summaryrefslogtreecommitdiffstats
path: root/drivers/soc/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/mediatek')
-rw-r--r--drivers/soc/mediatek/Kconfig88
-rw-r--r--drivers/soc/mediatek/Makefile10
-rw-r--r--drivers/soc/mediatek/mt6795-pm-domains.h112
-rw-r--r--drivers/soc/mediatek/mt8167-mmsys.h35
-rw-r--r--drivers/soc/mediatek/mt8167-pm-domains.h105
-rw-r--r--drivers/soc/mediatek/mt8173-pm-domains.h123
-rw-r--r--drivers/soc/mediatek/mt8183-mmsys.h63
-rw-r--r--drivers/soc/mediatek/mt8183-pm-domains.h266
-rw-r--r--drivers/soc/mediatek/mt8186-mmsys.h121
-rw-r--r--drivers/soc/mediatek/mt8186-pm-domains.h342
-rw-r--r--drivers/soc/mediatek/mt8192-mmsys.h77
-rw-r--r--drivers/soc/mediatek/mt8192-pm-domains.h355
-rw-r--r--drivers/soc/mediatek/mt8195-mmsys.h370
-rw-r--r--drivers/soc/mediatek/mt8195-pm-domains.h613
-rw-r--r--drivers/soc/mediatek/mt8365-mmsys.h82
-rw-r--r--drivers/soc/mediatek/mtk-cmdq-helper.c443
-rw-r--r--drivers/soc/mediatek/mtk-devapc.c324
-rw-r--r--drivers/soc/mediatek/mtk-infracfg.c93
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.c429
-rw-r--r--drivers/soc/mediatek/mtk-mmsys.h279
-rw-r--r--drivers/soc/mediatek/mtk-mutex.c877
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.c675
-rw-r--r--drivers/soc/mediatek/mtk-pm-domains.h106
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c2328
-rw-r--r--drivers/soc/mediatek/mtk-scpsys.c1147
-rw-r--r--drivers/soc/mediatek/mtk-svs.c2491
26 files changed, 11954 insertions, 0 deletions
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
new file mode 100644
index 000000000..40d0cc600
--- /dev/null
+++ b/drivers/soc/mediatek/Kconfig
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# MediaTek SoC drivers
+#
+menu "MediaTek SoC drivers"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+
+config MTK_CMDQ
+ tristate "MediaTek CMDQ Support"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select MAILBOX
+ select MTK_CMDQ_MBOX
+ select MTK_INFRACFG
+ help
+ Say yes here to add support for the MediaTek Command Queue (CMDQ)
+ driver. The CMDQ is used to help read/write registers with critical
+ time limitation, such as updating display configuration during the
+ vblank.
+
+config MTK_DEVAPC
+ tristate "Mediatek Device APC Support"
+ help
+ Say yes here to enable support for Mediatek Device APC driver.
+ This driver is mainly used to handle the violation which catches
+ unexpected transaction.
+ The violation information is logged for further analysis or
+ countermeasures.
+
+config MTK_INFRACFG
+ bool "MediaTek INFRACFG Support"
+ select REGMAP
+ help
+ Say yes here to add support for the MediaTek INFRACFG controller. The
+ INFRACFG controller contains various infrastructure registers not
+ directly associated to any device.
+
+config MTK_PMIC_WRAP
+ tristate "MediaTek PMIC Wrapper Support"
+ depends on RESET_CONTROLLER
+ depends on OF
+ select REGMAP
+ help
+ Say yes here to add support for MediaTek PMIC Wrapper found
+ on different MediaTek SoCs. The PMIC wrapper is a proprietary
+ hardware to connect the PMIC.
+
+config MTK_SCPSYS
+ bool "MediaTek SCPSYS Support"
+ default ARCH_MEDIATEK
+ depends on OF
+ select REGMAP
+ select MTK_INFRACFG
+ select PM_GENERIC_DOMAINS if PM
+ help
+ Say yes here to add support for the MediaTek SCPSYS power domain
+ driver.
+
+config MTK_SCPSYS_PM_DOMAINS
+ bool "MediaTek SCPSYS generic power domain"
+ default ARCH_MEDIATEK
+ depends on PM
+ select PM_GENERIC_DOMAINS
+ select REGMAP
+ help
+ Say y here to enable power domain support.
+ In order to meet high performance and low power requirements, the System
+ Control Processor System (SCPSYS) has several power management related
+ tasks in the system.
+
+config MTK_MMSYS
+ bool "MediaTek MMSYS Support"
+ default ARCH_MEDIATEK
+ depends on HAS_IOMEM
+ help
+ Say yes here to add support for the MediaTek Multimedia
+ Subsystem (MMSYS).
+
+config MTK_SVS
+ tristate "MediaTek Smart Voltage Scaling(SVS)"
+ depends on NVMEM_MTK_EFUSE && NVMEM
+ help
+ The Smart Voltage Scaling(SVS) engine is a piece of hardware
+ which has several controllers(banks) for calculating suitable
+ voltage to different power domains(CPU/GPU/CCI) according to
+ chip process corner, temperatures and other factors. Then DVFS
+ driver could apply SVS bank voltage to PMIC/Buck.
+
+endmenu
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
new file mode 100644
index 000000000..0e9e703c9
--- /dev/null
+++ b/drivers/soc/mediatek/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
+obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o
+obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
+obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
+obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o
+obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o
+obj-$(CONFIG_MTK_MMSYS) += mtk-mutex.o
+obj-$(CONFIG_MTK_SVS) += mtk-svs.o
diff --git a/drivers/soc/mediatek/mt6795-pm-domains.h b/drivers/soc/mediatek/mt6795-pm-domains.h
new file mode 100644
index 000000000..ef07c9dfd
--- /dev/null
+++ b/drivers/soc/mediatek/mt6795-pm-domains.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT6795_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt6795-power.h>
+
+/*
+ * MT6795 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt6795[] = {
+ [MT6795_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT6795_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = SPM_VEN_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT6795_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ },
+ [MT6795_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
+ MT8173_TOP_AXI_PROT_EN_MM_M1),
+ },
+ },
+ [MT6795_POWER_DOMAIN_MJC] = {
+ .name = "mjc",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x298,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT6795_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = SPM_AUDIO_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT6795_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = 0,
+ },
+ [MT6795_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = PWR_STATUS_MFG_2D,
+ .ctl_offs = SPM_MFG_2D_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ },
+ [MT6795_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(13, 8),
+ .sram_pdn_ack_bits = GENMASK(21, 16),
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
+ MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+ MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
+ },
+ },
+};
+
+static const struct scpsys_soc_data mt6795_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt6795,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt6795),
+};
+
+#endif /* __SOC_MEDIATEK_MT6795_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h
new file mode 100644
index 000000000..f7a35b365
--- /dev/null
+++ b/drivers/soc/mediatek/mt8167-mmsys.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8167_MMSYS_H
+#define __SOC_MEDIATEK_MT8167_MMSYS_H
+
+#define MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x030
+#define MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN 0x038
+#define MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x058
+#define MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0x064
+#define MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x06c
+
+#define MT8167_DITHER_MOUT_EN_RDMA0 0x1
+#define MT8167_RDMA0_SOUT_DSI0 0x2
+#define MT8167_DSI0_SEL_IN_RDMA0 0x1
+
+static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
+ MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_RDMA0,
+ MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
+ MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0,
+ MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI0,
+ MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0
+ },
+};
+
+#endif /* __SOC_MEDIATEK_MT8167_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8167-pm-domains.h b/drivers/soc/mediatek/mt8167-pm-domains.h
new file mode 100644
index 000000000..4d6c32759
--- /dev/null
+++ b/drivers/soc/mediatek/mt8167-pm-domains.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8167_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8167_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8167-power.h>
+
+#define MT8167_PWR_STATUS_MFG_2D BIT(24)
+#define MT8167_PWR_STATUS_MFG_ASYNC BIT(25)
+
+/*
+ * MT8167 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8167[] = {
+ [MT8167_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MM_EMI |
+ MT8167_TOP_AXI_PROT_EN_MCU_MM),
+ },
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8167_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8167_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8167_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = MT8167_PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_MCU_MFG |
+ MT8167_TOP_AXI_PROT_EN_MFG_EMI),
+ },
+ },
+ [MT8167_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = MT8167_PWR_STATUS_MFG_2D,
+ .ctl_offs = SPM_MFG_2D_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8167_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8167_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = SPM_CONN_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = 0,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8167_TOP_AXI_PROT_EN_CONN_EMI |
+ MT8167_TOP_AXI_PROT_EN_CONN_MCU |
+ MT8167_TOP_AXI_PROT_EN_MCU_CONN),
+ },
+ },
+};
+
+static const struct scpsys_soc_data mt8167_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8167,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8167),
+};
+
+#endif /* __SOC_MEDIATEK_MT8167_PM_DOMAINS_H */
+
diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h
new file mode 100644
index 000000000..1a5dc63b7
--- /dev/null
+++ b/drivers/soc/mediatek/mt8173-pm-domains.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8173_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8173_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8173-power.h>
+
+/*
+ * MT8173 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = {
+ [MT8173_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8173_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = SPM_VEN_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8173_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ },
+ [MT8173_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 |
+ MT8173_TOP_AXI_PROT_EN_MM_M1),
+ },
+ },
+ [MT8173_POWER_DOMAIN_VENC_LT] = {
+ .name = "venc_lt",
+ .sta_mask = PWR_STATUS_VENC_LT,
+ .ctl_offs = SPM_VEN2_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8173_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = SPM_AUDIO_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8173_POWER_DOMAIN_USB] = {
+ .name = "usb",
+ .sta_mask = PWR_STATUS_USB,
+ .ctl_offs = SPM_USB_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = 0,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8173_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = PWR_STATUS_MFG_2D,
+ .ctl_offs = SPM_MFG_2D_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ },
+ [MT8173_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND,
+ .sram_pdn_bits = GENMASK(13, 8),
+ .sram_pdn_ack_bits = GENMASK(21, 16),
+ .bp_infracfg = {
+ BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S |
+ MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+ MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT),
+ },
+ },
+};
+
+static const struct scpsys_soc_data mt8173_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8173,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173),
+};
+
+#endif /* __SOC_MEDIATEK_MT8173_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8183-mmsys.h b/drivers/soc/mediatek/mt8183-mmsys.h
new file mode 100644
index 000000000..ff6be1703
--- /dev/null
+++ b/drivers/soc/mediatek/mt8183-mmsys.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8183_MMSYS_H
+#define __SOC_MEDIATEK_MT8183_MMSYS_H
+
+#define MT8183_DISP_OVL0_MOUT_EN 0xf00
+#define MT8183_DISP_OVL0_2L_MOUT_EN 0xf04
+#define MT8183_DISP_OVL1_2L_MOUT_EN 0xf08
+#define MT8183_DISP_DITHER0_MOUT_EN 0xf0c
+#define MT8183_DISP_PATH0_SEL_IN 0xf24
+#define MT8183_DISP_DSI0_SEL_IN 0xf2c
+#define MT8183_DISP_DPI0_SEL_IN 0xf30
+#define MT8183_DISP_RDMA0_SOUT_SEL_IN 0xf50
+#define MT8183_DISP_RDMA1_SOUT_SEL_IN 0xf54
+
+#define MT8183_OVL0_MOUT_EN_OVL0_2L BIT(4)
+#define MT8183_OVL0_2L_MOUT_EN_DISP_PATH0 BIT(0)
+#define MT8183_OVL1_2L_MOUT_EN_RDMA1 BIT(4)
+#define MT8183_DITHER0_MOUT_IN_DSI0 BIT(0)
+#define MT8183_DISP_PATH0_SEL_IN_OVL0_2L 0x1
+#define MT8183_DSI0_SEL_IN_RDMA0 0x1
+#define MT8183_DSI0_SEL_IN_RDMA1 0x3
+#define MT8183_DPI0_SEL_IN_RDMA0 0x1
+#define MT8183_DPI0_SEL_IN_RDMA1 0x2
+#define MT8183_RDMA0_SOUT_COLOR0 0x1
+#define MT8183_RDMA1_SOUT_DSI0 0x1
+
+#define MT8183_MMSYS_SW0_RST_B 0x140
+
+static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
+ MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L,
+ MT8183_OVL0_MOUT_EN_OVL0_2L
+ }, {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
+ MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0,
+ MT8183_OVL0_2L_MOUT_EN_DISP_PATH0
+ }, {
+ DDP_COMPONENT_OVL_2L1, DDP_COMPONENT_RDMA1,
+ MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1,
+ MT8183_OVL1_2L_MOUT_EN_RDMA1
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0,
+ MT8183_DITHER0_MOUT_IN_DSI0
+ }, {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
+ MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L,
+ MT8183_DISP_PATH0_SEL_IN_OVL0_2L
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1,
+ MT8183_DPI0_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0,
+ MT8183_RDMA0_SOUT_COLOR0
+ }
+};
+
+#endif /* __SOC_MEDIATEK_MT8183_MMSYS_H */
+
diff --git a/drivers/soc/mediatek/mt8183-pm-domains.h b/drivers/soc/mediatek/mt8183-pm-domains.h
new file mode 100644
index 000000000..99de67fe5
--- /dev/null
+++ b/drivers/soc/mediatek/mt8183-pm-domains.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8183_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8183_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8183-power.h>
+
+/*
+ * MT8183 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
+ [MT8183_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = 0x0314,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ },
+ [MT8183_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = 0x032c,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CONN, MT8183_TOP_AXI_PROT_EN_SET,
+ MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
+ },
+ },
+ [MT8183_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = 0x0334,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8183_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = 0x0338,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8183_POWER_DOMAIN_MFG_CORE0] = {
+ .name = "mfg_core0",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x034c,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8183_POWER_DOMAIN_MFG_CORE1] = {
+ .name = "mfg_core1",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x0310,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8183_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = PWR_STATUS_MFG_2D,
+ .ctl_offs = 0x0348,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_MFG, MT8183_TOP_AXI_PROT_EN_1_SET,
+ MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MFG, MT8183_TOP_AXI_PROT_EN_SET,
+ MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
+ },
+ },
+ [MT8183_POWER_DOMAIN_DISP] = {
+ .name = "disp",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = 0x030c,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_DISP, MT8183_TOP_AXI_PROT_EN_1_SET,
+ MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_DISP, MT8183_TOP_AXI_PROT_EN_SET,
+ MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
+ },
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_DISP,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_CAM] = {
+ .name = "cam",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x0344,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_CAM, MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR, MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CAM, MT8183_TOP_AXI_PROT_EN_SET,
+ MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_CAM_2ND,
+ MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR,
+ MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_CAM,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = 0x0308,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_ISP,
+ MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR,
+ MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_ISP_2ND,
+ MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR,
+ MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_ISP,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x0300,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VDEC,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = 0x0304,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VENC,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VPU_TOP] = {
+ .name = "vpu_top",
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x0324,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP,
+ MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR,
+ MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_VPU_TOP,
+ MT8183_TOP_AXI_PROT_EN_SET,
+ MT8183_TOP_AXI_PROT_EN_CLR,
+ MT8183_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP_2ND,
+ MT8183_TOP_AXI_PROT_EN_MM_SET,
+ MT8183_TOP_AXI_PROT_EN_MM_CLR,
+ MT8183_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ .bp_smi = {
+ BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VPU_TOP,
+ MT8183_SMI_COMMON_CLAMP_EN_SET,
+ MT8183_SMI_COMMON_CLAMP_EN_CLR,
+ MT8183_SMI_COMMON_CLAMP_EN),
+ },
+ },
+ [MT8183_POWER_DOMAIN_VPU_CORE0] = {
+ .name = "vpu_core0",
+ .sta_mask = BIT(27),
+ .ctl_offs = 0x33c,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0,
+ MT8183_TOP_AXI_PROT_EN_MCU_SET,
+ MT8183_TOP_AXI_PROT_EN_MCU_CLR,
+ MT8183_TOP_AXI_PROT_EN_MCU_STA1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0_2ND,
+ MT8183_TOP_AXI_PROT_EN_MCU_SET,
+ MT8183_TOP_AXI_PROT_EN_MCU_CLR,
+ MT8183_TOP_AXI_PROT_EN_MCU_STA1),
+ },
+ .caps = MTK_SCPD_SRAM_ISO,
+ },
+ [MT8183_POWER_DOMAIN_VPU_CORE1] = {
+ .name = "vpu_core1",
+ .sta_mask = BIT(28),
+ .ctl_offs = 0x0340,
+ .pwr_sta_offs = 0x0180,
+ .pwr_sta2nd_offs = 0x0184,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1,
+ MT8183_TOP_AXI_PROT_EN_MCU_SET,
+ MT8183_TOP_AXI_PROT_EN_MCU_CLR,
+ MT8183_TOP_AXI_PROT_EN_MCU_STA1),
+ BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1_2ND,
+ MT8183_TOP_AXI_PROT_EN_MCU_SET,
+ MT8183_TOP_AXI_PROT_EN_MCU_CLR,
+ MT8183_TOP_AXI_PROT_EN_MCU_STA1),
+ },
+ .caps = MTK_SCPD_SRAM_ISO,
+ },
+};
+
+static const struct scpsys_soc_data mt8183_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8183,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8183),
+};
+
+#endif /* __SOC_MEDIATEK_MT8183_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8186-mmsys.h b/drivers/soc/mediatek/mt8186-mmsys.h
new file mode 100644
index 000000000..09b1ccbc0
--- /dev/null
+++ b/drivers/soc/mediatek/mt8186-mmsys.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8186_MMSYS_H
+#define __SOC_MEDIATEK_MT8186_MMSYS_H
+
+/* Values for DPI configuration in MMSYS address space */
+#define MT8186_MMSYS_DPI_OUTPUT_FORMAT 0x400
+#define DPI_FORMAT_MASK 0x1
+#define DPI_RGB888_DDR_CON BIT(0)
+#define DPI_RGB565_SDR_CON BIT(1)
+
+#define MT8186_MMSYS_OVL_CON 0xF04
+#define MT8186_MMSYS_OVL0_CON_MASK 0x3
+#define MT8186_MMSYS_OVL0_2L_CON_MASK 0xC
+#define MT8186_OVL0_GO_BLEND BIT(0)
+#define MT8186_OVL0_GO_BG BIT(1)
+#define MT8186_OVL0_2L_GO_BLEND BIT(2)
+#define MT8186_OVL0_2L_GO_BG BIT(3)
+#define MT8186_DISP_RDMA0_SOUT_SEL 0xF0C
+#define MT8186_RDMA0_SOUT_SEL_MASK 0xF
+#define MT8186_RDMA0_SOUT_TO_DSI0 (0)
+#define MT8186_RDMA0_SOUT_TO_COLOR0 (1)
+#define MT8186_RDMA0_SOUT_TO_DPI0 (2)
+#define MT8186_DISP_OVL0_2L_MOUT_EN 0xF14
+#define MT8186_OVL0_2L_MOUT_EN_MASK 0xF
+#define MT8186_OVL0_2L_MOUT_TO_RDMA0 BIT(0)
+#define MT8186_OVL0_2L_MOUT_TO_RDMA1 BIT(3)
+#define MT8186_DISP_OVL0_MOUT_EN 0xF18
+#define MT8186_OVL0_MOUT_EN_MASK 0xF
+#define MT8186_OVL0_MOUT_TO_RDMA0 BIT(0)
+#define MT8186_OVL0_MOUT_TO_RDMA1 BIT(3)
+#define MT8186_DISP_DITHER0_MOUT_EN 0xF20
+#define MT8186_DITHER0_MOUT_EN_MASK 0xF
+#define MT8186_DITHER0_MOUT_TO_DSI0 BIT(0)
+#define MT8186_DITHER0_MOUT_TO_RDMA1 BIT(2)
+#define MT8186_DITHER0_MOUT_TO_DPI0 BIT(3)
+#define MT8186_DISP_RDMA0_SEL_IN 0xF28
+#define MT8186_RDMA0_SEL_IN_MASK 0xF
+#define MT8186_RDMA0_FROM_OVL0 0
+#define MT8186_RDMA0_FROM_OVL0_2L 2
+#define MT8186_DISP_DSI0_SEL_IN 0xF30
+#define MT8186_DSI0_SEL_IN_MASK 0xF
+#define MT8186_DSI0_FROM_RDMA0 0
+#define MT8186_DSI0_FROM_DITHER0 1
+#define MT8186_DSI0_FROM_RDMA1 2
+#define MT8186_DISP_RDMA1_MOUT_EN 0xF3C
+#define MT8186_RDMA1_MOUT_EN_MASK 0xF
+#define MT8186_RDMA1_MOUT_TO_DPI0_SEL BIT(0)
+#define MT8186_RDMA1_MOUT_TO_DSI0_SEL BIT(2)
+#define MT8186_DISP_RDMA1_SEL_IN 0xF40
+#define MT8186_RDMA1_SEL_IN_MASK 0xF
+#define MT8186_RDMA1_FROM_OVL0 0
+#define MT8186_RDMA1_FROM_OVL0_2L 2
+#define MT8186_RDMA1_FROM_DITHER0 3
+#define MT8186_DISP_DPI0_SEL_IN 0xF44
+#define MT8186_DPI0_SEL_IN_MASK 0xF
+#define MT8186_DPI0_FROM_RDMA1 0
+#define MT8186_DPI0_FROM_DITHER0 1
+#define MT8186_DPI0_FROM_RDMA0 2
+
+#define MT8186_MMSYS_SW0_RST_B 0x160
+
+static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
+ MT8186_OVL0_MOUT_TO_RDMA0
+ },
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
+ MT8186_RDMA0_FROM_OVL0
+ },
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
+ MT8186_OVL0_GO_BLEND
+ },
+ {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
+ MT8186_RDMA0_SOUT_TO_COLOR0
+ },
+ {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
+ MT8186_DITHER0_MOUT_TO_DSI0,
+ },
+ {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
+ MT8186_DSI0_FROM_DITHER0
+ },
+ {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
+ MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
+ MT8186_OVL0_2L_MOUT_TO_RDMA1
+ },
+ {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
+ MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
+ MT8186_RDMA1_FROM_OVL0_2L
+ },
+ {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA1,
+ MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
+ MT8186_OVL0_2L_GO_BLEND
+ },
+ {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
+ MT8186_RDMA1_MOUT_TO_DPI0_SEL
+ },
+ {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
+ MT8186_DPI0_FROM_RDMA1
+ },
+};
+
+#endif /* __SOC_MEDIATEK_MT8186_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8186-pm-domains.h b/drivers/soc/mediatek/mt8186-pm-domains.h
new file mode 100644
index 000000000..fce86f79c
--- /dev/null
+++ b/drivers/soc/mediatek/mt8186-pm-domains.h
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
+ */
+
+#ifndef __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8186_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8186-power.h>
+
+/*
+ * MT8186 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = {
+ [MT8186_POWER_DOMAIN_MFG0] = {
+ .name = "mfg0",
+ .sta_mask = BIT(2),
+ .ctl_offs = 0x308,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8186_POWER_DOMAIN_MFG1] = {
+ .name = "mfg1",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x30c,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP2,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_MFG1_STEP3,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_MFG1_STEP4,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8186_POWER_DOMAIN_MFG2] = {
+ .name = "mfg2",
+ .sta_mask = BIT(4),
+ .ctl_offs = 0x310,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_MFG3] = {
+ .name = "mfg3",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x314,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_SSUSB] = {
+ .name = "ssusb",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x9F0,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8186_POWER_DOMAIN_SSUSB_P1] = {
+ .name = "ssusb_p1",
+ .sta_mask = BIT(19),
+ .ctl_offs = 0x9F4,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8186_POWER_DOMAIN_DIS] = {
+ .name = "dis",
+ .sta_mask = BIT(21),
+ .ctl_offs = 0x354,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_DIS_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_DIS_STEP2,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ },
+ },
+ [MT8186_POWER_DOMAIN_IMG] = {
+ .name = "img",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x334,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IMG_STEP2,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_IMG2] = {
+ .name = "img2",
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x338,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_IPE] = {
+ .name = "ipe",
+ .sta_mask = BIT(15),
+ .ctl_offs = 0x33C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_IPE_STEP2,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_CAM] = {
+ .name = "cam",
+ .sta_mask = BIT(23),
+ .ctl_offs = 0x35C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CAM_STEP2,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_CAM_RAWA] = {
+ .name = "cam_rawa",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x360,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_CAM_RAWB] = {
+ .name = "cam_rawb",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x364,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(18),
+ .ctl_offs = 0x348,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VENC_STEP2,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(16),
+ .ctl_offs = 0x340,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_VDEC_STEP2,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_WPE] = {
+ .name = "wpe",
+ .sta_mask = BIT(0),
+ .ctl_offs = 0x3F8,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP1,
+ MT8186_TOP_AXI_PROT_EN_2_SET,
+ MT8186_TOP_AXI_PROT_EN_2_CLR,
+ MT8186_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_2_WPE_STEP2,
+ MT8186_TOP_AXI_PROT_EN_2_SET,
+ MT8186_TOP_AXI_PROT_EN_2_CLR,
+ MT8186_TOP_AXI_PROT_EN_2_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_CONN_ON] = {
+ .name = "conn_on",
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x304,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_1_CONN_ON_STEP1,
+ MT8186_TOP_AXI_PROT_EN_1_SET,
+ MT8186_TOP_AXI_PROT_EN_1_CLR,
+ MT8186_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP2,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP3,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_CONN_ON_STEP4,
+ MT8186_TOP_AXI_PROT_EN_SET,
+ MT8186_TOP_AXI_PROT_EN_CLR,
+ MT8186_TOP_AXI_PROT_EN_STA),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8186_POWER_DOMAIN_CSIRX_TOP] = {
+ .name = "csirx_top",
+ .sta_mask = BIT(6),
+ .ctl_offs = 0x318,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8186_POWER_DOMAIN_ADSP_AO] = {
+ .name = "adsp_ao",
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x9FC,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ },
+ [MT8186_POWER_DOMAIN_ADSP_INFRA] = {
+ .name = "adsp_infra",
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x9F8,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ },
+ [MT8186_POWER_DOMAIN_ADSP_TOP] = {
+ .name = "adsp_top",
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x3E4,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP1,
+ MT8186_TOP_AXI_PROT_EN_3_SET,
+ MT8186_TOP_AXI_PROT_EN_3_CLR,
+ MT8186_TOP_AXI_PROT_EN_3_STA),
+ BUS_PROT_WR_IGN(MT8186_TOP_AXI_PROT_EN_3_ADSP_TOP_STEP2,
+ MT8186_TOP_AXI_PROT_EN_3_SET,
+ MT8186_TOP_AXI_PROT_EN_3_CLR,
+ MT8186_TOP_AXI_PROT_EN_3_STA),
+ },
+ .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+};
+
+static const struct scpsys_soc_data mt8186_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8186,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8186),
+};
+
+#endif /* __SOC_MEDIATEK_MT8186_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8192-mmsys.h b/drivers/soc/mediatek/mt8192-mmsys.h
new file mode 100644
index 000000000..a016d80b4
--- /dev/null
+++ b/drivers/soc/mediatek/mt8192-mmsys.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8192_MMSYS_H
+#define __SOC_MEDIATEK_MT8192_MMSYS_H
+
+#define MT8192_MMSYS_OVL_MOUT_EN 0xf04
+#define MT8192_DISP_OVL1_2L_MOUT_EN 0xf08
+#define MT8192_DISP_OVL0_2L_MOUT_EN 0xf18
+#define MT8192_DISP_OVL0_MOUT_EN 0xf1c
+#define MT8192_DISP_RDMA0_SEL_IN 0xf2c
+#define MT8192_DISP_RDMA0_SOUT_SEL 0xf30
+#define MT8192_DISP_CCORR0_SOUT_SEL 0xf34
+#define MT8192_DISP_AAL0_SEL_IN 0xf38
+#define MT8192_DISP_DITHER0_MOUT_EN 0xf3c
+#define MT8192_DISP_DSI0_SEL_IN 0xf40
+#define MT8192_DISP_OVL2_2L_MOUT_EN 0xf4c
+
+#define MT8192_DISP_OVL0_GO_BLEND BIT(0)
+#define MT8192_DITHER0_MOUT_IN_DSI0 BIT(0)
+#define MT8192_OVL0_MOUT_EN_DISP_RDMA0 BIT(0)
+#define MT8192_OVL2_2L_MOUT_EN_RDMA4 BIT(0)
+#define MT8192_DISP_OVL0_GO_BG BIT(1)
+#define MT8192_DISP_OVL0_2L_GO_BLEND BIT(2)
+#define MT8192_DISP_OVL0_2L_GO_BG BIT(3)
+#define MT8192_OVL1_2L_MOUT_EN_RDMA1 BIT(4)
+#define MT8192_OVL0_MOUT_EN_OVL0_2L BIT(4)
+#define MT8192_RDMA0_SEL_IN_OVL0_2L 0x3
+#define MT8192_RDMA0_SOUT_COLOR0 0x1
+#define MT8192_CCORR0_SOUT_AAL0 0x1
+#define MT8192_AAL0_SEL_IN_CCORR0 0x1
+#define MT8192_DSI0_SEL_IN_DITHER0 0x1
+
+static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
+ MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
+ MT8192_OVL0_MOUT_EN_DISP_RDMA0
+ }, {
+ DDP_COMPONENT_OVL_2L2, DDP_COMPONENT_RDMA4,
+ MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
+ MT8192_OVL2_2L_MOUT_EN_RDMA4
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
+ MT8192_DITHER0_MOUT_IN_DSI0
+ }, {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
+ MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
+ MT8192_RDMA0_SEL_IN_OVL0_2L
+ }, {
+ DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
+ MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
+ MT8192_AAL0_SEL_IN_CCORR0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0,
+ MT8192_DSI0_SEL_IN_DITHER0
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
+ MT8192_RDMA0_SOUT_COLOR0
+ }, {
+ DDP_COMPONENT_CCORR, DDP_COMPONENT_AAL0,
+ MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
+ MT8192_CCORR0_SOUT_AAL0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL_2L0,
+ MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
+ MT8192_DISP_OVL0_GO_BG
+ }, {
+ DDP_COMPONENT_OVL_2L0, DDP_COMPONENT_RDMA0,
+ MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
+ MT8192_DISP_OVL0_2L_GO_BLEND
+ }
+};
+
+#endif /* __SOC_MEDIATEK_MT8192_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8192-pm-domains.h b/drivers/soc/mediatek/mt8192-pm-domains.h
new file mode 100644
index 000000000..b97b20519
--- /dev/null
+++ b/drivers/soc/mediatek/mt8192-pm-domains.h
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8192_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8192_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8192-power.h>
+
+/*
+ * MT8192 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = {
+ [MT8192_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = BIT(21),
+ .ctl_offs = 0x0354,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_AUDIO,
+ MT8192_TOP_AXI_PROT_EN_2_SET,
+ MT8192_TOP_AXI_PROT_EN_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_2_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = 0x0304,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN,
+ MT8192_TOP_AXI_PROT_EN_SET,
+ MT8192_TOP_AXI_PROT_EN_CLR,
+ MT8192_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN_2ND,
+ MT8192_TOP_AXI_PROT_EN_SET,
+ MT8192_TOP_AXI_PROT_EN_CLR,
+ MT8192_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CONN,
+ MT8192_TOP_AXI_PROT_EN_1_SET,
+ MT8192_TOP_AXI_PROT_EN_1_CLR,
+ MT8192_TOP_AXI_PROT_EN_1_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8192_POWER_DOMAIN_MFG0] = {
+ .name = "mfg0",
+ .sta_mask = BIT(2),
+ .ctl_offs = 0x0308,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8192_POWER_DOMAIN_MFG1] = {
+ .name = "mfg1",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x030c,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_MFG1,
+ MT8192_TOP_AXI_PROT_EN_1_SET,
+ MT8192_TOP_AXI_PROT_EN_1_CLR,
+ MT8192_TOP_AXI_PROT_EN_1_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1,
+ MT8192_TOP_AXI_PROT_EN_2_SET,
+ MT8192_TOP_AXI_PROT_EN_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_2_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MFG1,
+ MT8192_TOP_AXI_PROT_EN_SET,
+ MT8192_TOP_AXI_PROT_EN_CLR,
+ MT8192_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1_2ND,
+ MT8192_TOP_AXI_PROT_EN_2_SET,
+ MT8192_TOP_AXI_PROT_EN_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_2_STA1),
+ },
+ .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8192_POWER_DOMAIN_MFG2] = {
+ .name = "mfg2",
+ .sta_mask = BIT(4),
+ .ctl_offs = 0x0310,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_MFG3] = {
+ .name = "mfg3",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x0314,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_MFG4] = {
+ .name = "mfg4",
+ .sta_mask = BIT(6),
+ .ctl_offs = 0x0318,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_MFG5] = {
+ .name = "mfg5",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x031c,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_MFG6] = {
+ .name = "mfg6",
+ .sta_mask = BIT(8),
+ .ctl_offs = 0x0320,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_DISP] = {
+ .name = "disp",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x0350,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_DISP,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_2_DISP,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_DISP,
+ MT8192_TOP_AXI_PROT_EN_SET,
+ MT8192_TOP_AXI_PROT_EN_CLR,
+ MT8192_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_DISP_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_DISP_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_IPE] = {
+ .name = "ipe",
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x0338,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x0330,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_ISP2] = {
+ .name = "isp2",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x0334,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_MDP] = {
+ .name = "mdp",
+ .sta_mask = BIT(19),
+ .ctl_offs = 0x034c,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x0344,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(15),
+ .ctl_offs = 0x033c,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_VDEC2] = {
+ .name = "vdec2",
+ .sta_mask = BIT(16),
+ .ctl_offs = 0x0340,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_CAM] = {
+ .name = "cam",
+ .sta_mask = BIT(23),
+ .ctl_offs = 0x035c,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_CAM,
+ MT8192_TOP_AXI_PROT_EN_2_SET,
+ MT8192_TOP_AXI_PROT_EN_2_CLR,
+ MT8192_TOP_AXI_PROT_EN_2_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CAM,
+ MT8192_TOP_AXI_PROT_EN_1_SET,
+ MT8192_TOP_AXI_PROT_EN_1_CLR,
+ MT8192_TOP_AXI_PROT_EN_1_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM_2ND,
+ MT8192_TOP_AXI_PROT_EN_MM_SET,
+ MT8192_TOP_AXI_PROT_EN_MM_CLR,
+ MT8192_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_VDNR_CAM,
+ MT8192_TOP_AXI_PROT_EN_VDNR_SET,
+ MT8192_TOP_AXI_PROT_EN_VDNR_CLR,
+ MT8192_TOP_AXI_PROT_EN_VDNR_STA1),
+ },
+ },
+ [MT8192_POWER_DOMAIN_CAM_RAWA] = {
+ .name = "cam_rawa",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x0360,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_CAM_RAWB] = {
+ .name = "cam_rawb",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x0364,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+ [MT8192_POWER_DOMAIN_CAM_RAWC] = {
+ .name = "cam_rawc",
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x0368,
+ .pwr_sta_offs = 0x016c,
+ .pwr_sta2nd_offs = 0x0170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ },
+};
+
+static const struct scpsys_soc_data mt8192_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8192,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8192),
+};
+
+#endif /* __SOC_MEDIATEK_MT8192_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h
new file mode 100644
index 000000000..abfe94a30
--- /dev/null
+++ b/drivers/soc/mediatek/mt8195-mmsys.h
@@ -0,0 +1,370 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8195_MMSYS_H
+#define __SOC_MEDIATEK_MT8195_MMSYS_H
+
+#define MT8195_VDO0_OVL_MOUT_EN 0xf14
+#define MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0 BIT(0)
+#define MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0 BIT(1)
+#define MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1 BIT(2)
+#define MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1 BIT(4)
+#define MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1 BIT(5)
+#define MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0 BIT(6)
+
+#define MT8195_VDO0_SEL_IN 0xf34
+#define MT8195_SEL_IN_VPP_MERGE_FROM_MASK GENMASK(1, 0)
+#define MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT (0 << 0)
+#define MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1 (1 << 0)
+#define MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0 (2 << 0)
+#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK GENMASK(4, 4)
+#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 (0 << 4)
+#define MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE (1 << 4)
+#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK GENMASK(5, 5)
+#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1 (0 << 5)
+#define MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE (1 << 5)
+#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK GENMASK(8, 8)
+#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE (0 << 8)
+#define MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT (1 << 8)
+#define MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK GENMASK(9, 9)
+#define MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT (0 << 9)
+#define MT8195_SEL_IN_DP_INTF0_FROM_MASK GENMASK(13, 12)
+#define MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT (0 << 0)
+#define MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE (1 << 12)
+#define MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0 (2 << 12)
+#define MT8195_SEL_IN_DSI0_FROM_MASK GENMASK(16, 16)
+#define MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT (0 << 16)
+#define MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0 (1 << 16)
+#define MT8195_SEL_IN_DSI1_FROM_MASK GENMASK(17, 17)
+#define MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT (0 << 17)
+#define MT8195_SEL_IN_DSI1_FROM_VPP_MERGE (1 << 17)
+#define MT8195_SEL_IN_DISP_WDMA1_FROM_MASK GENMASK(20, 20)
+#define MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1 (0 << 20)
+#define MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE (1 << 20)
+#define MT8195_SEL_IN_DSC_WRAP1_FROM_MASK GENMASK(21, 21)
+#define MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN (0 << 21)
+#define MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1 (1 << 21)
+#define MT8195_SEL_IN_DISP_WDMA0_FROM_MASK GENMASK(22, 22)
+#define MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0 (0 << 22)
+
+#define MT8195_VDO0_SEL_OUT 0xf38
+#define MT8195_SOUT_DISP_DITHER0_TO_MASK BIT(0)
+#define MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN (0 << 0)
+#define MT8195_SOUT_DISP_DITHER0_TO_DSI0 (1 << 0)
+#define MT8195_SOUT_DISP_DITHER1_TO_MASK GENMASK(2, 1)
+#define MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN (0 << 1)
+#define MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE (1 << 1)
+#define MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT (2 << 1)
+#define MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK GENMASK(4, 4)
+#define MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE (0 << 4)
+#define MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0 (1 << 4)
+#define MT8195_SOUT_VPP_MERGE_TO_MASK GENMASK(10, 8)
+#define MT8195_SOUT_VPP_MERGE_TO_DSI1 (0 << 8)
+#define MT8195_SOUT_VPP_MERGE_TO_DP_INTF0 (1 << 8)
+#define MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0 (2 << 8)
+#define MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1 (3 << 8)
+#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN (4 << 8)
+#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK GENMASK(11, 11)
+#define MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN (0 << 11)
+#define MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK GENMASK(13, 12)
+#define MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0 (0 << 12)
+#define MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0 (1 << 12)
+#define MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE (2 << 12)
+#define MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK GENMASK(17, 16)
+#define MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1 (0 << 16)
+#define MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0 (1 << 16)
+#define MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0 (2 << 16)
+#define MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE (3 << 16)
+
+static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_WDMA0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_OVL1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1,
+ MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_RDMA1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_WDMA1,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_OVL0,
+ MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0,
+ MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
+ MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSC0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSC1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
+ MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
+ MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
+ MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
+ MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
+ MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
+ MT8195_SEL_IN_DSI1_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_WDMA1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_WDMA1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
+ MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_WDMA0,
+ MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK,
+ MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSC0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
+ MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN
+ }, {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
+ MT8195_SOUT_DISP_DITHER0_TO_DSI0
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSC1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_DITHER1, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
+ MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
+ MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE
+ }, {
+ DDP_COMPONENT_MERGE5, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
+ MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSI1
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DP_INTF0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_WDMA1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN
+ }, {
+ DDP_COMPONENT_MERGE0, DDP_COMPONENT_DSC1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK,
+ MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DSI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC0, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DSI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DP_INTF1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_DPI1,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0
+ }, {
+ DDP_COMPONENT_DSC1, DDP_COMPONENT_MERGE0,
+ MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
+ MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE
+ }
+};
+
+#endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8195-pm-domains.h b/drivers/soc/mediatek/mt8195-pm-domains.h
new file mode 100644
index 000000000..d7387ea1b
--- /dev/null
+++ b/drivers/soc/mediatek/mt8195-pm-domains.h
@@ -0,0 +1,613 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Author: Chun-Jie Chen <chun-jie.chen@mediatek.com>
+ */
+
+#ifndef __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT8195_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+#include <dt-bindings/power/mt8195-power.h>
+
+/*
+ * MT8195 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt8195[] = {
+ [MT8195_POWER_DOMAIN_PCIE_MAC_P0] = {
+ .name = "pcie_mac_p0",
+ .sta_mask = BIT(11),
+ .ctl_offs = 0x328,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P0,
+ MT8195_TOP_AXI_PROT_EN_VDNR_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P0,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_PCIE_MAC_P1] = {
+ .name = "pcie_mac_p1",
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x32C,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_PCIE_MAC_P1,
+ MT8195_TOP_AXI_PROT_EN_VDNR_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_PCIE_MAC_P1,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_PCIE_PHY] = {
+ .name = "pcie_phy",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x330,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8195_POWER_DOMAIN_SSUSB_PCIE_PHY] = {
+ .name = "ssusb_pcie_phy",
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x334,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_ALWAYS_ON,
+ },
+ [MT8195_POWER_DOMAIN_CSI_RX_TOP] = {
+ .name = "csi_rx_top",
+ .sta_mask = BIT(18),
+ .ctl_offs = 0x3C4,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_ETHER] = {
+ .name = "ether",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x344,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8195_POWER_DOMAIN_ADSP] = {
+ .name = "adsp",
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x360,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_ADSP,
+ MT8195_TOP_AXI_PROT_EN_2_SET,
+ MT8195_TOP_AXI_PROT_EN_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_2_STA1),
+ },
+ .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8195_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = BIT(8),
+ .ctl_offs = 0x358,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_AUDIO,
+ MT8195_TOP_AXI_PROT_EN_2_SET,
+ MT8195_TOP_AXI_PROT_EN_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_2_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_MFG0] = {
+ .name = "mfg0",
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x300,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8195_POWER_DOMAIN_MFG1] = {
+ .name = "mfg1",
+ .sta_mask = BIT(2),
+ .ctl_offs = 0x304,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1,
+ MT8195_TOP_AXI_PROT_EN_SET,
+ MT8195_TOP_AXI_PROT_EN_CLR,
+ MT8195_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1,
+ MT8195_TOP_AXI_PROT_EN_2_SET,
+ MT8195_TOP_AXI_PROT_EN_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_MFG1,
+ MT8195_TOP_AXI_PROT_EN_1_SET,
+ MT8195_TOP_AXI_PROT_EN_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_1_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_MFG1_2ND,
+ MT8195_TOP_AXI_PROT_EN_2_SET,
+ MT8195_TOP_AXI_PROT_EN_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MFG1_2ND,
+ MT8195_TOP_AXI_PROT_EN_SET,
+ MT8195_TOP_AXI_PROT_EN_CLR,
+ MT8195_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_DOMAIN_SUPPLY,
+ },
+ [MT8195_POWER_DOMAIN_MFG2] = {
+ .name = "mfg2",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x308,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_MFG3] = {
+ .name = "mfg3",
+ .sta_mask = BIT(4),
+ .ctl_offs = 0x30C,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_MFG4] = {
+ .name = "mfg4",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x310,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_MFG5] = {
+ .name = "mfg5",
+ .sta_mask = BIT(6),
+ .ctl_offs = 0x314,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_MFG6] = {
+ .name = "mfg6",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x318,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_VPPSYS0] = {
+ .name = "vppsys0",
+ .sta_mask = BIT(11),
+ .ctl_offs = 0x364,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0,
+ MT8195_TOP_AXI_PROT_EN_SET,
+ MT8195_TOP_AXI_PROT_EN_CLR,
+ MT8195_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VPPSYS0_2ND,
+ MT8195_TOP_AXI_PROT_EN_SET,
+ MT8195_TOP_AXI_PROT_EN_CLR,
+ MT8195_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS0_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_VDOSYS0] = {
+ .name = "vdosys0",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x36C,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS0,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDOSYS0,
+ MT8195_TOP_AXI_PROT_EN_SET,
+ MT8195_TOP_AXI_PROT_EN_CLR,
+ MT8195_TOP_AXI_PROT_EN_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8195_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_VPPSYS1] = {
+ .name = "vppsys1",
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x368,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VPPSYS1_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VPPSYS1,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_VDOSYS1] = {
+ .name = "vdosys1",
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x370,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDOSYS1_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDOSYS1,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_DP_TX] = {
+ .name = "dp_tx",
+ .sta_mask = BIT(16),
+ .ctl_offs = 0x378,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_DP_TX,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_EPD_TX] = {
+ .name = "epd_tx",
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x37C,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_VDNR_1_EPD_TX,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_SET,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_VDNR_1_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_HDMI_TX] = {
+ .name = "hdmi_tx",
+ .sta_mask = BIT(18),
+ .ctl_offs = 0x380,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8195_POWER_DOMAIN_WPESYS] = {
+ .name = "wpesys",
+ .sta_mask = BIT(15),
+ .ctl_offs = 0x374,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_WPESYS,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_WPESYS_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ },
+ [MT8195_POWER_DOMAIN_VDEC0] = {
+ .name = "vdec0",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x388,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC0_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC0_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_VDEC1] = {
+ .name = "vdec1",
+ .sta_mask = BIT(21),
+ .ctl_offs = 0x38C,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VDEC1_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_VDEC2] = {
+ .name = "vdec2",
+ .sta_mask = BIT(22),
+ .ctl_offs = 0x390,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VDEC2_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(23),
+ .ctl_offs = 0x394,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_VENC_CORE1] = {
+ .name = "venc_core1",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x398,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_VENC_CORE1,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_VENC_CORE1,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_IMG] = {
+ .name = "img",
+ .sta_mask = BIT(29),
+ .ctl_offs = 0x3AC,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IMG_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_DIP] = {
+ .name = "dip",
+ .sta_mask = BIT(30),
+ .ctl_offs = 0x3B0,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_IPE] = {
+ .name = "ipe",
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x3B4,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_IPE,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_IPE,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_CAM] = {
+ .name = "cam",
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x39C,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_2_CAM,
+ MT8195_TOP_AXI_PROT_EN_2_SET,
+ MT8195_TOP_AXI_PROT_EN_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_2_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_1_CAM,
+ MT8195_TOP_AXI_PROT_EN_1_SET,
+ MT8195_TOP_AXI_PROT_EN_1_CLR,
+ MT8195_TOP_AXI_PROT_EN_1_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_CAM_2ND,
+ MT8195_TOP_AXI_PROT_EN_MM_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_STA1),
+ BUS_PROT_WR(MT8195_TOP_AXI_PROT_EN_MM_2_CAM,
+ MT8195_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8195_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8195_TOP_AXI_PROT_EN_MM_2_STA1),
+ },
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_CAM_RAWA] = {
+ .name = "cam_rawa",
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x3A0,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_CAM_RAWB] = {
+ .name = "cam_rawb",
+ .sta_mask = BIT(27),
+ .ctl_offs = 0x3A4,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+ [MT8195_POWER_DOMAIN_CAM_MRAW] = {
+ .name = "cam_mraw",
+ .sta_mask = BIT(28),
+ .ctl_offs = 0x3A8,
+ .pwr_sta_offs = 0x16c,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+ },
+};
+
+static const struct scpsys_soc_data mt8195_scpsys_data = {
+ .domains_data = scpsys_domain_data_mt8195,
+ .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8195),
+};
+
+#endif /* __SOC_MEDIATEK_MT8195_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mt8365-mmsys.h b/drivers/soc/mediatek/mt8365-mmsys.h
new file mode 100644
index 000000000..7abaf048d
--- /dev/null
+++ b/drivers/soc/mediatek/mt8365-mmsys.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MT8365_MMSYS_H
+#define __SOC_MEDIATEK_MT8365_MMSYS_H
+
+#define MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0xf3c
+#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL 0xf4c
+#define MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN 0xf50
+#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN 0xf54
+#define MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN 0xf60
+#define MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0xf64
+#define MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN 0xf68
+#define MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL 0xfd0
+#define MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN 0xfd8
+#define MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00 0xfdc
+
+#define MT8365_RDMA0_SOUT_COLOR0 0x1
+#define MT8365_DITHER_MOUT_EN_DSI0 0x1
+#define MT8365_DSI0_SEL_IN_DITHER 0x1
+#define MT8365_RDMA0_SEL_IN_OVL0 0x0
+#define MT8365_RDMA0_RSZ0_SEL_IN_RDMA0 0x0
+#define MT8365_DISP_COLOR_SEL_IN_COLOR0 0x0
+#define MT8365_OVL0_MOUT_PATH0_SEL BIT(0)
+#define MT8365_RDMA1_SOUT_DPI0 0x1
+#define MT8365_DPI0_SEL_IN_RDMA1 0x0
+#define MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK 0x1
+#define MT8365_DPI0_SEL_IN_RDMA1 0x0
+
+static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
+ MT8365_OVL0_MOUT_PATH0_SEL, MT8365_OVL0_MOUT_PATH0_SEL
+ },
+ {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN,
+ MT8365_RDMA0_SEL_IN_OVL0, MT8365_RDMA0_SEL_IN_OVL0
+ },
+ {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL,
+ MT8365_RDMA0_SOUT_COLOR0, MT8365_RDMA0_SOUT_COLOR0
+ },
+ {
+ DDP_COMPONENT_COLOR0, DDP_COMPONENT_CCORR,
+ MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
+ MT8365_DISP_COLOR_SEL_IN_COLOR0,MT8365_DISP_COLOR_SEL_IN_COLOR0
+ },
+ {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN,
+ MT8365_DITHER_MOUT_EN_DSI0, MT8365_DITHER_MOUT_EN_DSI0
+ },
+ {
+ DDP_COMPONENT_DITHER0, DDP_COMPONENT_DSI0,
+ MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN,
+ MT8365_DSI0_SEL_IN_DITHER, MT8365_DSI0_SEL_IN_DITHER
+ },
+ {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_COLOR0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
+ MT8365_RDMA0_RSZ0_SEL_IN_RDMA0, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0
+ },
+ {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
+ MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK
+ },
+ {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
+ MT8365_DPI0_SEL_IN_RDMA1, MT8365_DPI0_SEL_IN_RDMA1
+ },
+ {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
+ MT8365_RDMA1_SOUT_DPI0, MT8365_RDMA1_SOUT_DPI0
+ },
+};
+
+#endif /* __SOC_MEDIATEK_MT8365_MMSYS_H */
diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
new file mode 100644
index 000000000..c1837a468
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
@@ -0,0 +1,443 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2018 MediaTek Inc.
+
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/mailbox_controller.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#define CMDQ_WRITE_ENABLE_MASK BIT(0)
+#define CMDQ_POLL_ENABLE_MASK BIT(0)
+#define CMDQ_EOC_IRQ_EN BIT(0)
+#define CMDQ_REG_TYPE 1
+#define CMDQ_JUMP_RELATIVE 1
+
+struct cmdq_instruction {
+ union {
+ u32 value;
+ u32 mask;
+ struct {
+ u16 arg_c;
+ u16 src_reg;
+ };
+ };
+ union {
+ u16 offset;
+ u16 event;
+ u16 reg_dst;
+ };
+ union {
+ u8 subsys;
+ struct {
+ u8 sop:5;
+ u8 arg_c_t:1;
+ u8 src_t:1;
+ u8 dst_t:1;
+ };
+ };
+ u8 op;
+};
+
+int cmdq_dev_get_client_reg(struct device *dev,
+ struct cmdq_client_reg *client_reg, int idx)
+{
+ struct of_phandle_args spec;
+ int err;
+
+ if (!client_reg)
+ return -ENOENT;
+
+ err = of_parse_phandle_with_fixed_args(dev->of_node,
+ "mediatek,gce-client-reg",
+ 3, idx, &spec);
+ if (err < 0) {
+ dev_err(dev,
+ "error %d can't parse gce-client-reg property (%d)",
+ err, idx);
+
+ return err;
+ }
+
+ client_reg->subsys = (u8)spec.args[0];
+ client_reg->offset = (u16)spec.args[1];
+ client_reg->size = (u16)spec.args[2];
+ of_node_put(spec.np);
+
+ return 0;
+}
+EXPORT_SYMBOL(cmdq_dev_get_client_reg);
+
+struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
+{
+ struct cmdq_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return (struct cmdq_client *)-ENOMEM;
+
+ client->client.dev = dev;
+ client->client.tx_block = false;
+ client->client.knows_txdone = true;
+ client->chan = mbox_request_channel(&client->client, index);
+
+ if (IS_ERR(client->chan)) {
+ long err;
+
+ dev_err(dev, "failed to request channel\n");
+ err = PTR_ERR(client->chan);
+ kfree(client);
+
+ return ERR_PTR(err);
+ }
+
+ return client;
+}
+EXPORT_SYMBOL(cmdq_mbox_create);
+
+void cmdq_mbox_destroy(struct cmdq_client *client)
+{
+ mbox_free_channel(client->chan);
+ kfree(client);
+}
+EXPORT_SYMBOL(cmdq_mbox_destroy);
+
+struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size)
+{
+ struct cmdq_pkt *pkt;
+ struct device *dev;
+ dma_addr_t dma_addr;
+
+ pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
+ if (!pkt)
+ return ERR_PTR(-ENOMEM);
+ pkt->va_base = kzalloc(size, GFP_KERNEL);
+ if (!pkt->va_base) {
+ kfree(pkt);
+ return ERR_PTR(-ENOMEM);
+ }
+ pkt->buf_size = size;
+ pkt->cl = (void *)client;
+
+ dev = client->chan->mbox->dev;
+ dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, dma_addr)) {
+ dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
+ kfree(pkt->va_base);
+ kfree(pkt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pkt->pa_base = dma_addr;
+
+ return pkt;
+}
+EXPORT_SYMBOL(cmdq_pkt_create);
+
+void cmdq_pkt_destroy(struct cmdq_pkt *pkt)
+{
+ struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
+
+ dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
+ DMA_TO_DEVICE);
+ kfree(pkt->va_base);
+ kfree(pkt);
+}
+EXPORT_SYMBOL(cmdq_pkt_destroy);
+
+static int cmdq_pkt_append_command(struct cmdq_pkt *pkt,
+ struct cmdq_instruction inst)
+{
+ struct cmdq_instruction *cmd_ptr;
+
+ if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) {
+ /*
+ * In the case of allocated buffer size (pkt->buf_size) is used
+ * up, the real required size (pkt->cmdq_buf_size) is still
+ * increased, so that the user knows how much memory should be
+ * ultimately allocated after appending all commands and
+ * flushing the command packet. Therefor, the user can call
+ * cmdq_pkt_create() again with the real required buffer size.
+ */
+ pkt->cmd_buf_size += CMDQ_INST_SIZE;
+ WARN_ONCE(1, "%s: buffer size %u is too small !\n",
+ __func__, (u32)pkt->buf_size);
+ return -ENOMEM;
+ }
+
+ cmd_ptr = pkt->va_base + pkt->cmd_buf_size;
+ *cmd_ptr = inst;
+ pkt->cmd_buf_size += CMDQ_INST_SIZE;
+
+ return 0;
+}
+
+int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
+{
+ struct cmdq_instruction inst;
+
+ inst.op = CMDQ_CODE_WRITE;
+ inst.value = value;
+ inst.offset = offset;
+ inst.subsys = subsys;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write);
+
+int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
+ u16 offset, u32 value, u32 mask)
+{
+ struct cmdq_instruction inst = { {0} };
+ u16 offset_mask = offset;
+ int err;
+
+ if (mask != 0xffffffff) {
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ offset_mask |= CMDQ_WRITE_ENABLE_MASK;
+ }
+ err = cmdq_pkt_write(pkt, subsys, offset_mask, value);
+
+ return err;
+}
+EXPORT_SYMBOL(cmdq_pkt_write_mask);
+
+int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
+ u16 reg_idx)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_READ_S;
+ inst.dst_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.reg_dst = reg_idx;
+ inst.src_reg = addr_low;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_read_s);
+
+int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+ u16 addr_low, u16 src_reg_idx)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_WRITE_S;
+ inst.src_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.src_reg = src_reg_idx;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s);
+
+int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
+ u16 addr_low, u16 src_reg_idx, u32 mask)
+{
+ struct cmdq_instruction inst = {};
+ int err;
+
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ inst.mask = 0;
+ inst.op = CMDQ_CODE_WRITE_S_MASK;
+ inst.src_t = CMDQ_REG_TYPE;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.src_reg = src_reg_idx;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask);
+
+int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+ u16 addr_low, u32 value)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_WRITE_S;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.value = value;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_value);
+
+int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
+ u16 addr_low, u32 value, u32 mask)
+{
+ struct cmdq_instruction inst = {};
+ int err;
+
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ inst.op = CMDQ_CODE_WRITE_S_MASK;
+ inst.sop = high_addr_reg_idx;
+ inst.offset = addr_low;
+ inst.value = value;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value);
+
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
+{
+ struct cmdq_instruction inst = { {0} };
+ u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0;
+
+ if (event >= CMDQ_MAX_EVENT)
+ return -EINVAL;
+
+ inst.op = CMDQ_CODE_WFE;
+ inst.value = CMDQ_WFE_OPTION | clear_option;
+ inst.event = event;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_wfe);
+
+int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
+{
+ struct cmdq_instruction inst = { {0} };
+
+ if (event >= CMDQ_MAX_EVENT)
+ return -EINVAL;
+
+ inst.op = CMDQ_CODE_WFE;
+ inst.value = CMDQ_WFE_UPDATE;
+ inst.event = event;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_clear_event);
+
+int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event)
+{
+ struct cmdq_instruction inst = {};
+
+ if (event >= CMDQ_MAX_EVENT)
+ return -EINVAL;
+
+ inst.op = CMDQ_CODE_WFE;
+ inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE;
+ inst.event = event;
+
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_set_event);
+
+int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys,
+ u16 offset, u32 value)
+{
+ struct cmdq_instruction inst = { {0} };
+ int err;
+
+ inst.op = CMDQ_CODE_POLL;
+ inst.value = value;
+ inst.offset = offset;
+ inst.subsys = subsys;
+ err = cmdq_pkt_append_command(pkt, inst);
+
+ return err;
+}
+EXPORT_SYMBOL(cmdq_pkt_poll);
+
+int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
+ u16 offset, u32 value, u32 mask)
+{
+ struct cmdq_instruction inst = { {0} };
+ int err;
+
+ inst.op = CMDQ_CODE_MASK;
+ inst.mask = ~mask;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ offset = offset | CMDQ_POLL_ENABLE_MASK;
+ err = cmdq_pkt_poll(pkt, subsys, offset, value);
+
+ return err;
+}
+EXPORT_SYMBOL(cmdq_pkt_poll_mask);
+
+int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_LOGIC;
+ inst.dst_t = CMDQ_REG_TYPE;
+ inst.reg_dst = reg_idx;
+ inst.value = value;
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_assign);
+
+int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr)
+{
+ struct cmdq_instruction inst = {};
+
+ inst.op = CMDQ_CODE_JUMP;
+ inst.offset = CMDQ_JUMP_RELATIVE;
+ inst.value = addr >>
+ cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
+ return cmdq_pkt_append_command(pkt, inst);
+}
+EXPORT_SYMBOL(cmdq_pkt_jump);
+
+int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
+{
+ struct cmdq_instruction inst = { {0} };
+ int err;
+
+ /* insert EOC and generate IRQ for each command iteration */
+ inst.op = CMDQ_CODE_EOC;
+ inst.value = CMDQ_EOC_IRQ_EN;
+ err = cmdq_pkt_append_command(pkt, inst);
+ if (err < 0)
+ return err;
+
+ /* JUMP to end */
+ inst.op = CMDQ_CODE_JUMP;
+ inst.value = CMDQ_JUMP_PASS >>
+ cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan);
+ err = cmdq_pkt_append_command(pkt, inst);
+
+ return err;
+}
+EXPORT_SYMBOL(cmdq_pkt_finalize);
+
+int cmdq_pkt_flush_async(struct cmdq_pkt *pkt)
+{
+ int err;
+ struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
+
+ err = mbox_send_message(client->chan, pkt);
+ if (err < 0)
+ return err;
+ /* We can send next packet immediately, so just call txdone. */
+ mbox_client_txdone(client->chan, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(cmdq_pkt_flush_async);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
new file mode 100644
index 000000000..fc13334db
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#define VIO_MOD_TO_REG_IND(m) ((m) / 32)
+#define VIO_MOD_TO_REG_OFF(m) ((m) % 32)
+
+struct mtk_devapc_vio_dbgs {
+ union {
+ u32 vio_dbg0;
+ struct {
+ u32 mstid:16;
+ u32 dmnid:6;
+ u32 vio_w:1;
+ u32 vio_r:1;
+ u32 addr_h:4;
+ u32 resv:4;
+ } dbg0_bits;
+ };
+
+ u32 vio_dbg1;
+};
+
+struct mtk_devapc_regs_ofs {
+ /* reg offset */
+ u32 vio_mask_offset;
+ u32 vio_sta_offset;
+ u32 vio_dbg0_offset;
+ u32 vio_dbg1_offset;
+ u32 apc_con_offset;
+ u32 vio_shift_sta_offset;
+ u32 vio_shift_sel_offset;
+ u32 vio_shift_con_offset;
+};
+
+struct mtk_devapc_data {
+ /* numbers of violation index */
+ u32 vio_idx_num;
+ const struct mtk_devapc_regs_ofs *regs_ofs;
+};
+
+struct mtk_devapc_context {
+ struct device *dev;
+ void __iomem *infra_base;
+ struct clk *infra_clk;
+ const struct mtk_devapc_data *data;
+};
+
+static void clear_vio_status(struct mtk_devapc_context *ctx)
+{
+ void __iomem *reg;
+ int i;
+
+ reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
+
+ for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+ writel(GENMASK(31, 0), reg + 4 * i);
+
+ writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
+ reg + 4 * i);
+}
+
+static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
+{
+ void __iomem *reg;
+ u32 val;
+ int i;
+
+ reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
+
+ if (mask)
+ val = GENMASK(31, 0);
+ else
+ val = 0;
+
+ for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+ writel(val, reg + 4 * i);
+
+ val = readl(reg + 4 * i);
+ if (mask)
+ val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+ 0);
+ else
+ val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+ 0);
+
+ writel(val, reg + 4 * i);
+}
+
+#define PHY_DEVAPC_TIMEOUT 0x10000
+
+/*
+ * devapc_sync_vio_dbg - do "shift" mechansim" to get full violation information.
+ * shift mechanism is depends on devapc hardware design.
+ * Mediatek devapc set multiple slaves as a group.
+ * When violation is triggered, violation info is kept
+ * inside devapc hardware.
+ * Driver should do shift mechansim to sync full violation
+ * info to VIO_DBGs registers.
+ *
+ */
+static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
+{
+ void __iomem *pd_vio_shift_sta_reg;
+ void __iomem *pd_vio_shift_sel_reg;
+ void __iomem *pd_vio_shift_con_reg;
+ int min_shift_group;
+ int ret;
+ u32 val;
+
+ pd_vio_shift_sta_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_sta_offset;
+ pd_vio_shift_sel_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_sel_offset;
+ pd_vio_shift_con_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_con_offset;
+
+ /* Find the minimum shift group which has violation */
+ val = readl(pd_vio_shift_sta_reg);
+ if (!val)
+ return false;
+
+ min_shift_group = __ffs(val);
+
+ /* Assign the group to sync */
+ writel(0x1 << min_shift_group, pd_vio_shift_sel_reg);
+
+ /* Start syncing */
+ writel(0x1, pd_vio_shift_con_reg);
+
+ ret = readl_poll_timeout(pd_vio_shift_con_reg, val, val == 0x3, 0,
+ PHY_DEVAPC_TIMEOUT);
+ if (ret) {
+ dev_err(ctx->dev, "%s: Shift violation info failed\n", __func__);
+ return false;
+ }
+
+ /* Stop syncing */
+ writel(0x0, pd_vio_shift_con_reg);
+
+ /* Write clear */
+ writel(0x1 << min_shift_group, pd_vio_shift_sta_reg);
+
+ return true;
+}
+
+/*
+ * devapc_extract_vio_dbg - extract full violation information after doing
+ * shift mechanism.
+ */
+static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
+{
+ struct mtk_devapc_vio_dbgs vio_dbgs;
+ void __iomem *vio_dbg0_reg;
+ void __iomem *vio_dbg1_reg;
+
+ vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
+ vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+
+ vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
+ vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+
+ /* Print violation information */
+ if (vio_dbgs.dbg0_bits.vio_w)
+ dev_info(ctx->dev, "Write Violation\n");
+ else if (vio_dbgs.dbg0_bits.vio_r)
+ dev_info(ctx->dev, "Read Violation\n");
+
+ dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
+ vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
+ vio_dbgs.vio_dbg1);
+}
+
+/*
+ * devapc_violation_irq - the devapc Interrupt Service Routine (ISR) will dump
+ * violation information including which master violates
+ * access slave.
+ */
+static irqreturn_t devapc_violation_irq(int irq_number, void *data)
+{
+ struct mtk_devapc_context *ctx = data;
+
+ while (devapc_sync_vio_dbg(ctx))
+ devapc_extract_vio_dbg(ctx);
+
+ clear_vio_status(ctx);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * start_devapc - unmask slave's irq to start receiving devapc violation.
+ */
+static void start_devapc(struct mtk_devapc_context *ctx)
+{
+ writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+
+ mask_module_irq(ctx, false);
+}
+
+/*
+ * stop_devapc - mask slave's irq to stop service.
+ */
+static void stop_devapc(struct mtk_devapc_context *ctx)
+{
+ mask_module_irq(ctx, true);
+
+ writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+}
+
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
+ .vio_mask_offset = 0x0,
+ .vio_sta_offset = 0x400,
+ .vio_dbg0_offset = 0x900,
+ .vio_dbg1_offset = 0x904,
+ .apc_con_offset = 0xF00,
+ .vio_shift_sta_offset = 0xF10,
+ .vio_shift_sel_offset = 0xF14,
+ .vio_shift_con_offset = 0xF20,
+};
+
+static const struct mtk_devapc_data devapc_mt6779 = {
+ .vio_idx_num = 511,
+ .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
+static const struct mtk_devapc_data devapc_mt8186 = {
+ .vio_idx_num = 519,
+ .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
+static const struct of_device_id mtk_devapc_dt_match[] = {
+ {
+ .compatible = "mediatek,mt6779-devapc",
+ .data = &devapc_mt6779,
+ }, {
+ .compatible = "mediatek,mt8186-devapc",
+ .data = &devapc_mt8186,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
+
+static int mtk_devapc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct mtk_devapc_context *ctx;
+ u32 devapc_irq;
+ int ret;
+
+ if (IS_ERR(node))
+ return -ENODEV;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->data = of_device_get_match_data(&pdev->dev);
+ ctx->dev = &pdev->dev;
+
+ ctx->infra_base = of_iomap(node, 0);
+ if (!ctx->infra_base)
+ return -EINVAL;
+
+ devapc_irq = irq_of_parse_and_map(node, 0);
+ if (!devapc_irq)
+ return -EINVAL;
+
+ ctx->infra_clk = devm_clk_get(&pdev->dev, "devapc-infra-clock");
+ if (IS_ERR(ctx->infra_clk))
+ return -EINVAL;
+
+ if (clk_prepare_enable(ctx->infra_clk))
+ return -EINVAL;
+
+ ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
+ IRQF_TRIGGER_NONE, "devapc", ctx);
+ if (ret) {
+ clk_disable_unprepare(ctx->infra_clk);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, ctx);
+
+ start_devapc(ctx);
+
+ return 0;
+}
+
+static int mtk_devapc_remove(struct platform_device *pdev)
+{
+ struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
+
+ stop_devapc(ctx);
+
+ clk_disable_unprepare(ctx->infra_clk);
+
+ return 0;
+}
+
+static struct platform_driver mtk_devapc_driver = {
+ .probe = mtk_devapc_probe,
+ .remove = mtk_devapc_remove,
+ .driver = {
+ .name = "mtk-devapc",
+ .of_match_table = mtk_devapc_dt_match,
+ },
+};
+
+module_platform_driver(mtk_devapc_driver);
+
+MODULE_DESCRIPTION("Mediatek Device APC Driver");
+MODULE_AUTHOR("Neal Liu <neal.liu@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c
new file mode 100644
index 000000000..2acf19676
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-infracfg.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
+ */
+
+#include <linux/export.h>
+#include <linux/jiffies.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/soc/mediatek/infracfg.h>
+#include <asm/processor.h>
+
+#define MTK_POLL_DELAY_US 10
+#define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ))
+
+/**
+ * mtk_infracfg_set_bus_protection - enable bus protection
+ * @infracfg: The infracfg regmap
+ * @mask: The mask containing the protection bits to be enabled.
+ * @reg_update: The boolean flag determines to set the protection bits
+ * by regmap_update_bits with enable register(PROTECTEN) or
+ * by regmap_write with set register(PROTECTEN_SET).
+ *
+ * This function enables the bus protection bits for disabled power
+ * domains so that the system does not hang when some unit accesses the
+ * bus while in power down.
+ */
+int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask,
+ bool reg_update)
+{
+ u32 val;
+ int ret;
+
+ if (reg_update)
+ regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask,
+ mask);
+ else
+ regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_SET, mask);
+
+ ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1,
+ val, (val & mask) == mask,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+
+ return ret;
+}
+
+/**
+ * mtk_infracfg_clear_bus_protection - disable bus protection
+ * @infracfg: The infracfg regmap
+ * @mask: The mask containing the protection bits to be disabled.
+ * @reg_update: The boolean flag determines to clear the protection bits
+ * by regmap_update_bits with enable register(PROTECTEN) or
+ * by regmap_write with clear register(PROTECTEN_CLR).
+ *
+ * This function disables the bus protection bits previously enabled with
+ * mtk_infracfg_set_bus_protection.
+ */
+
+int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask,
+ bool reg_update)
+{
+ int ret;
+ u32 val;
+
+ if (reg_update)
+ regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0);
+ else
+ regmap_write(infracfg, INFRA_TOPAXI_PROTECTEN_CLR, mask);
+
+ ret = regmap_read_poll_timeout(infracfg, INFRA_TOPAXI_PROTECTSTA1,
+ val, !(val & mask),
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+
+ return ret;
+}
+
+static int __init mtk_infracfg_init(void)
+{
+ struct regmap *infracfg;
+
+ /*
+ * MT8192 has an experimental path to route GPU traffic to the DSU's
+ * Accelerator Coherency Port, which is inadvertently enabled by
+ * default. It turns out not to work, so disable it to prevent spurious
+ * GPU faults.
+ */
+ infracfg = syscon_regmap_lookup_by_compatible("mediatek,mt8192-infracfg");
+ if (!IS_ERR(infracfg))
+ regmap_set_bits(infracfg, MT8192_INFRA_CTRL,
+ MT8192_INFRA_CTRL_DISABLE_MFG2ACP);
+ return 0;
+}
+postcore_initcall(mtk_infracfg_init);
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
new file mode 100644
index 000000000..d2c7a87aa
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: James Liao <jamesjj.liao@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+
+#include "mtk-mmsys.h"
+#include "mt8167-mmsys.h"
+#include "mt8183-mmsys.h"
+#include "mt8186-mmsys.h"
+#include "mt8192-mmsys.h"
+#include "mt8195-mmsys.h"
+#include "mt8365-mmsys.h"
+
+static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
+ .clk_driver = "clk-mt2701-mm",
+ .routes = mmsys_default_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_default_routing_table),
+};
+
+static const struct mtk_mmsys_match_data mt2701_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt2701_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
+ .clk_driver = "clk-mt2712-mm",
+ .routes = mmsys_default_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_default_routing_table),
+};
+
+static const struct mtk_mmsys_match_data mt2712_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt2712_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
+ .clk_driver = "clk-mt6779-mm",
+};
+
+static const struct mtk_mmsys_match_data mt6779_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt6779_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
+ .clk_driver = "clk-mt6797-mm",
+};
+
+static const struct mtk_mmsys_match_data mt6797_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt6797_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
+ .clk_driver = "clk-mt8167-mm",
+ .routes = mt8167_mmsys_routing_table,
+ .num_routes = ARRAY_SIZE(mt8167_mmsys_routing_table),
+};
+
+static const struct mtk_mmsys_match_data mt8167_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8167_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
+ .clk_driver = "clk-mt8173-mm",
+ .routes = mmsys_default_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_default_routing_table),
+ .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+};
+
+static const struct mtk_mmsys_match_data mt8173_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8173_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
+ .clk_driver = "clk-mt8183-mm",
+ .routes = mmsys_mt8183_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8183_routing_table),
+ .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B,
+};
+
+static const struct mtk_mmsys_match_data mt8183_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8183_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
+ .clk_driver = "clk-mt8186-mm",
+ .routes = mmsys_mt8186_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8186_routing_table),
+ .sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+};
+
+static const struct mtk_mmsys_match_data mt8186_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8186_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
+ .clk_driver = "clk-mt8192-mm",
+ .routes = mmsys_mt8192_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8192_routing_table),
+ .sw0_rst_offset = MT8186_MMSYS_SW0_RST_B,
+};
+
+static const struct mtk_mmsys_match_data mt8192_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8192_mmsys_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
+ .io_start = 0x1c01a000,
+ .clk_driver = "clk-mt8195-vdo0",
+ .routes = mmsys_mt8195_routing_table,
+ .num_routes = ARRAY_SIZE(mmsys_mt8195_routing_table),
+};
+
+static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
+ .io_start = 0x1c100000,
+ .clk_driver = "clk-mt8195-vdo1",
+};
+
+static const struct mtk_mmsys_match_data mt8195_mmsys_match_data = {
+ .num_drv_data = 2,
+ .drv_data = {
+ &mt8195_vdosys0_driver_data,
+ &mt8195_vdosys1_driver_data,
+ },
+};
+
+static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
+ .clk_driver = "clk-mt8365-mm",
+ .routes = mt8365_mmsys_routing_table,
+ .num_routes = ARRAY_SIZE(mt8365_mmsys_routing_table),
+};
+
+static const struct mtk_mmsys_match_data mt8365_mmsys_match_data = {
+ .num_drv_data = 1,
+ .drv_data = {
+ &mt8365_mmsys_driver_data,
+ },
+};
+
+struct mtk_mmsys {
+ void __iomem *regs;
+ const struct mtk_mmsys_driver_data *data;
+ spinlock_t lock; /* protects mmsys_sw_rst_b reg */
+ struct reset_controller_dev rcdev;
+ phys_addr_t io_start;
+};
+
+static int mtk_mmsys_find_match_drvdata(struct mtk_mmsys *mmsys,
+ const struct mtk_mmsys_match_data *match)
+{
+ int i;
+
+ for (i = 0; i < match->num_drv_data; i++)
+ if (mmsys->io_start == match->drv_data[i]->io_start)
+ return i;
+
+ return -EINVAL;
+}
+
+void mtk_mmsys_ddp_connect(struct device *dev,
+ enum mtk_ddp_comp_id cur,
+ enum mtk_ddp_comp_id next)
+{
+ struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+ const struct mtk_mmsys_routes *routes = mmsys->data->routes;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < mmsys->data->num_routes; i++)
+ if (cur == routes[i].from_comp && next == routes[i].to_comp) {
+ reg = readl_relaxed(mmsys->regs + routes[i].addr);
+ reg &= ~routes[i].mask;
+ reg |= routes[i].val;
+ writel_relaxed(reg, mmsys->regs + routes[i].addr);
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect);
+
+void mtk_mmsys_ddp_disconnect(struct device *dev,
+ enum mtk_ddp_comp_id cur,
+ enum mtk_ddp_comp_id next)
+{
+ struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+ const struct mtk_mmsys_routes *routes = mmsys->data->routes;
+ u32 reg;
+ int i;
+
+ for (i = 0; i < mmsys->data->num_routes; i++)
+ if (cur == routes[i].from_comp && next == routes[i].to_comp) {
+ reg = readl_relaxed(mmsys->regs + routes[i].addr);
+ reg &= ~routes[i].mask;
+ writel_relaxed(reg, mmsys->regs + routes[i].addr);
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
+
+static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl_relaxed(mmsys->regs + offset);
+ tmp = (tmp & ~mask) | val;
+ writel_relaxed(tmp, mmsys->regs + offset);
+}
+
+void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val)
+{
+ if (val)
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ DPI_RGB888_DDR_CON, DPI_FORMAT_MASK);
+ else
+ mtk_mmsys_update_bits(dev_get_drvdata(dev), MT8186_MMSYS_DPI_OUTPUT_FORMAT,
+ DPI_RGB565_SDR_CON, DPI_FORMAT_MASK);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config);
+
+static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id,
+ bool assert)
+{
+ struct mtk_mmsys *mmsys = container_of(rcdev, struct mtk_mmsys, rcdev);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&mmsys->lock, flags);
+
+ reg = readl_relaxed(mmsys->regs + mmsys->data->sw0_rst_offset);
+
+ if (assert)
+ reg &= ~BIT(id);
+ else
+ reg |= BIT(id);
+
+ writel_relaxed(reg, mmsys->regs + mmsys->data->sw0_rst_offset);
+
+ spin_unlock_irqrestore(&mmsys->lock, flags);
+
+ return 0;
+}
+
+static int mtk_mmsys_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ return mtk_mmsys_reset_update(rcdev, id, true);
+}
+
+static int mtk_mmsys_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ return mtk_mmsys_reset_update(rcdev, id, false);
+}
+
+static int mtk_mmsys_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ int ret;
+
+ ret = mtk_mmsys_reset_assert(rcdev, id);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 1100);
+
+ return mtk_mmsys_reset_deassert(rcdev, id);
+}
+
+static const struct reset_control_ops mtk_mmsys_reset_ops = {
+ .assert = mtk_mmsys_reset_assert,
+ .deassert = mtk_mmsys_reset_deassert,
+ .reset = mtk_mmsys_reset,
+};
+
+static int mtk_mmsys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct platform_device *clks;
+ struct platform_device *drm;
+ const struct mtk_mmsys_match_data *match_data;
+ struct mtk_mmsys *mmsys;
+ struct resource *res;
+ int ret;
+
+ mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
+ if (!mmsys)
+ return -ENOMEM;
+
+ mmsys->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(mmsys->regs)) {
+ ret = PTR_ERR(mmsys->regs);
+ dev_err(dev, "Failed to ioremap mmsys registers: %d\n", ret);
+ return ret;
+ }
+
+ spin_lock_init(&mmsys->lock);
+
+ mmsys->rcdev.owner = THIS_MODULE;
+ mmsys->rcdev.nr_resets = 32;
+ mmsys->rcdev.ops = &mtk_mmsys_reset_ops;
+ mmsys->rcdev.of_node = pdev->dev.of_node;
+ ret = devm_reset_controller_register(&pdev->dev, &mmsys->rcdev);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't register mmsys reset controller: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "Couldn't get mmsys resource\n");
+ return -EINVAL;
+ }
+ mmsys->io_start = res->start;
+
+ match_data = of_device_get_match_data(dev);
+ if (match_data->num_drv_data > 1) {
+ /* This SoC has multiple mmsys channels */
+ ret = mtk_mmsys_find_match_drvdata(mmsys, match_data);
+ if (ret < 0) {
+ dev_err(dev, "Couldn't get match driver data\n");
+ return ret;
+ }
+ mmsys->data = match_data->drv_data[ret];
+ } else {
+ dev_dbg(dev, "Using single mmsys channel\n");
+ mmsys->data = match_data->drv_data[0];
+ }
+
+ platform_set_drvdata(pdev, mmsys);
+
+ clks = platform_device_register_data(&pdev->dev, mmsys->data->clk_driver,
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(clks))
+ return PTR_ERR(clks);
+
+ drm = platform_device_register_data(&pdev->dev, "mediatek-drm",
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(drm)) {
+ platform_device_unregister(clks);
+ return PTR_ERR(drm);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_match_mtk_mmsys[] = {
+ {
+ .compatible = "mediatek,mt2701-mmsys",
+ .data = &mt2701_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt2712-mmsys",
+ .data = &mt2712_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt6779-mmsys",
+ .data = &mt6779_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt6797-mmsys",
+ .data = &mt6797_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8167-mmsys",
+ .data = &mt8167_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8173-mmsys",
+ .data = &mt8173_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8183-mmsys",
+ .data = &mt8183_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8186-mmsys",
+ .data = &mt8186_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8192-mmsys",
+ .data = &mt8192_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8195-mmsys",
+ .data = &mt8195_mmsys_match_data,
+ },
+ {
+ .compatible = "mediatek,mt8365-mmsys",
+ .data = &mt8365_mmsys_match_data,
+ },
+ { }
+};
+
+static struct platform_driver mtk_mmsys_drv = {
+ .driver = {
+ .name = "mtk-mmsys",
+ .of_match_table = of_match_mtk_mmsys,
+ },
+ .probe = mtk_mmsys_probe,
+};
+
+builtin_platform_driver(mtk_mmsys_drv);
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
new file mode 100644
index 000000000..f01ba2064
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MTK_MMSYS_H
+#define __SOC_MEDIATEK_MTK_MMSYS_H
+
+#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
+#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
+#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
+#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c
+#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
+#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
+#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
+#define DISP_REG_CONFIG_DSIE_SEL_IN 0x0a4
+#define DISP_REG_CONFIG_DSIO_SEL_IN 0x0a8
+#define DISP_REG_CONFIG_DPI_SEL_IN 0x0ac
+#define DISP_REG_CONFIG_DISP_RDMA2_SOUT 0x0b8
+#define DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN 0x0c4
+#define DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8
+#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100
+
+#define DISP_REG_CONFIG_DISP_OVL_MOUT_EN 0x030
+#define DISP_REG_CONFIG_OUT_SEL 0x04c
+#define DISP_REG_CONFIG_DSI_SEL 0x050
+#define DISP_REG_CONFIG_DPI_SEL 0x064
+
+#define OVL0_MOUT_EN_COLOR0 0x1
+#define OD_MOUT_EN_RDMA0 0x1
+#define OD1_MOUT_EN_RDMA1 BIT(16)
+#define UFOE_MOUT_EN_DSI0 0x1
+#define COLOR0_SEL_IN_OVL0 0x1
+#define OVL1_MOUT_EN_COLOR1 0x1
+#define GAMMA_MOUT_EN_RDMA1 0x1
+#define RDMA0_SOUT_DPI0 0x2
+#define RDMA0_SOUT_DPI1 0x3
+#define RDMA0_SOUT_DSI1 0x1
+#define RDMA0_SOUT_DSI2 0x4
+#define RDMA0_SOUT_DSI3 0x5
+#define RDMA0_SOUT_MASK 0x7
+#define RDMA1_SOUT_DPI0 0x2
+#define RDMA1_SOUT_DPI1 0x3
+#define RDMA1_SOUT_DSI1 0x1
+#define RDMA1_SOUT_DSI2 0x4
+#define RDMA1_SOUT_DSI3 0x5
+#define RDMA1_SOUT_MASK 0x7
+#define RDMA2_SOUT_DPI0 0x2
+#define RDMA2_SOUT_DPI1 0x3
+#define RDMA2_SOUT_DSI1 0x1
+#define RDMA2_SOUT_DSI2 0x4
+#define RDMA2_SOUT_DSI3 0x5
+#define RDMA2_SOUT_MASK 0x7
+#define DPI0_SEL_IN_RDMA1 0x1
+#define DPI0_SEL_IN_RDMA2 0x3
+#define DPI0_SEL_IN_MASK 0x3
+#define DPI1_SEL_IN_RDMA1 (0x1 << 8)
+#define DPI1_SEL_IN_RDMA2 (0x3 << 8)
+#define DPI1_SEL_IN_MASK (0x3 << 8)
+#define DSI0_SEL_IN_RDMA1 0x1
+#define DSI0_SEL_IN_RDMA2 0x4
+#define DSI0_SEL_IN_MASK 0x7
+#define DSI1_SEL_IN_RDMA1 0x1
+#define DSI1_SEL_IN_RDMA2 0x4
+#define DSI1_SEL_IN_MASK 0x7
+#define DSI2_SEL_IN_RDMA1 (0x1 << 16)
+#define DSI2_SEL_IN_RDMA2 (0x4 << 16)
+#define DSI2_SEL_IN_MASK (0x7 << 16)
+#define DSI3_SEL_IN_RDMA1 (0x1 << 16)
+#define DSI3_SEL_IN_RDMA2 (0x4 << 16)
+#define DSI3_SEL_IN_MASK (0x7 << 16)
+#define COLOR1_SEL_IN_OVL1 0x1
+
+#define OVL_MOUT_EN_RDMA 0x1
+#define BLS_TO_DSI_RDMA1_TO_DPI1 0x8
+#define BLS_TO_DPI_RDMA1_TO_DSI 0x2
+#define BLS_RDMA1_DSI_DPI_MASK 0xf
+#define DSI_SEL_IN_BLS 0x0
+#define DPI_SEL_IN_BLS 0x0
+#define DPI_SEL_IN_MASK 0x1
+#define DSI_SEL_IN_RDMA 0x1
+#define DSI_SEL_IN_MASK 0x1
+
+struct mtk_mmsys_routes {
+ u32 from_comp;
+ u32 to_comp;
+ u32 addr;
+ u32 mask;
+ u32 val;
+};
+
+struct mtk_mmsys_driver_data {
+ const resource_size_t io_start;
+ const char *clk_driver;
+ const struct mtk_mmsys_routes *routes;
+ const unsigned int num_routes;
+ const u16 sw0_rst_offset;
+};
+
+struct mtk_mmsys_match_data {
+ unsigned short num_drv_data;
+ const struct mtk_mmsys_driver_data *drv_data[];
+};
+
+/*
+ * Routes in mt8173, mt2701, mt2712 are different. That means
+ * in the same register address, it controls different input/output
+ * selection for each SoC. But, right now, they use the same table as
+ * default routes meet their requirements. But we don't have the complete
+ * route information for these three SoC, so just keep them in the same
+ * table. After we've more information, we could separate mt2701, mt2712
+ * to an independent table.
+ */
+static const struct mtk_mmsys_routes mmsys_default_routing_table[] = {
+ {
+ DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0,
+ DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK,
+ BLS_TO_DSI_RDMA1_TO_DPI1
+ }, {
+ DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0,
+ DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK,
+ DSI_SEL_IN_BLS
+ }, {
+ DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK,
+ BLS_TO_DPI_RDMA1_TO_DSI
+ }, {
+ DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK,
+ DSI_SEL_IN_RDMA
+ }, {
+ DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DPI_SEL, DPI_SEL_IN_MASK,
+ DPI_SEL_IN_BLS
+ }, {
+ DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1,
+ DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, GAMMA_MOUT_EN_RDMA1,
+ GAMMA_MOUT_EN_RDMA1
+ }, {
+ DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0,
+ DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD_MOUT_EN_RDMA0,
+ OD_MOUT_EN_RDMA0
+ }, {
+ DDP_COMPONENT_OD1, DDP_COMPONENT_RDMA1,
+ DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD1_MOUT_EN_RDMA1,
+ OD1_MOUT_EN_RDMA1
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
+ DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
+ OVL0_MOUT_EN_COLOR0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0,
+ DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
+ COLOR0_SEL_IN_OVL0
+ }, {
+ DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0,
+ DISP_REG_CONFIG_DISP_OVL_MOUT_EN, OVL_MOUT_EN_RDMA,
+ OVL_MOUT_EN_RDMA
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
+ DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, OVL1_MOUT_EN_COLOR1,
+ OVL1_MOUT_EN_COLOR1
+ }, {
+ DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1,
+ DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1,
+ COLOR1_SEL_IN_OVL1
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
+ RDMA0_SOUT_DPI0
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI1,
+ DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
+ RDMA0_SOUT_DPI1
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI1,
+ DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
+ RDMA0_SOUT_DSI1
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI2,
+ DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
+ RDMA0_SOUT_DSI2
+ }, {
+ DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI3,
+ DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK,
+ RDMA0_SOUT_DSI3
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DPI0
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK,
+ DPI0_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1,
+ DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DPI1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1,
+ DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK,
+ DPI1_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI0,
+ DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK,
+ DSI0_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1,
+ DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DSI1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1,
+ DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK,
+ DSI1_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2,
+ DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DSI2
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2,
+ DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK,
+ DSI2_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3,
+ DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
+ RDMA1_SOUT_DSI3
+ }, {
+ DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3,
+ DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK,
+ DSI3_SEL_IN_RDMA1
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
+ RDMA2_SOUT_DPI0
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0,
+ DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK,
+ DPI0_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1,
+ DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
+ RDMA2_SOUT_DPI1
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1,
+ DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK,
+ DPI1_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI0,
+ DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK,
+ DSI0_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1,
+ DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
+ RDMA2_SOUT_DSI1
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1,
+ DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK,
+ DSI1_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2,
+ DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
+ RDMA2_SOUT_DSI2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2,
+ DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK,
+ DSI2_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3,
+ DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK,
+ RDMA2_SOUT_DSI3
+ }, {
+ DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3,
+ DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK,
+ DSI3_SEL_IN_RDMA2
+ }, {
+ DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0,
+ DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, UFOE_MOUT_EN_DSI0,
+ UFOE_MOUT_EN_DSI0
+ }
+};
+
+#endif /* __SOC_MEDIATEK_MTK_MMSYS_H */
diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c
new file mode 100644
index 000000000..c1a33d520
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-mutex.c
@@ -0,0 +1,877 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+#include <linux/soc/mediatek/mtk-mutex.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#define MT2701_MUTEX0_MOD0 0x2c
+#define MT2701_MUTEX0_SOF0 0x30
+#define MT8183_MUTEX0_MOD0 0x30
+#define MT8183_MUTEX0_SOF0 0x2c
+
+#define DISP_REG_MUTEX_EN(n) (0x20 + 0x20 * (n))
+#define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n))
+#define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n))
+#define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n))
+#define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n))
+#define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n))
+
+#define INT_MUTEX BIT(1)
+
+#define MT8186_MUTEX_MOD_DISP_OVL0 0
+#define MT8186_MUTEX_MOD_DISP_OVL0_2L 1
+#define MT8186_MUTEX_MOD_DISP_RDMA0 2
+#define MT8186_MUTEX_MOD_DISP_COLOR0 4
+#define MT8186_MUTEX_MOD_DISP_CCORR0 5
+#define MT8186_MUTEX_MOD_DISP_AAL0 7
+#define MT8186_MUTEX_MOD_DISP_GAMMA0 8
+#define MT8186_MUTEX_MOD_DISP_POSTMASK0 9
+#define MT8186_MUTEX_MOD_DISP_DITHER0 10
+#define MT8186_MUTEX_MOD_DISP_RDMA1 17
+
+#define MT8186_MUTEX_SOF_SINGLE_MODE 0
+#define MT8186_MUTEX_SOF_DSI0 1
+#define MT8186_MUTEX_SOF_DPI0 2
+#define MT8186_MUTEX_EOF_DSI0 (MT8186_MUTEX_SOF_DSI0 << 6)
+#define MT8186_MUTEX_EOF_DPI0 (MT8186_MUTEX_SOF_DPI0 << 6)
+
+#define MT8167_MUTEX_MOD_DISP_PWM 1
+#define MT8167_MUTEX_MOD_DISP_OVL0 6
+#define MT8167_MUTEX_MOD_DISP_OVL1 7
+#define MT8167_MUTEX_MOD_DISP_RDMA0 8
+#define MT8167_MUTEX_MOD_DISP_RDMA1 9
+#define MT8167_MUTEX_MOD_DISP_WDMA0 10
+#define MT8167_MUTEX_MOD_DISP_CCORR 11
+#define MT8167_MUTEX_MOD_DISP_COLOR 12
+#define MT8167_MUTEX_MOD_DISP_AAL 13
+#define MT8167_MUTEX_MOD_DISP_GAMMA 14
+#define MT8167_MUTEX_MOD_DISP_DITHER 15
+#define MT8167_MUTEX_MOD_DISP_UFOE 16
+
+#define MT8192_MUTEX_MOD_DISP_OVL0 0
+#define MT8192_MUTEX_MOD_DISP_OVL0_2L 1
+#define MT8192_MUTEX_MOD_DISP_RDMA0 2
+#define MT8192_MUTEX_MOD_DISP_COLOR0 4
+#define MT8192_MUTEX_MOD_DISP_CCORR0 5
+#define MT8192_MUTEX_MOD_DISP_AAL0 6
+#define MT8192_MUTEX_MOD_DISP_GAMMA0 7
+#define MT8192_MUTEX_MOD_DISP_POSTMASK0 8
+#define MT8192_MUTEX_MOD_DISP_DITHER0 9
+#define MT8192_MUTEX_MOD_DISP_OVL2_2L 16
+#define MT8192_MUTEX_MOD_DISP_RDMA4 17
+
+#define MT8183_MUTEX_MOD_DISP_RDMA0 0
+#define MT8183_MUTEX_MOD_DISP_RDMA1 1
+#define MT8183_MUTEX_MOD_DISP_OVL0 9
+#define MT8183_MUTEX_MOD_DISP_OVL0_2L 10
+#define MT8183_MUTEX_MOD_DISP_OVL1_2L 11
+#define MT8183_MUTEX_MOD_DISP_WDMA0 12
+#define MT8183_MUTEX_MOD_DISP_COLOR0 13
+#define MT8183_MUTEX_MOD_DISP_CCORR0 14
+#define MT8183_MUTEX_MOD_DISP_AAL0 15
+#define MT8183_MUTEX_MOD_DISP_GAMMA0 16
+#define MT8183_MUTEX_MOD_DISP_DITHER0 17
+
+#define MT8183_MUTEX_MOD_MDP_RDMA0 2
+#define MT8183_MUTEX_MOD_MDP_RSZ0 4
+#define MT8183_MUTEX_MOD_MDP_RSZ1 5
+#define MT8183_MUTEX_MOD_MDP_TDSHP0 6
+#define MT8183_MUTEX_MOD_MDP_WROT0 7
+#define MT8183_MUTEX_MOD_MDP_WDMA 8
+#define MT8183_MUTEX_MOD_MDP_AAL0 23
+#define MT8183_MUTEX_MOD_MDP_CCORR0 24
+
+#define MT8186_MUTEX_MOD_MDP_RDMA0 0
+#define MT8186_MUTEX_MOD_MDP_AAL0 2
+#define MT8186_MUTEX_MOD_MDP_HDR0 4
+#define MT8186_MUTEX_MOD_MDP_RSZ0 5
+#define MT8186_MUTEX_MOD_MDP_RSZ1 6
+#define MT8186_MUTEX_MOD_MDP_WROT0 7
+#define MT8186_MUTEX_MOD_MDP_TDSHP0 9
+#define MT8186_MUTEX_MOD_MDP_COLOR0 14
+
+#define MT8173_MUTEX_MOD_DISP_OVL0 11
+#define MT8173_MUTEX_MOD_DISP_OVL1 12
+#define MT8173_MUTEX_MOD_DISP_RDMA0 13
+#define MT8173_MUTEX_MOD_DISP_RDMA1 14
+#define MT8173_MUTEX_MOD_DISP_RDMA2 15
+#define MT8173_MUTEX_MOD_DISP_WDMA0 16
+#define MT8173_MUTEX_MOD_DISP_WDMA1 17
+#define MT8173_MUTEX_MOD_DISP_COLOR0 18
+#define MT8173_MUTEX_MOD_DISP_COLOR1 19
+#define MT8173_MUTEX_MOD_DISP_AAL 20
+#define MT8173_MUTEX_MOD_DISP_GAMMA 21
+#define MT8173_MUTEX_MOD_DISP_UFOE 22
+#define MT8173_MUTEX_MOD_DISP_PWM0 23
+#define MT8173_MUTEX_MOD_DISP_PWM1 24
+#define MT8173_MUTEX_MOD_DISP_OD 25
+
+#define MT8195_MUTEX_MOD_DISP_OVL0 0
+#define MT8195_MUTEX_MOD_DISP_WDMA0 1
+#define MT8195_MUTEX_MOD_DISP_RDMA0 2
+#define MT8195_MUTEX_MOD_DISP_COLOR0 3
+#define MT8195_MUTEX_MOD_DISP_CCORR0 4
+#define MT8195_MUTEX_MOD_DISP_AAL0 5
+#define MT8195_MUTEX_MOD_DISP_GAMMA0 6
+#define MT8195_MUTEX_MOD_DISP_DITHER0 7
+#define MT8195_MUTEX_MOD_DISP_DSI0 8
+#define MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 9
+#define MT8195_MUTEX_MOD_DISP_VPP_MERGE 20
+#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
+#define MT8195_MUTEX_MOD_DISP_PWM0 27
+
+#define MT8365_MUTEX_MOD_DISP_OVL0 7
+#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
+#define MT8365_MUTEX_MOD_DISP_RDMA0 9
+#define MT8365_MUTEX_MOD_DISP_RDMA1 10
+#define MT8365_MUTEX_MOD_DISP_WDMA0 11
+#define MT8365_MUTEX_MOD_DISP_COLOR0 12
+#define MT8365_MUTEX_MOD_DISP_CCORR 13
+#define MT8365_MUTEX_MOD_DISP_AAL 14
+#define MT8365_MUTEX_MOD_DISP_GAMMA 15
+#define MT8365_MUTEX_MOD_DISP_DITHER 16
+#define MT8365_MUTEX_MOD_DISP_DSI0 17
+#define MT8365_MUTEX_MOD_DISP_PWM0 20
+#define MT8365_MUTEX_MOD_DISP_DPI0 22
+
+#define MT2712_MUTEX_MOD_DISP_PWM2 10
+#define MT2712_MUTEX_MOD_DISP_OVL0 11
+#define MT2712_MUTEX_MOD_DISP_OVL1 12
+#define MT2712_MUTEX_MOD_DISP_RDMA0 13
+#define MT2712_MUTEX_MOD_DISP_RDMA1 14
+#define MT2712_MUTEX_MOD_DISP_RDMA2 15
+#define MT2712_MUTEX_MOD_DISP_WDMA0 16
+#define MT2712_MUTEX_MOD_DISP_WDMA1 17
+#define MT2712_MUTEX_MOD_DISP_COLOR0 18
+#define MT2712_MUTEX_MOD_DISP_COLOR1 19
+#define MT2712_MUTEX_MOD_DISP_AAL0 20
+#define MT2712_MUTEX_MOD_DISP_UFOE 22
+#define MT2712_MUTEX_MOD_DISP_PWM0 23
+#define MT2712_MUTEX_MOD_DISP_PWM1 24
+#define MT2712_MUTEX_MOD_DISP_OD0 25
+#define MT2712_MUTEX_MOD2_DISP_AAL1 33
+#define MT2712_MUTEX_MOD2_DISP_OD1 34
+
+#define MT2701_MUTEX_MOD_DISP_OVL 3
+#define MT2701_MUTEX_MOD_DISP_WDMA 6
+#define MT2701_MUTEX_MOD_DISP_COLOR 7
+#define MT2701_MUTEX_MOD_DISP_BLS 9
+#define MT2701_MUTEX_MOD_DISP_RDMA0 10
+#define MT2701_MUTEX_MOD_DISP_RDMA1 12
+
+#define MT2712_MUTEX_SOF_SINGLE_MODE 0
+#define MT2712_MUTEX_SOF_DSI0 1
+#define MT2712_MUTEX_SOF_DSI1 2
+#define MT2712_MUTEX_SOF_DPI0 3
+#define MT2712_MUTEX_SOF_DPI1 4
+#define MT2712_MUTEX_SOF_DSI2 5
+#define MT2712_MUTEX_SOF_DSI3 6
+#define MT8167_MUTEX_SOF_DPI0 2
+#define MT8167_MUTEX_SOF_DPI1 3
+#define MT8183_MUTEX_SOF_DSI0 1
+#define MT8183_MUTEX_SOF_DPI0 2
+#define MT8195_MUTEX_SOF_DSI0 1
+#define MT8195_MUTEX_SOF_DSI1 2
+#define MT8195_MUTEX_SOF_DP_INTF0 3
+#define MT8195_MUTEX_SOF_DP_INTF1 4
+#define MT8195_MUTEX_SOF_DPI0 6 /* for HDMI_TX */
+#define MT8195_MUTEX_SOF_DPI1 5 /* for digital video out */
+
+#define MT8183_MUTEX_EOF_DSI0 (MT8183_MUTEX_SOF_DSI0 << 6)
+#define MT8183_MUTEX_EOF_DPI0 (MT8183_MUTEX_SOF_DPI0 << 6)
+#define MT8195_MUTEX_EOF_DSI0 (MT8195_MUTEX_SOF_DSI0 << 7)
+#define MT8195_MUTEX_EOF_DSI1 (MT8195_MUTEX_SOF_DSI1 << 7)
+#define MT8195_MUTEX_EOF_DP_INTF0 (MT8195_MUTEX_SOF_DP_INTF0 << 7)
+#define MT8195_MUTEX_EOF_DP_INTF1 (MT8195_MUTEX_SOF_DP_INTF1 << 7)
+#define MT8195_MUTEX_EOF_DPI0 (MT8195_MUTEX_SOF_DPI0 << 7)
+#define MT8195_MUTEX_EOF_DPI1 (MT8195_MUTEX_SOF_DPI1 << 7)
+
+struct mtk_mutex {
+ int id;
+ bool claimed;
+};
+
+enum mtk_mutex_sof_id {
+ MUTEX_SOF_SINGLE_MODE,
+ MUTEX_SOF_DSI0,
+ MUTEX_SOF_DSI1,
+ MUTEX_SOF_DPI0,
+ MUTEX_SOF_DPI1,
+ MUTEX_SOF_DSI2,
+ MUTEX_SOF_DSI3,
+ MUTEX_SOF_DP_INTF0,
+ MUTEX_SOF_DP_INTF1,
+ DDP_MUTEX_SOF_MAX,
+};
+
+struct mtk_mutex_data {
+ const unsigned int *mutex_mod;
+ const unsigned int *mutex_sof;
+ const unsigned int mutex_mod_reg;
+ const unsigned int mutex_sof_reg;
+ const unsigned int *mutex_table_mod;
+ const bool no_clk;
+};
+
+struct mtk_mutex_ctx {
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *regs;
+ struct mtk_mutex mutex[10];
+ const struct mtk_mutex_data *data;
+ phys_addr_t addr;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+static const unsigned int mt2701_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_BLS] = MT2701_MUTEX_MOD_DISP_BLS,
+ [DDP_COMPONENT_COLOR0] = MT2701_MUTEX_MOD_DISP_COLOR,
+ [DDP_COMPONENT_OVL0] = MT2701_MUTEX_MOD_DISP_OVL,
+ [DDP_COMPONENT_RDMA0] = MT2701_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT2701_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_WDMA0] = MT2701_MUTEX_MOD_DISP_WDMA,
+};
+
+static const unsigned int mt2712_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT2712_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_AAL1] = MT2712_MUTEX_MOD2_DISP_AAL1,
+ [DDP_COMPONENT_COLOR0] = MT2712_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_COLOR1] = MT2712_MUTEX_MOD_DISP_COLOR1,
+ [DDP_COMPONENT_OD0] = MT2712_MUTEX_MOD_DISP_OD0,
+ [DDP_COMPONENT_OD1] = MT2712_MUTEX_MOD2_DISP_OD1,
+ [DDP_COMPONENT_OVL0] = MT2712_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT2712_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT2712_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_PWM1] = MT2712_MUTEX_MOD_DISP_PWM1,
+ [DDP_COMPONENT_PWM2] = MT2712_MUTEX_MOD_DISP_PWM2,
+ [DDP_COMPONENT_RDMA0] = MT2712_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT2712_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_RDMA2] = MT2712_MUTEX_MOD_DISP_RDMA2,
+ [DDP_COMPONENT_UFOE] = MT2712_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT2712_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_WDMA1] = MT2712_MUTEX_MOD_DISP_WDMA1,
+};
+
+static const unsigned int mt8167_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8167_MUTEX_MOD_DISP_AAL,
+ [DDP_COMPONENT_CCORR] = MT8167_MUTEX_MOD_DISP_CCORR,
+ [DDP_COMPONENT_COLOR0] = MT8167_MUTEX_MOD_DISP_COLOR,
+ [DDP_COMPONENT_DITHER0] = MT8167_MUTEX_MOD_DISP_DITHER,
+ [DDP_COMPONENT_GAMMA] = MT8167_MUTEX_MOD_DISP_GAMMA,
+ [DDP_COMPONENT_OVL0] = MT8167_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT8167_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT8167_MUTEX_MOD_DISP_PWM,
+ [DDP_COMPONENT_RDMA0] = MT8167_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8167_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_UFOE] = MT8167_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT8167_MUTEX_MOD_DISP_WDMA0,
+};
+
+static const unsigned int mt8173_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8173_MUTEX_MOD_DISP_AAL,
+ [DDP_COMPONENT_COLOR0] = MT8173_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_COLOR1] = MT8173_MUTEX_MOD_DISP_COLOR1,
+ [DDP_COMPONENT_GAMMA] = MT8173_MUTEX_MOD_DISP_GAMMA,
+ [DDP_COMPONENT_OD0] = MT8173_MUTEX_MOD_DISP_OD,
+ [DDP_COMPONENT_OVL0] = MT8173_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL1] = MT8173_MUTEX_MOD_DISP_OVL1,
+ [DDP_COMPONENT_PWM0] = MT8173_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_PWM1] = MT8173_MUTEX_MOD_DISP_PWM1,
+ [DDP_COMPONENT_RDMA0] = MT8173_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8173_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_RDMA2] = MT8173_MUTEX_MOD_DISP_RDMA2,
+ [DDP_COMPONENT_UFOE] = MT8173_MUTEX_MOD_DISP_UFOE,
+ [DDP_COMPONENT_WDMA0] = MT8173_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_WDMA1] = MT8173_MUTEX_MOD_DISP_WDMA1,
+};
+
+static const unsigned int mt8183_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8183_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_CCORR] = MT8183_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_COLOR0] = MT8183_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_DITHER0] = MT8183_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_GAMMA] = MT8183_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_OVL0] = MT8183_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL_2L0] = MT8183_MUTEX_MOD_DISP_OVL0_2L,
+ [DDP_COMPONENT_OVL_2L1] = MT8183_MUTEX_MOD_DISP_OVL1_2L,
+ [DDP_COMPONENT_RDMA0] = MT8183_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8183_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_WDMA0] = MT8183_MUTEX_MOD_DISP_WDMA0,
+};
+
+static const unsigned int mt8183_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+ [MUTEX_MOD_IDX_MDP_RDMA0] = MT8183_MUTEX_MOD_MDP_RDMA0,
+ [MUTEX_MOD_IDX_MDP_RSZ0] = MT8183_MUTEX_MOD_MDP_RSZ0,
+ [MUTEX_MOD_IDX_MDP_RSZ1] = MT8183_MUTEX_MOD_MDP_RSZ1,
+ [MUTEX_MOD_IDX_MDP_TDSHP0] = MT8183_MUTEX_MOD_MDP_TDSHP0,
+ [MUTEX_MOD_IDX_MDP_WROT0] = MT8183_MUTEX_MOD_MDP_WROT0,
+ [MUTEX_MOD_IDX_MDP_WDMA] = MT8183_MUTEX_MOD_MDP_WDMA,
+ [MUTEX_MOD_IDX_MDP_AAL0] = MT8183_MUTEX_MOD_MDP_AAL0,
+ [MUTEX_MOD_IDX_MDP_CCORR0] = MT8183_MUTEX_MOD_MDP_CCORR0,
+};
+
+static const unsigned int mt8186_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8186_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_CCORR] = MT8186_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_COLOR0] = MT8186_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_DITHER0] = MT8186_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_GAMMA] = MT8186_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_OVL0] = MT8186_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL_2L0] = MT8186_MUTEX_MOD_DISP_OVL0_2L,
+ [DDP_COMPONENT_POSTMASK0] = MT8186_MUTEX_MOD_DISP_POSTMASK0,
+ [DDP_COMPONENT_RDMA0] = MT8186_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8186_MUTEX_MOD_DISP_RDMA1,
+};
+
+static const unsigned int mt8186_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = {
+ [MUTEX_MOD_IDX_MDP_RDMA0] = MT8186_MUTEX_MOD_MDP_RDMA0,
+ [MUTEX_MOD_IDX_MDP_RSZ0] = MT8186_MUTEX_MOD_MDP_RSZ0,
+ [MUTEX_MOD_IDX_MDP_RSZ1] = MT8186_MUTEX_MOD_MDP_RSZ1,
+ [MUTEX_MOD_IDX_MDP_TDSHP0] = MT8186_MUTEX_MOD_MDP_TDSHP0,
+ [MUTEX_MOD_IDX_MDP_WROT0] = MT8186_MUTEX_MOD_MDP_WROT0,
+ [MUTEX_MOD_IDX_MDP_HDR0] = MT8186_MUTEX_MOD_MDP_HDR0,
+ [MUTEX_MOD_IDX_MDP_AAL0] = MT8186_MUTEX_MOD_MDP_AAL0,
+ [MUTEX_MOD_IDX_MDP_COLOR0] = MT8186_MUTEX_MOD_MDP_COLOR0,
+};
+
+static const unsigned int mt8192_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8192_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_CCORR] = MT8192_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_COLOR0] = MT8192_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_DITHER0] = MT8192_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_GAMMA] = MT8192_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_POSTMASK0] = MT8192_MUTEX_MOD_DISP_POSTMASK0,
+ [DDP_COMPONENT_OVL0] = MT8192_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL_2L0] = MT8192_MUTEX_MOD_DISP_OVL0_2L,
+ [DDP_COMPONENT_OVL_2L2] = MT8192_MUTEX_MOD_DISP_OVL2_2L,
+ [DDP_COMPONENT_RDMA0] = MT8192_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA4] = MT8192_MUTEX_MOD_DISP_RDMA4,
+};
+
+static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_OVL0] = MT8195_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_WDMA0] = MT8195_MUTEX_MOD_DISP_WDMA0,
+ [DDP_COMPONENT_RDMA0] = MT8195_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_COLOR0] = MT8195_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_CCORR] = MT8195_MUTEX_MOD_DISP_CCORR0,
+ [DDP_COMPONENT_AAL0] = MT8195_MUTEX_MOD_DISP_AAL0,
+ [DDP_COMPONENT_GAMMA] = MT8195_MUTEX_MOD_DISP_GAMMA0,
+ [DDP_COMPONENT_DITHER0] = MT8195_MUTEX_MOD_DISP_DITHER0,
+ [DDP_COMPONENT_MERGE0] = MT8195_MUTEX_MOD_DISP_VPP_MERGE,
+ [DDP_COMPONENT_DSC0] = MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0,
+ [DDP_COMPONENT_DSI0] = MT8195_MUTEX_MOD_DISP_DSI0,
+ [DDP_COMPONENT_PWM0] = MT8195_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_DP_INTF0] = MT8195_MUTEX_MOD_DISP_DP_INTF0,
+};
+
+static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = {
+ [DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL,
+ [DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR,
+ [DDP_COMPONENT_COLOR0] = MT8365_MUTEX_MOD_DISP_COLOR0,
+ [DDP_COMPONENT_DITHER0] = MT8365_MUTEX_MOD_DISP_DITHER,
+ [DDP_COMPONENT_DPI0] = MT8365_MUTEX_MOD_DISP_DPI0,
+ [DDP_COMPONENT_DSI0] = MT8365_MUTEX_MOD_DISP_DSI0,
+ [DDP_COMPONENT_GAMMA] = MT8365_MUTEX_MOD_DISP_GAMMA,
+ [DDP_COMPONENT_OVL0] = MT8365_MUTEX_MOD_DISP_OVL0,
+ [DDP_COMPONENT_OVL_2L0] = MT8365_MUTEX_MOD_DISP_OVL0_2L,
+ [DDP_COMPONENT_PWM0] = MT8365_MUTEX_MOD_DISP_PWM0,
+ [DDP_COMPONENT_RDMA0] = MT8365_MUTEX_MOD_DISP_RDMA0,
+ [DDP_COMPONENT_RDMA1] = MT8365_MUTEX_MOD_DISP_RDMA1,
+ [DDP_COMPONENT_WDMA0] = MT8365_MUTEX_MOD_DISP_WDMA0,
+};
+
+static const unsigned int mt2712_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
+ [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
+ [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
+ [MUTEX_SOF_DPI1] = MUTEX_SOF_DPI1,
+ [MUTEX_SOF_DSI2] = MUTEX_SOF_DSI2,
+ [MUTEX_SOF_DSI3] = MUTEX_SOF_DSI3,
+};
+
+static const unsigned int mt6795_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
+ [MUTEX_SOF_DSI1] = MUTEX_SOF_DSI1,
+ [MUTEX_SOF_DPI0] = MUTEX_SOF_DPI0,
+};
+
+static const unsigned int mt8167_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0,
+ [MUTEX_SOF_DPI0] = MT8167_MUTEX_SOF_DPI0,
+ [MUTEX_SOF_DPI1] = MT8167_MUTEX_SOF_DPI1,
+};
+
+/* Add EOF setting so overlay hardware can receive frame done irq */
+static const unsigned int mt8183_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MUTEX_SOF_DSI0 | MT8183_MUTEX_EOF_DSI0,
+ [MUTEX_SOF_DPI0] = MT8183_MUTEX_SOF_DPI0 | MT8183_MUTEX_EOF_DPI0,
+};
+
+static const unsigned int mt8186_mutex_sof[MUTEX_SOF_DSI3 + 1] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MT8186_MUTEX_SOF_DSI0 | MT8186_MUTEX_EOF_DSI0,
+ [MUTEX_SOF_DPI0] = MT8186_MUTEX_SOF_DPI0 | MT8186_MUTEX_EOF_DPI0,
+};
+
+/*
+ * To support refresh mode(video mode), DISP_REG_MUTEX_SOF should
+ * select the EOF source and configure the EOF plus timing from the
+ * module that provides the timing signal.
+ * So that MUTEX can not only send a STREAM_DONE event to GCE
+ * but also detect the error at end of frame(EAEOF) when EOF signal
+ * arrives.
+ */
+static const unsigned int mt8195_mutex_sof[DDP_MUTEX_SOF_MAX] = {
+ [MUTEX_SOF_SINGLE_MODE] = MUTEX_SOF_SINGLE_MODE,
+ [MUTEX_SOF_DSI0] = MT8195_MUTEX_SOF_DSI0 | MT8195_MUTEX_EOF_DSI0,
+ [MUTEX_SOF_DSI1] = MT8195_MUTEX_SOF_DSI1 | MT8195_MUTEX_EOF_DSI1,
+ [MUTEX_SOF_DPI0] = MT8195_MUTEX_SOF_DPI0 | MT8195_MUTEX_EOF_DPI0,
+ [MUTEX_SOF_DPI1] = MT8195_MUTEX_SOF_DPI1 | MT8195_MUTEX_EOF_DPI1,
+ [MUTEX_SOF_DP_INTF0] =
+ MT8195_MUTEX_SOF_DP_INTF0 | MT8195_MUTEX_EOF_DP_INTF0,
+ [MUTEX_SOF_DP_INTF1] =
+ MT8195_MUTEX_SOF_DP_INTF1 | MT8195_MUTEX_EOF_DP_INTF1,
+};
+
+static const struct mtk_mutex_data mt2701_mutex_driver_data = {
+ .mutex_mod = mt2701_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt2712_mutex_driver_data = {
+ .mutex_mod = mt2712_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt6795_mutex_driver_data = {
+ .mutex_mod = mt8173_mutex_mod,
+ .mutex_sof = mt6795_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8167_mutex_driver_data = {
+ .mutex_mod = mt8167_mutex_mod,
+ .mutex_sof = mt8167_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+ .no_clk = true,
+};
+
+static const struct mtk_mutex_data mt8173_mutex_driver_data = {
+ .mutex_mod = mt8173_mutex_mod,
+ .mutex_sof = mt2712_mutex_sof,
+ .mutex_mod_reg = MT2701_MUTEX0_MOD0,
+ .mutex_sof_reg = MT2701_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8183_mutex_driver_data = {
+ .mutex_mod = mt8183_mutex_mod,
+ .mutex_sof = mt8183_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+ .mutex_table_mod = mt8183_mutex_table_mod,
+ .no_clk = true,
+};
+
+static const struct mtk_mutex_data mt8186_mdp_mutex_driver_data = {
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+ .mutex_table_mod = mt8186_mdp_mutex_table_mod,
+};
+
+static const struct mtk_mutex_data mt8186_mutex_driver_data = {
+ .mutex_mod = mt8186_mutex_mod,
+ .mutex_sof = mt8186_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8192_mutex_driver_data = {
+ .mutex_mod = mt8192_mutex_mod,
+ .mutex_sof = mt8183_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8195_mutex_driver_data = {
+ .mutex_mod = mt8195_mutex_mod,
+ .mutex_sof = mt8195_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+};
+
+static const struct mtk_mutex_data mt8365_mutex_driver_data = {
+ .mutex_mod = mt8365_mutex_mod,
+ .mutex_sof = mt8183_mutex_sof,
+ .mutex_mod_reg = MT8183_MUTEX0_MOD0,
+ .mutex_sof_reg = MT8183_MUTEX0_SOF0,
+ .no_clk = true,
+};
+
+struct mtk_mutex *mtk_mutex_get(struct device *dev)
+{
+ struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < 10; i++)
+ if (!mtx->mutex[i].claimed) {
+ mtx->mutex[i].claimed = true;
+ return &mtx->mutex[i];
+ }
+
+ return ERR_PTR(-EBUSY);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_get);
+
+void mtk_mutex_put(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ mutex->claimed = false;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_put);
+
+int mtk_mutex_prepare(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ return clk_prepare_enable(mtx->clk);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_prepare);
+
+void mtk_mutex_unprepare(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ clk_disable_unprepare(mtx->clk);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_unprepare);
+
+void mtk_mutex_add_comp(struct mtk_mutex *mutex,
+ enum mtk_ddp_comp_id id)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ unsigned int reg;
+ unsigned int sof_id;
+ unsigned int offset;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ switch (id) {
+ case DDP_COMPONENT_DSI0:
+ sof_id = MUTEX_SOF_DSI0;
+ break;
+ case DDP_COMPONENT_DSI1:
+ sof_id = MUTEX_SOF_DSI0;
+ break;
+ case DDP_COMPONENT_DSI2:
+ sof_id = MUTEX_SOF_DSI2;
+ break;
+ case DDP_COMPONENT_DSI3:
+ sof_id = MUTEX_SOF_DSI3;
+ break;
+ case DDP_COMPONENT_DPI0:
+ sof_id = MUTEX_SOF_DPI0;
+ break;
+ case DDP_COMPONENT_DPI1:
+ sof_id = MUTEX_SOF_DPI1;
+ break;
+ case DDP_COMPONENT_DP_INTF0:
+ sof_id = MUTEX_SOF_DP_INTF0;
+ break;
+ default:
+ if (mtx->data->mutex_mod[id] < 32) {
+ offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+ mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg |= 1 << mtx->data->mutex_mod[id];
+ writel_relaxed(reg, mtx->regs + offset);
+ } else {
+ offset = DISP_REG_MUTEX_MOD2(mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg |= 1 << (mtx->data->mutex_mod[id] - 32);
+ writel_relaxed(reg, mtx->regs + offset);
+ }
+ return;
+ }
+
+ writel_relaxed(mtx->data->mutex_sof[sof_id],
+ mtx->regs +
+ DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_add_comp);
+
+void mtk_mutex_remove_comp(struct mtk_mutex *mutex,
+ enum mtk_ddp_comp_id id)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ unsigned int reg;
+ unsigned int offset;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ switch (id) {
+ case DDP_COMPONENT_DSI0:
+ case DDP_COMPONENT_DSI1:
+ case DDP_COMPONENT_DSI2:
+ case DDP_COMPONENT_DSI3:
+ case DDP_COMPONENT_DPI0:
+ case DDP_COMPONENT_DPI1:
+ case DDP_COMPONENT_DP_INTF0:
+ writel_relaxed(MUTEX_SOF_SINGLE_MODE,
+ mtx->regs +
+ DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg,
+ mutex->id));
+ break;
+ default:
+ if (mtx->data->mutex_mod[id] < 32) {
+ offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+ mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg &= ~(1 << mtx->data->mutex_mod[id]);
+ writel_relaxed(reg, mtx->regs + offset);
+ } else {
+ offset = DISP_REG_MUTEX_MOD2(mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+ reg &= ~(1 << (mtx->data->mutex_mod[id] - 32));
+ writel_relaxed(reg, mtx->regs + offset);
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_remove_comp);
+
+void mtk_mutex_enable(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_enable);
+
+int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ if (!mtx->cmdq_reg.size) {
+ dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set");
+ return -EINVAL;
+ }
+
+ cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys,
+ mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1);
+ return 0;
+#else
+ dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ");
+ return -ENODEV;
+#endif
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq);
+
+void mtk_mutex_disable(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ writel(0, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_disable);
+
+void mtk_mutex_acquire(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ u32 tmp;
+
+ writel(1, mtx->regs + DISP_REG_MUTEX_EN(mutex->id));
+ writel(1, mtx->regs + DISP_REG_MUTEX(mutex->id));
+ if (readl_poll_timeout_atomic(mtx->regs + DISP_REG_MUTEX(mutex->id),
+ tmp, tmp & INT_MUTEX, 1, 10000))
+ pr_err("could not acquire mutex %d\n", mutex->id);
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_acquire);
+
+void mtk_mutex_release(struct mtk_mutex *mutex)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ writel(0, mtx->regs + DISP_REG_MUTEX(mutex->id));
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_release);
+
+int mtk_mutex_write_mod(struct mtk_mutex *mutex,
+ enum mtk_mutex_mod_index idx, bool clear)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+ unsigned int reg;
+ unsigned int offset;
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ if (idx < MUTEX_MOD_IDX_MDP_RDMA0 ||
+ idx >= MUTEX_MOD_IDX_MAX) {
+ dev_err(mtx->dev, "Not supported MOD table index : %d", idx);
+ return -EINVAL;
+ }
+
+ offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg,
+ mutex->id);
+ reg = readl_relaxed(mtx->regs + offset);
+
+ if (clear)
+ reg &= ~BIT(mtx->data->mutex_table_mod[idx]);
+ else
+ reg |= BIT(mtx->data->mutex_table_mod[idx]);
+
+ writel_relaxed(reg, mtx->regs + offset);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_write_mod);
+
+int mtk_mutex_write_sof(struct mtk_mutex *mutex,
+ enum mtk_mutex_sof_index idx)
+{
+ struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx,
+ mutex[mutex->id]);
+
+ WARN_ON(&mtx->mutex[mutex->id] != mutex);
+
+ if (idx < MUTEX_SOF_IDX_SINGLE_MODE ||
+ idx >= MUTEX_SOF_IDX_MAX) {
+ dev_err(mtx->dev, "Not supported SOF index : %d", idx);
+ return -EINVAL;
+ }
+
+ writel_relaxed(idx, mtx->regs +
+ DISP_REG_MUTEX_SOF(mtx->data->mutex_sof_reg, mutex->id));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_mutex_write_sof);
+
+static int mtk_mutex_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_mutex_ctx *mtx;
+ struct resource *regs;
+ int i;
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ int ret;
+#endif
+
+ mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL);
+ if (!mtx)
+ return -ENOMEM;
+
+ for (i = 0; i < 10; i++)
+ mtx->mutex[i].id = i;
+
+ mtx->data = of_device_get_match_data(dev);
+
+ if (!mtx->data->no_clk) {
+ mtx->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(mtx->clk)) {
+ if (PTR_ERR(mtx->clk) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get clock\n");
+ return PTR_ERR(mtx->clk);
+ }
+ }
+
+ mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
+ if (IS_ERR(mtx->regs)) {
+ dev_err(dev, "Failed to map mutex registers\n");
+ return PTR_ERR(mtx->regs);
+ }
+ mtx->addr = regs->start;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg!\n");
+#endif
+
+ platform_set_drvdata(pdev, mtx);
+
+ return 0;
+}
+
+static int mtk_mutex_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id mutex_driver_dt_match[] = {
+ { .compatible = "mediatek,mt2701-disp-mutex",
+ .data = &mt2701_mutex_driver_data},
+ { .compatible = "mediatek,mt2712-disp-mutex",
+ .data = &mt2712_mutex_driver_data},
+ { .compatible = "mediatek,mt6795-disp-mutex",
+ .data = &mt6795_mutex_driver_data},
+ { .compatible = "mediatek,mt8167-disp-mutex",
+ .data = &mt8167_mutex_driver_data},
+ { .compatible = "mediatek,mt8173-disp-mutex",
+ .data = &mt8173_mutex_driver_data},
+ { .compatible = "mediatek,mt8183-disp-mutex",
+ .data = &mt8183_mutex_driver_data},
+ { .compatible = "mediatek,mt8186-disp-mutex",
+ .data = &mt8186_mutex_driver_data},
+ { .compatible = "mediatek,mt8186-mdp3-mutex",
+ .data = &mt8186_mdp_mutex_driver_data},
+ { .compatible = "mediatek,mt8192-disp-mutex",
+ .data = &mt8192_mutex_driver_data},
+ { .compatible = "mediatek,mt8195-disp-mutex",
+ .data = &mt8195_mutex_driver_data},
+ { .compatible = "mediatek,mt8365-disp-mutex",
+ .data = &mt8365_mutex_driver_data},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mutex_driver_dt_match);
+
+static struct platform_driver mtk_mutex_driver = {
+ .probe = mtk_mutex_probe,
+ .remove = mtk_mutex_remove,
+ .driver = {
+ .name = "mediatek-mutex",
+ .owner = THIS_MODULE,
+ .of_match_table = mutex_driver_dt_match,
+ },
+};
+
+builtin_platform_driver(mtk_mutex_driver);
diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c
new file mode 100644
index 000000000..474b272f9
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-pm-domains.c
@@ -0,0 +1,675 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Collabora Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/soc/mediatek/infracfg.h>
+
+#include "mt6795-pm-domains.h"
+#include "mt8167-pm-domains.h"
+#include "mt8173-pm-domains.h"
+#include "mt8183-pm-domains.h"
+#include "mt8186-pm-domains.h"
+#include "mt8192-pm-domains.h"
+#include "mt8195-pm-domains.h"
+
+#define MTK_POLL_DELAY_US 10
+#define MTK_POLL_TIMEOUT USEC_PER_SEC
+
+#define PWR_RST_B_BIT BIT(0)
+#define PWR_ISO_BIT BIT(1)
+#define PWR_ON_BIT BIT(2)
+#define PWR_ON_2ND_BIT BIT(3)
+#define PWR_CLK_DIS_BIT BIT(4)
+#define PWR_SRAM_CLKISO_BIT BIT(5)
+#define PWR_SRAM_ISOINT_B_BIT BIT(6)
+
+struct scpsys_domain {
+ struct generic_pm_domain genpd;
+ const struct scpsys_domain_data *data;
+ struct scpsys *scpsys;
+ int num_clks;
+ struct clk_bulk_data *clks;
+ int num_subsys_clks;
+ struct clk_bulk_data *subsys_clks;
+ struct regmap *infracfg;
+ struct regmap *smi;
+ struct regulator *supply;
+};
+
+struct scpsys {
+ struct device *dev;
+ struct regmap *base;
+ const struct scpsys_soc_data *soc_data;
+ struct genpd_onecell_data pd_data;
+ struct generic_pm_domain *domains[];
+};
+
+#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
+
+static bool scpsys_domain_is_on(struct scpsys_domain *pd)
+{
+ struct scpsys *scpsys = pd->scpsys;
+ u32 status, status2;
+
+ regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
+ status &= pd->data->sta_mask;
+
+ regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2);
+ status2 &= pd->data->sta_mask;
+
+ /* A domain is on when both status bits are set. */
+ return status && status2;
+}
+
+static int scpsys_sram_enable(struct scpsys_domain *pd)
+{
+ u32 pdn_ack = pd->data->sram_pdn_ack_bits;
+ struct scpsys *scpsys = pd->scpsys;
+ unsigned int tmp;
+ int ret;
+
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
+
+ /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+ ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
+ (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
+ udelay(1);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
+ }
+
+ return 0;
+}
+
+static int scpsys_sram_disable(struct scpsys_domain *pd)
+{
+ u32 pdn_ack = pd->data->sram_pdn_ack_bits;
+ struct scpsys *scpsys = pd->scpsys;
+ unsigned int tmp;
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
+ udelay(1);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
+ }
+
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
+
+ /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+ return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
+ (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US,
+ MTK_POLL_TIMEOUT);
+}
+
+static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap)
+{
+ int i, ret;
+
+ for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) {
+ u32 val, mask = bpd[i].bus_prot_mask;
+
+ if (!mask)
+ break;
+
+ if (bpd[i].bus_prot_reg_update)
+ regmap_set_bits(regmap, bpd[i].bus_prot_set, mask);
+ else
+ regmap_write(regmap, bpd[i].bus_prot_set, mask);
+
+ ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
+ val, (val & mask) == mask,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
+{
+ int ret;
+
+ ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg);
+ if (ret)
+ return ret;
+
+ return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi);
+}
+
+static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd,
+ struct regmap *regmap)
+{
+ int i, ret;
+
+ for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) {
+ u32 val, mask = bpd[i].bus_prot_mask;
+
+ if (!mask)
+ continue;
+
+ if (bpd[i].bus_prot_reg_update)
+ regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask);
+ else
+ regmap_write(regmap, bpd[i].bus_prot_clr, mask);
+
+ if (bpd[i].ignore_clr_ack)
+ continue;
+
+ ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
+ val, !(val & mask),
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
+{
+ int ret;
+
+ ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi);
+ if (ret)
+ return ret;
+
+ return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg);
+}
+
+static int scpsys_regulator_enable(struct regulator *supply)
+{
+ return supply ? regulator_enable(supply) : 0;
+}
+
+static int scpsys_regulator_disable(struct regulator *supply)
+{
+ return supply ? regulator_disable(supply) : 0;
+}
+
+static int scpsys_power_on(struct generic_pm_domain *genpd)
+{
+ struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
+ struct scpsys *scpsys = pd->scpsys;
+ bool tmp;
+ int ret;
+
+ ret = scpsys_regulator_enable(pd->supply);
+ if (ret)
+ return ret;
+
+ ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
+ if (ret)
+ goto err_reg;
+
+ /* subsys power on */
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
+
+ /* wait until PWR_ACK = 1 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US,
+ MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ goto err_pwr_ack;
+
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+
+ ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
+ if (ret)
+ goto err_pwr_ack;
+
+ ret = scpsys_sram_enable(pd);
+ if (ret < 0)
+ goto err_disable_subsys_clks;
+
+ ret = scpsys_bus_protect_disable(pd);
+ if (ret < 0)
+ goto err_disable_sram;
+
+ return 0;
+
+err_disable_sram:
+ scpsys_sram_disable(pd);
+err_disable_subsys_clks:
+ clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+err_pwr_ack:
+ clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+err_reg:
+ scpsys_regulator_disable(pd->supply);
+ return ret;
+}
+
+static int scpsys_power_off(struct generic_pm_domain *genpd)
+{
+ struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
+ struct scpsys *scpsys = pd->scpsys;
+ bool tmp;
+ int ret;
+
+ ret = scpsys_bus_protect_enable(pd);
+ if (ret < 0)
+ return ret;
+
+ ret = scpsys_sram_disable(pd);
+ if (ret < 0)
+ return ret;
+
+ clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+
+ /* subsys power off */
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
+
+ /* wait until PWR_ACK = 0 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
+ MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+
+ clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+
+ scpsys_regulator_disable(pd->supply);
+
+ return 0;
+}
+
+static struct
+generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
+{
+ const struct scpsys_domain_data *domain_data;
+ struct scpsys_domain *pd;
+ struct device_node *root_node = scpsys->dev->of_node;
+ struct device_node *smi_node;
+ struct property *prop;
+ const char *clk_name;
+ int i, ret, num_clks;
+ struct clk *clk;
+ int clk_ind = 0;
+ u32 id;
+
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret) {
+ dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n",
+ node, ret);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (id >= scpsys->soc_data->num_domains) {
+ dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ domain_data = &scpsys->soc_data->domains_data[id];
+ if (domain_data->sta_mask == 0) {
+ dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ pd->data = domain_data;
+ pd->scpsys = scpsys;
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
+ /*
+ * Find regulator in current power domain node.
+ * devm_regulator_get() finds regulator in a node and its child
+ * node, so set of_node to current power domain node then change
+ * back to original node after regulator is found for current
+ * power domain node.
+ */
+ scpsys->dev->of_node = node;
+ pd->supply = devm_regulator_get(scpsys->dev, "domain");
+ scpsys->dev->of_node = root_node;
+ if (IS_ERR(pd->supply)) {
+ dev_err_probe(scpsys->dev, PTR_ERR(pd->supply),
+ "%pOF: failed to get power supply.\n",
+ node);
+ return ERR_CAST(pd->supply);
+ }
+ }
+
+ pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg");
+ if (IS_ERR(pd->infracfg))
+ return ERR_CAST(pd->infracfg);
+
+ smi_node = of_parse_phandle(node, "mediatek,smi", 0);
+ if (smi_node) {
+ pd->smi = device_node_to_regmap(smi_node);
+ of_node_put(smi_node);
+ if (IS_ERR(pd->smi))
+ return ERR_CAST(pd->smi);
+ }
+
+ num_clks = of_clk_get_parent_count(node);
+ if (num_clks > 0) {
+ /* Calculate number of subsys_clks */
+ of_property_for_each_string(node, "clock-names", prop, clk_name) {
+ char *subsys;
+
+ subsys = strchr(clk_name, '-');
+ if (subsys)
+ pd->num_subsys_clks++;
+ else
+ pd->num_clks++;
+ }
+
+ pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL);
+ if (!pd->clks)
+ return ERR_PTR(-ENOMEM);
+
+ pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
+ sizeof(*pd->subsys_clks), GFP_KERNEL);
+ if (!pd->subsys_clks)
+ return ERR_PTR(-ENOMEM);
+
+ }
+
+ for (i = 0; i < pd->num_clks; i++) {
+ clk = of_clk_get(node, i);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err_probe(scpsys->dev, ret,
+ "%pOF: failed to get clk at index %d\n", node, i);
+ goto err_put_clocks;
+ }
+
+ pd->clks[clk_ind++].clk = clk;
+ }
+
+ for (i = 0; i < pd->num_subsys_clks; i++) {
+ clk = of_clk_get(node, i + clk_ind);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err_probe(scpsys->dev, ret,
+ "%pOF: failed to get clk at index %d\n", node,
+ i + clk_ind);
+ goto err_put_subsys_clocks;
+ }
+
+ pd->subsys_clks[i].clk = clk;
+ }
+
+ /*
+ * Initially turn on all domains to make the domains usable
+ * with !CONFIG_PM and to get the hardware in sync with the
+ * software. The unused domains will be switched off during
+ * late_init time.
+ */
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
+ if (scpsys_domain_is_on(pd))
+ dev_warn(scpsys->dev,
+ "%pOF: A default off power domain has been ON\n", node);
+ } else {
+ ret = scpsys_power_on(&pd->genpd);
+ if (ret < 0) {
+ dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
+ goto err_put_subsys_clocks;
+ }
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
+ pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
+ }
+
+ if (scpsys->domains[id]) {
+ ret = -EINVAL;
+ dev_err(scpsys->dev,
+ "power domain with id %d already exists, check your device-tree\n", id);
+ goto err_put_subsys_clocks;
+ }
+
+ if (!pd->data->name)
+ pd->genpd.name = node->name;
+ else
+ pd->genpd.name = pd->data->name;
+
+ pd->genpd.power_off = scpsys_power_off;
+ pd->genpd.power_on = scpsys_power_on;
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
+ pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+ if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
+ pm_genpd_init(&pd->genpd, NULL, true);
+ else
+ pm_genpd_init(&pd->genpd, NULL, false);
+
+ scpsys->domains[id] = &pd->genpd;
+
+ return scpsys->pd_data.domains[id];
+
+err_put_subsys_clocks:
+ clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+err_put_clocks:
+ clk_bulk_put(pd->num_clks, pd->clks);
+ return ERR_PTR(ret);
+}
+
+static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent)
+{
+ struct generic_pm_domain *child_pd, *parent_pd;
+ struct device_node *child;
+ int ret;
+
+ for_each_child_of_node(parent, child) {
+ u32 id;
+
+ ret = of_property_read_u32(parent, "reg", &id);
+ if (ret) {
+ dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child);
+ goto err_put_node;
+ }
+
+ if (!scpsys->pd_data.domains[id]) {
+ ret = -EINVAL;
+ dev_err(scpsys->dev, "power domain with id %d does not exist\n", id);
+ goto err_put_node;
+ }
+
+ parent_pd = scpsys->pd_data.domains[id];
+
+ child_pd = scpsys_add_one_domain(scpsys, child);
+ if (IS_ERR(child_pd)) {
+ ret = PTR_ERR(child_pd);
+ dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
+ child);
+ goto err_put_node;
+ }
+
+ ret = pm_genpd_add_subdomain(parent_pd, child_pd);
+ if (ret) {
+ dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n",
+ child_pd->name, parent_pd->name);
+ goto err_put_node;
+ } else {
+ dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name,
+ child_pd->name);
+ }
+
+ /* recursive call to add all subdomains */
+ ret = scpsys_add_subdomain(scpsys, child);
+ if (ret)
+ goto err_put_node;
+ }
+
+ return 0;
+
+err_put_node:
+ of_node_put(child);
+ return ret;
+}
+
+static void scpsys_remove_one_domain(struct scpsys_domain *pd)
+{
+ int ret;
+
+ if (scpsys_domain_is_on(pd))
+ scpsys_power_off(&pd->genpd);
+
+ /*
+ * We're in the error cleanup already, so we only complain,
+ * but won't emit another error on top of the original one.
+ */
+ ret = pm_genpd_remove(&pd->genpd);
+ if (ret < 0)
+ dev_err(pd->scpsys->dev,
+ "failed to remove domain '%s' : %d - state may be inconsistent\n",
+ pd->genpd.name, ret);
+
+ clk_bulk_put(pd->num_clks, pd->clks);
+ clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+}
+
+static void scpsys_domain_cleanup(struct scpsys *scpsys)
+{
+ struct generic_pm_domain *genpd;
+ struct scpsys_domain *pd;
+ int i;
+
+ for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
+ genpd = scpsys->pd_data.domains[i];
+ if (genpd) {
+ pd = to_scpsys_domain(genpd);
+ scpsys_remove_one_domain(pd);
+ }
+ }
+}
+
+static const struct of_device_id scpsys_of_match[] = {
+ {
+ .compatible = "mediatek,mt6795-power-controller",
+ .data = &mt6795_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8167-power-controller",
+ .data = &mt8167_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8173-power-controller",
+ .data = &mt8173_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8183-power-controller",
+ .data = &mt8183_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8186-power-controller",
+ .data = &mt8186_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8192-power-controller",
+ .data = &mt8192_scpsys_data,
+ },
+ {
+ .compatible = "mediatek,mt8195-power-controller",
+ .data = &mt8195_scpsys_data,
+ },
+ { }
+};
+
+static int scpsys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct scpsys_soc_data *soc;
+ struct device_node *node;
+ struct device *parent;
+ struct scpsys *scpsys;
+ int ret;
+
+ soc = of_device_get_match_data(&pdev->dev);
+ if (!soc) {
+ dev_err(&pdev->dev, "no power controller data\n");
+ return -EINVAL;
+ }
+
+ scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL);
+ if (!scpsys)
+ return -ENOMEM;
+
+ scpsys->dev = dev;
+ scpsys->soc_data = soc;
+
+ scpsys->pd_data.domains = scpsys->domains;
+ scpsys->pd_data.num_domains = soc->num_domains;
+
+ parent = dev->parent;
+ if (!parent) {
+ dev_err(dev, "no parent for syscon devices\n");
+ return -ENODEV;
+ }
+
+ scpsys->base = syscon_node_to_regmap(parent->of_node);
+ if (IS_ERR(scpsys->base)) {
+ dev_err(dev, "no regmap available\n");
+ return PTR_ERR(scpsys->base);
+ }
+
+ ret = -ENODEV;
+ for_each_available_child_of_node(np, node) {
+ struct generic_pm_domain *domain;
+
+ domain = scpsys_add_one_domain(scpsys, node);
+ if (IS_ERR(domain)) {
+ ret = PTR_ERR(domain);
+ of_node_put(node);
+ goto err_cleanup_domains;
+ }
+
+ ret = scpsys_add_subdomain(scpsys, node);
+ if (ret) {
+ of_node_put(node);
+ goto err_cleanup_domains;
+ }
+ }
+
+ if (ret) {
+ dev_dbg(dev, "no power domains present\n");
+ return ret;
+ }
+
+ ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
+ if (ret) {
+ dev_err(dev, "failed to add provider: %d\n", ret);
+ goto err_cleanup_domains;
+ }
+
+ return 0;
+
+err_cleanup_domains:
+ scpsys_domain_cleanup(scpsys);
+ return ret;
+}
+
+static struct platform_driver scpsys_pm_domain_driver = {
+ .probe = scpsys_probe,
+ .driver = {
+ .name = "mtk-power-controller",
+ .suppress_bind_attrs = true,
+ .of_match_table = scpsys_of_match,
+ },
+};
+builtin_platform_driver(scpsys_pm_domain_driver);
diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h
new file mode 100644
index 000000000..7d3c0c363
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-pm-domains.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+
+#define MTK_SCPD_ACTIVE_WAKEUP BIT(0)
+#define MTK_SCPD_FWAIT_SRAM BIT(1)
+#define MTK_SCPD_SRAM_ISO BIT(2)
+#define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3)
+#define MTK_SCPD_DOMAIN_SUPPLY BIT(4)
+/* can't set MTK_SCPD_KEEP_DEFAULT_OFF at the same time */
+#define MTK_SCPD_ALWAYS_ON BIT(5)
+#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
+
+#define SPM_VDE_PWR_CON 0x0210
+#define SPM_MFG_PWR_CON 0x0214
+#define SPM_VEN_PWR_CON 0x0230
+#define SPM_ISP_PWR_CON 0x0238
+#define SPM_DIS_PWR_CON 0x023c
+#define SPM_CONN_PWR_CON 0x0280
+#define SPM_VEN2_PWR_CON 0x0298
+#define SPM_AUDIO_PWR_CON 0x029c
+#define SPM_MFG_2D_PWR_CON 0x02c0
+#define SPM_MFG_ASYNC_PWR_CON 0x02c4
+#define SPM_USB_PWR_CON 0x02cc
+
+#define SPM_PWR_STATUS 0x060c
+#define SPM_PWR_STATUS_2ND 0x0610
+
+#define PWR_STATUS_CONN BIT(1)
+#define PWR_STATUS_DISP BIT(3)
+#define PWR_STATUS_MFG BIT(4)
+#define PWR_STATUS_ISP BIT(5)
+#define PWR_STATUS_VDEC BIT(7)
+#define PWR_STATUS_VENC_LT BIT(20)
+#define PWR_STATUS_VENC BIT(21)
+#define PWR_STATUS_MFG_2D BIT(22)
+#define PWR_STATUS_MFG_ASYNC BIT(23)
+#define PWR_STATUS_AUDIO BIT(24)
+#define PWR_STATUS_USB BIT(25)
+
+#define SPM_MAX_BUS_PROT_DATA 6
+
+#define _BUS_PROT(_mask, _set, _clr, _sta, _update, _ignore) { \
+ .bus_prot_mask = (_mask), \
+ .bus_prot_set = _set, \
+ .bus_prot_clr = _clr, \
+ .bus_prot_sta = _sta, \
+ .bus_prot_reg_update = _update, \
+ .ignore_clr_ack = _ignore, \
+ }
+
+#define BUS_PROT_WR(_mask, _set, _clr, _sta) \
+ _BUS_PROT(_mask, _set, _clr, _sta, false, false)
+
+#define BUS_PROT_WR_IGN(_mask, _set, _clr, _sta) \
+ _BUS_PROT(_mask, _set, _clr, _sta, false, true)
+
+#define BUS_PROT_UPDATE(_mask, _set, _clr, _sta) \
+ _BUS_PROT(_mask, _set, _clr, _sta, true, false)
+
+#define BUS_PROT_UPDATE_TOPAXI(_mask) \
+ BUS_PROT_UPDATE(_mask, \
+ INFRA_TOPAXI_PROTECTEN, \
+ INFRA_TOPAXI_PROTECTEN, \
+ INFRA_TOPAXI_PROTECTSTA1)
+
+struct scpsys_bus_prot_data {
+ u32 bus_prot_mask;
+ u32 bus_prot_set;
+ u32 bus_prot_clr;
+ u32 bus_prot_sta;
+ bool bus_prot_reg_update;
+ bool ignore_clr_ack;
+};
+
+/**
+ * struct scpsys_domain_data - scp domain data for power on/off flow
+ * @name: The name of the power domain.
+ * @sta_mask: The mask for power on/off status bit.
+ * @ctl_offs: The offset for main power control register.
+ * @sram_pdn_bits: The mask for sram power control bits.
+ * @sram_pdn_ack_bits: The mask for sram power control acked bits.
+ * @caps: The flag for active wake-up action.
+ * @bp_infracfg: bus protection for infracfg subsystem
+ * @bp_smi: bus protection for smi subsystem
+ */
+struct scpsys_domain_data {
+ const char *name;
+ u32 sta_mask;
+ int ctl_offs;
+ u32 sram_pdn_bits;
+ u32 sram_pdn_ack_bits;
+ u8 caps;
+ const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA];
+ const struct scpsys_bus_prot_data bp_smi[SPM_MAX_BUS_PROT_DATA];
+ int pwr_sta_offs;
+ int pwr_sta2nd_offs;
+};
+
+struct scpsys_soc_data {
+ const struct scpsys_domain_data *domains_data;
+ int num_domains;
+};
+
+#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
new file mode 100644
index 000000000..eb82ae066
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -0,0 +1,2328 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu, MediaTek
+ */
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define PWRAP_POLL_DELAY_US 10
+#define PWRAP_POLL_TIMEOUT_US 10000
+
+#define PWRAP_MT8135_BRIDGE_IORD_ARB_EN 0x4
+#define PWRAP_MT8135_BRIDGE_WACS3_EN 0x10
+#define PWRAP_MT8135_BRIDGE_INIT_DONE3 0x14
+#define PWRAP_MT8135_BRIDGE_WACS4_EN 0x24
+#define PWRAP_MT8135_BRIDGE_INIT_DONE4 0x28
+#define PWRAP_MT8135_BRIDGE_INT_EN 0x38
+#define PWRAP_MT8135_BRIDGE_TIMER_EN 0x48
+#define PWRAP_MT8135_BRIDGE_WDT_UNIT 0x50
+#define PWRAP_MT8135_BRIDGE_WDT_SRC_EN 0x54
+
+/* macro for wrapper status */
+#define PWRAP_GET_WACS_RDATA(x) (((x) >> 0) & 0x0000ffff)
+#define PWRAP_GET_WACS_ARB_FSM(x) (((x) >> 1) & 0x00000007)
+#define PWRAP_GET_WACS_FSM(x) (((x) >> 16) & 0x00000007)
+#define PWRAP_GET_WACS_REQ(x) (((x) >> 19) & 0x00000001)
+#define PWRAP_STATE_SYNC_IDLE0 BIT(20)
+#define PWRAP_STATE_INIT_DONE0 BIT(21)
+#define PWRAP_STATE_INIT_DONE0_MT8186 BIT(22)
+#define PWRAP_STATE_INIT_DONE1 BIT(15)
+
+/* macro for WACS FSM */
+#define PWRAP_WACS_FSM_IDLE 0x00
+#define PWRAP_WACS_FSM_REQ 0x02
+#define PWRAP_WACS_FSM_WFDLE 0x04
+#define PWRAP_WACS_FSM_WFVLDCLR 0x06
+#define PWRAP_WACS_INIT_DONE 0x01
+#define PWRAP_WACS_WACS_SYNC_IDLE 0x01
+#define PWRAP_WACS_SYNC_BUSY 0x00
+
+/* macro for device wrapper default value */
+#define PWRAP_DEW_READ_TEST_VAL 0x5aa5
+#define PWRAP_DEW_WRITE_TEST_VAL 0xa55a
+
+/* macro for manual command */
+#define PWRAP_MAN_CMD_SPI_WRITE_NEW (1 << 14)
+#define PWRAP_MAN_CMD_SPI_WRITE (1 << 13)
+#define PWRAP_MAN_CMD_OP_CSH (0x0 << 8)
+#define PWRAP_MAN_CMD_OP_CSL (0x1 << 8)
+#define PWRAP_MAN_CMD_OP_CK (0x2 << 8)
+#define PWRAP_MAN_CMD_OP_OUTS (0x8 << 8)
+#define PWRAP_MAN_CMD_OP_OUTD (0x9 << 8)
+#define PWRAP_MAN_CMD_OP_OUTQ (0xa << 8)
+
+/* macro for Watch Dog Timer Source */
+#define PWRAP_WDT_SRC_EN_STAUPD_TRIG (1 << 25)
+#define PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE (1 << 20)
+#define PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE (1 << 6)
+#define PWRAP_WDT_SRC_MASK_ALL 0xffffffff
+#define PWRAP_WDT_SRC_MASK_NO_STAUPD ~(PWRAP_WDT_SRC_EN_STAUPD_TRIG | \
+ PWRAP_WDT_SRC_EN_HARB_STAUPD_DLE | \
+ PWRAP_WDT_SRC_EN_HARB_STAUPD_ALE)
+
+/* Group of bits used for shown slave capability */
+#define PWRAP_SLV_CAP_SPI BIT(0)
+#define PWRAP_SLV_CAP_DUALIO BIT(1)
+#define PWRAP_SLV_CAP_SECURITY BIT(2)
+#define HAS_CAP(_c, _x) (((_c) & (_x)) == (_x))
+
+/* Group of bits used for shown pwrap capability */
+#define PWRAP_CAP_BRIDGE BIT(0)
+#define PWRAP_CAP_RESET BIT(1)
+#define PWRAP_CAP_DCM BIT(2)
+#define PWRAP_CAP_INT1_EN BIT(3)
+#define PWRAP_CAP_WDT_SRC1 BIT(4)
+#define PWRAP_CAP_ARB BIT(5)
+#define PWRAP_CAP_ARB_MT8186 BIT(8)
+
+/* defines for slave device wrapper registers */
+enum dew_regs {
+ PWRAP_DEW_BASE,
+ PWRAP_DEW_DIO_EN,
+ PWRAP_DEW_READ_TEST,
+ PWRAP_DEW_WRITE_TEST,
+ PWRAP_DEW_CRC_EN,
+ PWRAP_DEW_CRC_VAL,
+ PWRAP_DEW_MON_GRP_SEL,
+ PWRAP_DEW_CIPHER_KEY_SEL,
+ PWRAP_DEW_CIPHER_IV_SEL,
+ PWRAP_DEW_CIPHER_RDY,
+ PWRAP_DEW_CIPHER_MODE,
+ PWRAP_DEW_CIPHER_SWRST,
+
+ /* MT6323 only regs */
+ PWRAP_DEW_CIPHER_EN,
+ PWRAP_DEW_RDDMY_NO,
+
+ /* MT6358 only regs */
+ PWRAP_SMT_CON1,
+ PWRAP_DRV_CON1,
+ PWRAP_FILTER_CON0,
+ PWRAP_GPIO_PULLEN0_CLR,
+ PWRAP_RG_SPI_CON0,
+ PWRAP_RG_SPI_RECORD0,
+ PWRAP_RG_SPI_CON2,
+ PWRAP_RG_SPI_CON3,
+ PWRAP_RG_SPI_CON4,
+ PWRAP_RG_SPI_CON5,
+ PWRAP_RG_SPI_CON6,
+ PWRAP_RG_SPI_CON7,
+ PWRAP_RG_SPI_CON8,
+ PWRAP_RG_SPI_CON13,
+ PWRAP_SPISLV_KEY,
+
+ /* MT6359 only regs */
+ PWRAP_DEW_CRC_SWRST,
+ PWRAP_DEW_RG_EN_RECORD,
+ PWRAP_DEW_RECORD_CMD0,
+ PWRAP_DEW_RECORD_CMD1,
+ PWRAP_DEW_RECORD_CMD2,
+ PWRAP_DEW_RECORD_CMD3,
+ PWRAP_DEW_RECORD_CMD4,
+ PWRAP_DEW_RECORD_CMD5,
+ PWRAP_DEW_RECORD_WDATA0,
+ PWRAP_DEW_RECORD_WDATA1,
+ PWRAP_DEW_RECORD_WDATA2,
+ PWRAP_DEW_RECORD_WDATA3,
+ PWRAP_DEW_RECORD_WDATA4,
+ PWRAP_DEW_RECORD_WDATA5,
+ PWRAP_DEW_RG_ADDR_TARGET,
+ PWRAP_DEW_RG_ADDR_MASK,
+ PWRAP_DEW_RG_WDATA_TARGET,
+ PWRAP_DEW_RG_WDATA_MASK,
+ PWRAP_DEW_RG_SPI_RECORD_CLR,
+ PWRAP_DEW_RG_CMD_ALERT_CLR,
+
+ /* MT6397 only regs */
+ PWRAP_DEW_EVENT_OUT_EN,
+ PWRAP_DEW_EVENT_SRC_EN,
+ PWRAP_DEW_EVENT_SRC,
+ PWRAP_DEW_EVENT_FLAG,
+ PWRAP_DEW_MON_FLAG_SEL,
+ PWRAP_DEW_EVENT_TEST,
+ PWRAP_DEW_CIPHER_LOAD,
+ PWRAP_DEW_CIPHER_START,
+};
+
+static const u32 mt6323_regs[] = {
+ [PWRAP_DEW_BASE] = 0x0000,
+ [PWRAP_DEW_DIO_EN] = 0x018a,
+ [PWRAP_DEW_READ_TEST] = 0x018c,
+ [PWRAP_DEW_WRITE_TEST] = 0x018e,
+ [PWRAP_DEW_CRC_EN] = 0x0192,
+ [PWRAP_DEW_CRC_VAL] = 0x0194,
+ [PWRAP_DEW_MON_GRP_SEL] = 0x0196,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0198,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x019a,
+ [PWRAP_DEW_CIPHER_EN] = 0x019c,
+ [PWRAP_DEW_CIPHER_RDY] = 0x019e,
+ [PWRAP_DEW_CIPHER_MODE] = 0x01a0,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x01a2,
+ [PWRAP_DEW_RDDMY_NO] = 0x01a4,
+};
+
+static const u32 mt6351_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x02F2,
+ [PWRAP_DEW_READ_TEST] = 0x02F4,
+ [PWRAP_DEW_WRITE_TEST] = 0x02F6,
+ [PWRAP_DEW_CRC_EN] = 0x02FA,
+ [PWRAP_DEW_CRC_VAL] = 0x02FC,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
+ [PWRAP_DEW_CIPHER_EN] = 0x0304,
+ [PWRAP_DEW_CIPHER_RDY] = 0x0306,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0308,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x030A,
+ [PWRAP_DEW_RDDMY_NO] = 0x030C,
+};
+
+static const u32 mt6357_regs[] = {
+ [PWRAP_DEW_DIO_EN] = 0x040A,
+ [PWRAP_DEW_READ_TEST] = 0x040C,
+ [PWRAP_DEW_WRITE_TEST] = 0x040E,
+ [PWRAP_DEW_CRC_EN] = 0x0412,
+ [PWRAP_DEW_CRC_VAL] = 0x0414,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x041A,
+ [PWRAP_DEW_CIPHER_EN] = 0x041C,
+ [PWRAP_DEW_CIPHER_RDY] = 0x041E,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0420,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x0422,
+ [PWRAP_DEW_RDDMY_NO] = 0x0424,
+};
+
+static const u32 mt6358_regs[] = {
+ [PWRAP_SMT_CON1] = 0x0030,
+ [PWRAP_DRV_CON1] = 0x0038,
+ [PWRAP_FILTER_CON0] = 0x0040,
+ [PWRAP_GPIO_PULLEN0_CLR] = 0x0098,
+ [PWRAP_RG_SPI_CON0] = 0x0408,
+ [PWRAP_RG_SPI_RECORD0] = 0x040a,
+ [PWRAP_DEW_DIO_EN] = 0x040c,
+ [PWRAP_DEW_READ_TEST] = 0x040e,
+ [PWRAP_DEW_WRITE_TEST] = 0x0410,
+ [PWRAP_DEW_CRC_EN] = 0x0414,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x041a,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x041c,
+ [PWRAP_DEW_CIPHER_EN] = 0x041e,
+ [PWRAP_DEW_CIPHER_RDY] = 0x0420,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0422,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x0424,
+ [PWRAP_RG_SPI_CON2] = 0x0432,
+ [PWRAP_RG_SPI_CON3] = 0x0434,
+ [PWRAP_RG_SPI_CON4] = 0x0436,
+ [PWRAP_RG_SPI_CON5] = 0x0438,
+ [PWRAP_RG_SPI_CON6] = 0x043a,
+ [PWRAP_RG_SPI_CON7] = 0x043c,
+ [PWRAP_RG_SPI_CON8] = 0x043e,
+ [PWRAP_RG_SPI_CON13] = 0x0448,
+ [PWRAP_SPISLV_KEY] = 0x044a,
+};
+
+static const u32 mt6359_regs[] = {
+ [PWRAP_DEW_RG_EN_RECORD] = 0x040a,
+ [PWRAP_DEW_DIO_EN] = 0x040c,
+ [PWRAP_DEW_READ_TEST] = 0x040e,
+ [PWRAP_DEW_WRITE_TEST] = 0x0410,
+ [PWRAP_DEW_CRC_SWRST] = 0x0412,
+ [PWRAP_DEW_CRC_EN] = 0x0414,
+ [PWRAP_DEW_CRC_VAL] = 0x0416,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0x041a,
+ [PWRAP_DEW_CIPHER_EN] = 0x041c,
+ [PWRAP_DEW_CIPHER_RDY] = 0x041e,
+ [PWRAP_DEW_CIPHER_MODE] = 0x0420,
+ [PWRAP_DEW_CIPHER_SWRST] = 0x0422,
+ [PWRAP_DEW_RDDMY_NO] = 0x0424,
+ [PWRAP_DEW_RECORD_CMD0] = 0x0428,
+ [PWRAP_DEW_RECORD_CMD1] = 0x042a,
+ [PWRAP_DEW_RECORD_CMD2] = 0x042c,
+ [PWRAP_DEW_RECORD_CMD3] = 0x042e,
+ [PWRAP_DEW_RECORD_CMD4] = 0x0430,
+ [PWRAP_DEW_RECORD_CMD5] = 0x0432,
+ [PWRAP_DEW_RECORD_WDATA0] = 0x0434,
+ [PWRAP_DEW_RECORD_WDATA1] = 0x0436,
+ [PWRAP_DEW_RECORD_WDATA2] = 0x0438,
+ [PWRAP_DEW_RECORD_WDATA3] = 0x043a,
+ [PWRAP_DEW_RECORD_WDATA4] = 0x043c,
+ [PWRAP_DEW_RECORD_WDATA5] = 0x043e,
+ [PWRAP_DEW_RG_ADDR_TARGET] = 0x0440,
+ [PWRAP_DEW_RG_ADDR_MASK] = 0x0442,
+ [PWRAP_DEW_RG_WDATA_TARGET] = 0x0444,
+ [PWRAP_DEW_RG_WDATA_MASK] = 0x0446,
+ [PWRAP_DEW_RG_SPI_RECORD_CLR] = 0x0448,
+ [PWRAP_DEW_RG_CMD_ALERT_CLR] = 0x0448,
+ [PWRAP_SPISLV_KEY] = 0x044a,
+};
+
+static const u32 mt6397_regs[] = {
+ [PWRAP_DEW_BASE] = 0xbc00,
+ [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00,
+ [PWRAP_DEW_DIO_EN] = 0xbc02,
+ [PWRAP_DEW_EVENT_SRC_EN] = 0xbc04,
+ [PWRAP_DEW_EVENT_SRC] = 0xbc06,
+ [PWRAP_DEW_EVENT_FLAG] = 0xbc08,
+ [PWRAP_DEW_READ_TEST] = 0xbc0a,
+ [PWRAP_DEW_WRITE_TEST] = 0xbc0c,
+ [PWRAP_DEW_CRC_EN] = 0xbc0e,
+ [PWRAP_DEW_CRC_VAL] = 0xbc10,
+ [PWRAP_DEW_MON_GRP_SEL] = 0xbc12,
+ [PWRAP_DEW_MON_FLAG_SEL] = 0xbc14,
+ [PWRAP_DEW_EVENT_TEST] = 0xbc16,
+ [PWRAP_DEW_CIPHER_KEY_SEL] = 0xbc18,
+ [PWRAP_DEW_CIPHER_IV_SEL] = 0xbc1a,
+ [PWRAP_DEW_CIPHER_LOAD] = 0xbc1c,
+ [PWRAP_DEW_CIPHER_START] = 0xbc1e,
+ [PWRAP_DEW_CIPHER_RDY] = 0xbc20,
+ [PWRAP_DEW_CIPHER_MODE] = 0xbc22,
+ [PWRAP_DEW_CIPHER_SWRST] = 0xbc24,
+};
+
+enum pwrap_regs {
+ PWRAP_MUX_SEL,
+ PWRAP_WRAP_EN,
+ PWRAP_DIO_EN,
+ PWRAP_SIDLY,
+ PWRAP_CSHEXT_WRITE,
+ PWRAP_CSHEXT_READ,
+ PWRAP_CSLEXT_START,
+ PWRAP_CSLEXT_END,
+ PWRAP_STAUPD_PRD,
+ PWRAP_STAUPD_GRPEN,
+ PWRAP_STAUPD_MAN_TRIG,
+ PWRAP_STAUPD_STA,
+ PWRAP_WRAP_STA,
+ PWRAP_HARB_INIT,
+ PWRAP_HARB_HPRIO,
+ PWRAP_HIPRIO_ARB_EN,
+ PWRAP_HARB_STA0,
+ PWRAP_HARB_STA1,
+ PWRAP_MAN_EN,
+ PWRAP_MAN_CMD,
+ PWRAP_MAN_RDATA,
+ PWRAP_MAN_VLDCLR,
+ PWRAP_WACS0_EN,
+ PWRAP_INIT_DONE0,
+ PWRAP_WACS0_CMD,
+ PWRAP_WACS0_RDATA,
+ PWRAP_WACS0_VLDCLR,
+ PWRAP_WACS1_EN,
+ PWRAP_INIT_DONE1,
+ PWRAP_WACS1_CMD,
+ PWRAP_WACS1_RDATA,
+ PWRAP_WACS1_VLDCLR,
+ PWRAP_WACS2_EN,
+ PWRAP_INIT_DONE2,
+ PWRAP_WACS2_CMD,
+ PWRAP_WACS2_RDATA,
+ PWRAP_WACS2_VLDCLR,
+ PWRAP_INT_EN,
+ PWRAP_INT_FLG_RAW,
+ PWRAP_INT_FLG,
+ PWRAP_INT_CLR,
+ PWRAP_SIG_ADR,
+ PWRAP_SIG_MODE,
+ PWRAP_SIG_VALUE,
+ PWRAP_SIG_ERRVAL,
+ PWRAP_CRC_EN,
+ PWRAP_TIMER_EN,
+ PWRAP_TIMER_STA,
+ PWRAP_WDT_UNIT,
+ PWRAP_WDT_SRC_EN,
+ PWRAP_WDT_FLG,
+ PWRAP_DEBUG_INT_SEL,
+ PWRAP_CIPHER_KEY_SEL,
+ PWRAP_CIPHER_IV_SEL,
+ PWRAP_CIPHER_RDY,
+ PWRAP_CIPHER_MODE,
+ PWRAP_CIPHER_SWRST,
+ PWRAP_DCM_EN,
+ PWRAP_DCM_DBC_PRD,
+ PWRAP_EINT_STA0_ADR,
+ PWRAP_EINT_STA1_ADR,
+ PWRAP_SWINF_2_WDATA_31_0,
+ PWRAP_SWINF_2_RDATA_31_0,
+
+ /* MT2701 only regs */
+ PWRAP_ADC_CMD_ADDR,
+ PWRAP_PWRAP_ADC_CMD,
+ PWRAP_ADC_RDY_ADDR,
+ PWRAP_ADC_RDATA_ADDR1,
+ PWRAP_ADC_RDATA_ADDR2,
+
+ /* MT7622 only regs */
+ PWRAP_STA,
+ PWRAP_CLR,
+ PWRAP_DVFS_ADR8,
+ PWRAP_DVFS_WDATA8,
+ PWRAP_DVFS_ADR9,
+ PWRAP_DVFS_WDATA9,
+ PWRAP_DVFS_ADR10,
+ PWRAP_DVFS_WDATA10,
+ PWRAP_DVFS_ADR11,
+ PWRAP_DVFS_WDATA11,
+ PWRAP_DVFS_ADR12,
+ PWRAP_DVFS_WDATA12,
+ PWRAP_DVFS_ADR13,
+ PWRAP_DVFS_WDATA13,
+ PWRAP_DVFS_ADR14,
+ PWRAP_DVFS_WDATA14,
+ PWRAP_DVFS_ADR15,
+ PWRAP_DVFS_WDATA15,
+ PWRAP_EXT_CK,
+ PWRAP_ADC_RDATA_ADDR,
+ PWRAP_GPS_STA,
+ PWRAP_SW_RST,
+ PWRAP_DVFS_STEP_CTRL0,
+ PWRAP_DVFS_STEP_CTRL1,
+ PWRAP_DVFS_STEP_CTRL2,
+ PWRAP_SPI2_CTRL,
+
+ /* MT8135 only regs */
+ PWRAP_CSHEXT,
+ PWRAP_EVENT_IN_EN,
+ PWRAP_EVENT_DST_EN,
+ PWRAP_RRARB_INIT,
+ PWRAP_RRARB_EN,
+ PWRAP_RRARB_STA0,
+ PWRAP_RRARB_STA1,
+ PWRAP_EVENT_STA,
+ PWRAP_EVENT_STACLR,
+ PWRAP_CIPHER_LOAD,
+ PWRAP_CIPHER_START,
+
+ /* MT8173 only regs */
+ PWRAP_RDDMY,
+ PWRAP_SI_CK_CON,
+ PWRAP_DVFS_ADR0,
+ PWRAP_DVFS_WDATA0,
+ PWRAP_DVFS_ADR1,
+ PWRAP_DVFS_WDATA1,
+ PWRAP_DVFS_ADR2,
+ PWRAP_DVFS_WDATA2,
+ PWRAP_DVFS_ADR3,
+ PWRAP_DVFS_WDATA3,
+ PWRAP_DVFS_ADR4,
+ PWRAP_DVFS_WDATA4,
+ PWRAP_DVFS_ADR5,
+ PWRAP_DVFS_WDATA5,
+ PWRAP_DVFS_ADR6,
+ PWRAP_DVFS_WDATA6,
+ PWRAP_DVFS_ADR7,
+ PWRAP_DVFS_WDATA7,
+ PWRAP_SPMINF_STA,
+ PWRAP_CIPHER_EN,
+
+ /* MT8183 only regs */
+ PWRAP_SI_SAMPLE_CTRL,
+ PWRAP_CSLEXT_WRITE,
+ PWRAP_CSLEXT_READ,
+ PWRAP_EXT_CK_WRITE,
+ PWRAP_STAUPD_CTRL,
+ PWRAP_WACS_P2P_EN,
+ PWRAP_INIT_DONE_P2P,
+ PWRAP_WACS_MD32_EN,
+ PWRAP_INIT_DONE_MD32,
+ PWRAP_INT1_EN,
+ PWRAP_INT1_FLG,
+ PWRAP_INT1_CLR,
+ PWRAP_WDT_SRC_EN_1,
+ PWRAP_INT_GPS_AUXADC_CMD_ADDR,
+ PWRAP_INT_GPS_AUXADC_CMD,
+ PWRAP_INT_GPS_AUXADC_RDATA_ADDR,
+ PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
+ PWRAP_GPSINF_0_STA,
+ PWRAP_GPSINF_1_STA,
+
+ /* MT8516 only regs */
+ PWRAP_OP_TYPE,
+ PWRAP_MSB_FIRST,
+};
+
+static int mt2701_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_RDDMY] = 0x18,
+ [PWRAP_SI_CK_CON] = 0x1c,
+ [PWRAP_CSHEXT_WRITE] = 0x20,
+ [PWRAP_CSHEXT_READ] = 0x24,
+ [PWRAP_CSLEXT_START] = 0x28,
+ [PWRAP_CSLEXT_END] = 0x2c,
+ [PWRAP_STAUPD_PRD] = 0x30,
+ [PWRAP_STAUPD_GRPEN] = 0x34,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x38,
+ [PWRAP_STAUPD_STA] = 0x3c,
+ [PWRAP_WRAP_STA] = 0x44,
+ [PWRAP_HARB_INIT] = 0x48,
+ [PWRAP_HARB_HPRIO] = 0x4c,
+ [PWRAP_HIPRIO_ARB_EN] = 0x50,
+ [PWRAP_HARB_STA0] = 0x54,
+ [PWRAP_HARB_STA1] = 0x58,
+ [PWRAP_MAN_EN] = 0x5c,
+ [PWRAP_MAN_CMD] = 0x60,
+ [PWRAP_MAN_RDATA] = 0x64,
+ [PWRAP_MAN_VLDCLR] = 0x68,
+ [PWRAP_WACS0_EN] = 0x6c,
+ [PWRAP_INIT_DONE0] = 0x70,
+ [PWRAP_WACS0_CMD] = 0x74,
+ [PWRAP_WACS0_RDATA] = 0x78,
+ [PWRAP_WACS0_VLDCLR] = 0x7c,
+ [PWRAP_WACS1_EN] = 0x80,
+ [PWRAP_INIT_DONE1] = 0x84,
+ [PWRAP_WACS1_CMD] = 0x88,
+ [PWRAP_WACS1_RDATA] = 0x8c,
+ [PWRAP_WACS1_VLDCLR] = 0x90,
+ [PWRAP_WACS2_EN] = 0x94,
+ [PWRAP_INIT_DONE2] = 0x98,
+ [PWRAP_WACS2_CMD] = 0x9c,
+ [PWRAP_WACS2_RDATA] = 0xa0,
+ [PWRAP_WACS2_VLDCLR] = 0xa4,
+ [PWRAP_INT_EN] = 0xa8,
+ [PWRAP_INT_FLG_RAW] = 0xac,
+ [PWRAP_INT_FLG] = 0xb0,
+ [PWRAP_INT_CLR] = 0xb4,
+ [PWRAP_SIG_ADR] = 0xb8,
+ [PWRAP_SIG_MODE] = 0xbc,
+ [PWRAP_SIG_VALUE] = 0xc0,
+ [PWRAP_SIG_ERRVAL] = 0xc4,
+ [PWRAP_CRC_EN] = 0xc8,
+ [PWRAP_TIMER_EN] = 0xcc,
+ [PWRAP_TIMER_STA] = 0xd0,
+ [PWRAP_WDT_UNIT] = 0xd4,
+ [PWRAP_WDT_SRC_EN] = 0xd8,
+ [PWRAP_WDT_FLG] = 0xdc,
+ [PWRAP_DEBUG_INT_SEL] = 0xe0,
+ [PWRAP_DVFS_ADR0] = 0xe4,
+ [PWRAP_DVFS_WDATA0] = 0xe8,
+ [PWRAP_DVFS_ADR1] = 0xec,
+ [PWRAP_DVFS_WDATA1] = 0xf0,
+ [PWRAP_DVFS_ADR2] = 0xf4,
+ [PWRAP_DVFS_WDATA2] = 0xf8,
+ [PWRAP_DVFS_ADR3] = 0xfc,
+ [PWRAP_DVFS_WDATA3] = 0x100,
+ [PWRAP_DVFS_ADR4] = 0x104,
+ [PWRAP_DVFS_WDATA4] = 0x108,
+ [PWRAP_DVFS_ADR5] = 0x10c,
+ [PWRAP_DVFS_WDATA5] = 0x110,
+ [PWRAP_DVFS_ADR6] = 0x114,
+ [PWRAP_DVFS_WDATA6] = 0x118,
+ [PWRAP_DVFS_ADR7] = 0x11c,
+ [PWRAP_DVFS_WDATA7] = 0x120,
+ [PWRAP_CIPHER_KEY_SEL] = 0x124,
+ [PWRAP_CIPHER_IV_SEL] = 0x128,
+ [PWRAP_CIPHER_EN] = 0x12c,
+ [PWRAP_CIPHER_RDY] = 0x130,
+ [PWRAP_CIPHER_MODE] = 0x134,
+ [PWRAP_CIPHER_SWRST] = 0x138,
+ [PWRAP_DCM_EN] = 0x13c,
+ [PWRAP_DCM_DBC_PRD] = 0x140,
+ [PWRAP_ADC_CMD_ADDR] = 0x144,
+ [PWRAP_PWRAP_ADC_CMD] = 0x148,
+ [PWRAP_ADC_RDY_ADDR] = 0x14c,
+ [PWRAP_ADC_RDATA_ADDR1] = 0x150,
+ [PWRAP_ADC_RDATA_ADDR2] = 0x154,
+};
+
+static int mt6765_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_RDDMY] = 0x20,
+ [PWRAP_CSHEXT_WRITE] = 0x24,
+ [PWRAP_CSHEXT_READ] = 0x28,
+ [PWRAP_CSLEXT_START] = 0x2C,
+ [PWRAP_CSLEXT_END] = 0x30,
+ [PWRAP_STAUPD_PRD] = 0x3C,
+ [PWRAP_HARB_HPRIO] = 0x68,
+ [PWRAP_HIPRIO_ARB_EN] = 0x6C,
+ [PWRAP_MAN_EN] = 0x7C,
+ [PWRAP_MAN_CMD] = 0x80,
+ [PWRAP_WACS0_EN] = 0x8C,
+ [PWRAP_WACS1_EN] = 0x94,
+ [PWRAP_WACS2_EN] = 0x9C,
+ [PWRAP_INIT_DONE2] = 0xA0,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
+ [PWRAP_INT_EN] = 0xB4,
+ [PWRAP_INT_FLG_RAW] = 0xB8,
+ [PWRAP_INT_FLG] = 0xBC,
+ [PWRAP_INT_CLR] = 0xC0,
+ [PWRAP_TIMER_EN] = 0xE8,
+ [PWRAP_WDT_UNIT] = 0xF0,
+ [PWRAP_WDT_SRC_EN] = 0xF4,
+ [PWRAP_DCM_EN] = 0x1DC,
+ [PWRAP_DCM_DBC_PRD] = 0x1E0,
+};
+
+static int mt6779_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_RDDMY] = 0x20,
+ [PWRAP_CSHEXT_WRITE] = 0x24,
+ [PWRAP_CSHEXT_READ] = 0x28,
+ [PWRAP_CSLEXT_WRITE] = 0x2C,
+ [PWRAP_CSLEXT_READ] = 0x30,
+ [PWRAP_EXT_CK_WRITE] = 0x34,
+ [PWRAP_STAUPD_CTRL] = 0x3C,
+ [PWRAP_STAUPD_GRPEN] = 0x40,
+ [PWRAP_EINT_STA0_ADR] = 0x44,
+ [PWRAP_HARB_HPRIO] = 0x68,
+ [PWRAP_HIPRIO_ARB_EN] = 0x6C,
+ [PWRAP_MAN_EN] = 0x7C,
+ [PWRAP_MAN_CMD] = 0x80,
+ [PWRAP_WACS0_EN] = 0x8C,
+ [PWRAP_INIT_DONE0] = 0x90,
+ [PWRAP_WACS1_EN] = 0x94,
+ [PWRAP_WACS2_EN] = 0x9C,
+ [PWRAP_INIT_DONE1] = 0x98,
+ [PWRAP_INIT_DONE2] = 0xA0,
+ [PWRAP_INT_EN] = 0xBC,
+ [PWRAP_INT_FLG_RAW] = 0xC0,
+ [PWRAP_INT_FLG] = 0xC4,
+ [PWRAP_INT_CLR] = 0xC8,
+ [PWRAP_INT1_EN] = 0xCC,
+ [PWRAP_INT1_FLG] = 0xD4,
+ [PWRAP_INT1_CLR] = 0xD8,
+ [PWRAP_TIMER_EN] = 0xF0,
+ [PWRAP_WDT_UNIT] = 0xF8,
+ [PWRAP_WDT_SRC_EN] = 0xFC,
+ [PWRAP_WDT_SRC_EN_1] = 0x100,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
+};
+
+static int mt6797_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xC,
+ [PWRAP_RDDMY] = 0x10,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1C,
+ [PWRAP_CSLEXT_START] = 0x20,
+ [PWRAP_CSLEXT_END] = 0x24,
+ [PWRAP_STAUPD_PRD] = 0x28,
+ [PWRAP_HARB_HPRIO] = 0x50,
+ [PWRAP_HIPRIO_ARB_EN] = 0x54,
+ [PWRAP_MAN_EN] = 0x60,
+ [PWRAP_MAN_CMD] = 0x64,
+ [PWRAP_WACS0_EN] = 0x70,
+ [PWRAP_WACS1_EN] = 0x84,
+ [PWRAP_WACS2_EN] = 0x98,
+ [PWRAP_INIT_DONE2] = 0x9C,
+ [PWRAP_WACS2_CMD] = 0xA0,
+ [PWRAP_WACS2_RDATA] = 0xA4,
+ [PWRAP_WACS2_VLDCLR] = 0xA8,
+ [PWRAP_INT_EN] = 0xC0,
+ [PWRAP_INT_FLG_RAW] = 0xC4,
+ [PWRAP_INT_FLG] = 0xC8,
+ [PWRAP_INT_CLR] = 0xCC,
+ [PWRAP_TIMER_EN] = 0xF4,
+ [PWRAP_WDT_UNIT] = 0xFC,
+ [PWRAP_WDT_SRC_EN] = 0x100,
+ [PWRAP_DCM_EN] = 0x1CC,
+ [PWRAP_DCM_DBC_PRD] = 0x1D4,
+};
+
+static int mt6873_regs[] = {
+ [PWRAP_INIT_DONE2] = 0x0,
+ [PWRAP_TIMER_EN] = 0x3E0,
+ [PWRAP_INT_EN] = 0x448,
+ [PWRAP_WACS2_CMD] = 0xC80,
+ [PWRAP_SWINF_2_WDATA_31_0] = 0xC84,
+ [PWRAP_SWINF_2_RDATA_31_0] = 0xC94,
+ [PWRAP_WACS2_VLDCLR] = 0xCA4,
+ [PWRAP_WACS2_RDATA] = 0xCA8,
+};
+
+static int mt7622_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xC,
+ [PWRAP_RDDMY] = 0x10,
+ [PWRAP_SI_CK_CON] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1C,
+ [PWRAP_CSLEXT_START] = 0x20,
+ [PWRAP_CSLEXT_END] = 0x24,
+ [PWRAP_STAUPD_PRD] = 0x28,
+ [PWRAP_STAUPD_GRPEN] = 0x2C,
+ [PWRAP_EINT_STA0_ADR] = 0x30,
+ [PWRAP_EINT_STA1_ADR] = 0x34,
+ [PWRAP_STA] = 0x38,
+ [PWRAP_CLR] = 0x3C,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x40,
+ [PWRAP_STAUPD_STA] = 0x44,
+ [PWRAP_WRAP_STA] = 0x48,
+ [PWRAP_HARB_INIT] = 0x4C,
+ [PWRAP_HARB_HPRIO] = 0x50,
+ [PWRAP_HIPRIO_ARB_EN] = 0x54,
+ [PWRAP_HARB_STA0] = 0x58,
+ [PWRAP_HARB_STA1] = 0x5C,
+ [PWRAP_MAN_EN] = 0x60,
+ [PWRAP_MAN_CMD] = 0x64,
+ [PWRAP_MAN_RDATA] = 0x68,
+ [PWRAP_MAN_VLDCLR] = 0x6C,
+ [PWRAP_WACS0_EN] = 0x70,
+ [PWRAP_INIT_DONE0] = 0x74,
+ [PWRAP_WACS0_CMD] = 0x78,
+ [PWRAP_WACS0_RDATA] = 0x7C,
+ [PWRAP_WACS0_VLDCLR] = 0x80,
+ [PWRAP_WACS1_EN] = 0x84,
+ [PWRAP_INIT_DONE1] = 0x88,
+ [PWRAP_WACS1_CMD] = 0x8C,
+ [PWRAP_WACS1_RDATA] = 0x90,
+ [PWRAP_WACS1_VLDCLR] = 0x94,
+ [PWRAP_WACS2_EN] = 0x98,
+ [PWRAP_INIT_DONE2] = 0x9C,
+ [PWRAP_WACS2_CMD] = 0xA0,
+ [PWRAP_WACS2_RDATA] = 0xA4,
+ [PWRAP_WACS2_VLDCLR] = 0xA8,
+ [PWRAP_INT_EN] = 0xAC,
+ [PWRAP_INT_FLG_RAW] = 0xB0,
+ [PWRAP_INT_FLG] = 0xB4,
+ [PWRAP_INT_CLR] = 0xB8,
+ [PWRAP_SIG_ADR] = 0xBC,
+ [PWRAP_SIG_MODE] = 0xC0,
+ [PWRAP_SIG_VALUE] = 0xC4,
+ [PWRAP_SIG_ERRVAL] = 0xC8,
+ [PWRAP_CRC_EN] = 0xCC,
+ [PWRAP_TIMER_EN] = 0xD0,
+ [PWRAP_TIMER_STA] = 0xD4,
+ [PWRAP_WDT_UNIT] = 0xD8,
+ [PWRAP_WDT_SRC_EN] = 0xDC,
+ [PWRAP_WDT_FLG] = 0xE0,
+ [PWRAP_DEBUG_INT_SEL] = 0xE4,
+ [PWRAP_DVFS_ADR0] = 0xE8,
+ [PWRAP_DVFS_WDATA0] = 0xEC,
+ [PWRAP_DVFS_ADR1] = 0xF0,
+ [PWRAP_DVFS_WDATA1] = 0xF4,
+ [PWRAP_DVFS_ADR2] = 0xF8,
+ [PWRAP_DVFS_WDATA2] = 0xFC,
+ [PWRAP_DVFS_ADR3] = 0x100,
+ [PWRAP_DVFS_WDATA3] = 0x104,
+ [PWRAP_DVFS_ADR4] = 0x108,
+ [PWRAP_DVFS_WDATA4] = 0x10C,
+ [PWRAP_DVFS_ADR5] = 0x110,
+ [PWRAP_DVFS_WDATA5] = 0x114,
+ [PWRAP_DVFS_ADR6] = 0x118,
+ [PWRAP_DVFS_WDATA6] = 0x11C,
+ [PWRAP_DVFS_ADR7] = 0x120,
+ [PWRAP_DVFS_WDATA7] = 0x124,
+ [PWRAP_DVFS_ADR8] = 0x128,
+ [PWRAP_DVFS_WDATA8] = 0x12C,
+ [PWRAP_DVFS_ADR9] = 0x130,
+ [PWRAP_DVFS_WDATA9] = 0x134,
+ [PWRAP_DVFS_ADR10] = 0x138,
+ [PWRAP_DVFS_WDATA10] = 0x13C,
+ [PWRAP_DVFS_ADR11] = 0x140,
+ [PWRAP_DVFS_WDATA11] = 0x144,
+ [PWRAP_DVFS_ADR12] = 0x148,
+ [PWRAP_DVFS_WDATA12] = 0x14C,
+ [PWRAP_DVFS_ADR13] = 0x150,
+ [PWRAP_DVFS_WDATA13] = 0x154,
+ [PWRAP_DVFS_ADR14] = 0x158,
+ [PWRAP_DVFS_WDATA14] = 0x15C,
+ [PWRAP_DVFS_ADR15] = 0x160,
+ [PWRAP_DVFS_WDATA15] = 0x164,
+ [PWRAP_SPMINF_STA] = 0x168,
+ [PWRAP_CIPHER_KEY_SEL] = 0x16C,
+ [PWRAP_CIPHER_IV_SEL] = 0x170,
+ [PWRAP_CIPHER_EN] = 0x174,
+ [PWRAP_CIPHER_RDY] = 0x178,
+ [PWRAP_CIPHER_MODE] = 0x17C,
+ [PWRAP_CIPHER_SWRST] = 0x180,
+ [PWRAP_DCM_EN] = 0x184,
+ [PWRAP_DCM_DBC_PRD] = 0x188,
+ [PWRAP_EXT_CK] = 0x18C,
+ [PWRAP_ADC_CMD_ADDR] = 0x190,
+ [PWRAP_PWRAP_ADC_CMD] = 0x194,
+ [PWRAP_ADC_RDATA_ADDR] = 0x198,
+ [PWRAP_GPS_STA] = 0x19C,
+ [PWRAP_SW_RST] = 0x1A0,
+ [PWRAP_DVFS_STEP_CTRL0] = 0x238,
+ [PWRAP_DVFS_STEP_CTRL1] = 0x23C,
+ [PWRAP_DVFS_STEP_CTRL2] = 0x240,
+ [PWRAP_SPI2_CTRL] = 0x244,
+};
+
+static int mt8135_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_CSHEXT] = 0x10,
+ [PWRAP_CSHEXT_WRITE] = 0x14,
+ [PWRAP_CSHEXT_READ] = 0x18,
+ [PWRAP_CSLEXT_START] = 0x1c,
+ [PWRAP_CSLEXT_END] = 0x20,
+ [PWRAP_STAUPD_PRD] = 0x24,
+ [PWRAP_STAUPD_GRPEN] = 0x28,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x2c,
+ [PWRAP_STAUPD_STA] = 0x30,
+ [PWRAP_EVENT_IN_EN] = 0x34,
+ [PWRAP_EVENT_DST_EN] = 0x38,
+ [PWRAP_WRAP_STA] = 0x3c,
+ [PWRAP_RRARB_INIT] = 0x40,
+ [PWRAP_RRARB_EN] = 0x44,
+ [PWRAP_RRARB_STA0] = 0x48,
+ [PWRAP_RRARB_STA1] = 0x4c,
+ [PWRAP_HARB_INIT] = 0x50,
+ [PWRAP_HARB_HPRIO] = 0x54,
+ [PWRAP_HIPRIO_ARB_EN] = 0x58,
+ [PWRAP_HARB_STA0] = 0x5c,
+ [PWRAP_HARB_STA1] = 0x60,
+ [PWRAP_MAN_EN] = 0x64,
+ [PWRAP_MAN_CMD] = 0x68,
+ [PWRAP_MAN_RDATA] = 0x6c,
+ [PWRAP_MAN_VLDCLR] = 0x70,
+ [PWRAP_WACS0_EN] = 0x74,
+ [PWRAP_INIT_DONE0] = 0x78,
+ [PWRAP_WACS0_CMD] = 0x7c,
+ [PWRAP_WACS0_RDATA] = 0x80,
+ [PWRAP_WACS0_VLDCLR] = 0x84,
+ [PWRAP_WACS1_EN] = 0x88,
+ [PWRAP_INIT_DONE1] = 0x8c,
+ [PWRAP_WACS1_CMD] = 0x90,
+ [PWRAP_WACS1_RDATA] = 0x94,
+ [PWRAP_WACS1_VLDCLR] = 0x98,
+ [PWRAP_WACS2_EN] = 0x9c,
+ [PWRAP_INIT_DONE2] = 0xa0,
+ [PWRAP_WACS2_CMD] = 0xa4,
+ [PWRAP_WACS2_RDATA] = 0xa8,
+ [PWRAP_WACS2_VLDCLR] = 0xac,
+ [PWRAP_INT_EN] = 0xb0,
+ [PWRAP_INT_FLG_RAW] = 0xb4,
+ [PWRAP_INT_FLG] = 0xb8,
+ [PWRAP_INT_CLR] = 0xbc,
+ [PWRAP_SIG_ADR] = 0xc0,
+ [PWRAP_SIG_MODE] = 0xc4,
+ [PWRAP_SIG_VALUE] = 0xc8,
+ [PWRAP_SIG_ERRVAL] = 0xcc,
+ [PWRAP_CRC_EN] = 0xd0,
+ [PWRAP_EVENT_STA] = 0xd4,
+ [PWRAP_EVENT_STACLR] = 0xd8,
+ [PWRAP_TIMER_EN] = 0xdc,
+ [PWRAP_TIMER_STA] = 0xe0,
+ [PWRAP_WDT_UNIT] = 0xe4,
+ [PWRAP_WDT_SRC_EN] = 0xe8,
+ [PWRAP_WDT_FLG] = 0xec,
+ [PWRAP_DEBUG_INT_SEL] = 0xf0,
+ [PWRAP_CIPHER_KEY_SEL] = 0x134,
+ [PWRAP_CIPHER_IV_SEL] = 0x138,
+ [PWRAP_CIPHER_LOAD] = 0x13c,
+ [PWRAP_CIPHER_START] = 0x140,
+ [PWRAP_CIPHER_RDY] = 0x144,
+ [PWRAP_CIPHER_MODE] = 0x148,
+ [PWRAP_CIPHER_SWRST] = 0x14c,
+ [PWRAP_DCM_EN] = 0x15c,
+ [PWRAP_DCM_DBC_PRD] = 0x160,
+};
+
+static int mt8173_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_RDDMY] = 0x10,
+ [PWRAP_SI_CK_CON] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1c,
+ [PWRAP_CSLEXT_START] = 0x20,
+ [PWRAP_CSLEXT_END] = 0x24,
+ [PWRAP_STAUPD_PRD] = 0x28,
+ [PWRAP_STAUPD_GRPEN] = 0x2c,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x40,
+ [PWRAP_STAUPD_STA] = 0x44,
+ [PWRAP_WRAP_STA] = 0x48,
+ [PWRAP_HARB_INIT] = 0x4c,
+ [PWRAP_HARB_HPRIO] = 0x50,
+ [PWRAP_HIPRIO_ARB_EN] = 0x54,
+ [PWRAP_HARB_STA0] = 0x58,
+ [PWRAP_HARB_STA1] = 0x5c,
+ [PWRAP_MAN_EN] = 0x60,
+ [PWRAP_MAN_CMD] = 0x64,
+ [PWRAP_MAN_RDATA] = 0x68,
+ [PWRAP_MAN_VLDCLR] = 0x6c,
+ [PWRAP_WACS0_EN] = 0x70,
+ [PWRAP_INIT_DONE0] = 0x74,
+ [PWRAP_WACS0_CMD] = 0x78,
+ [PWRAP_WACS0_RDATA] = 0x7c,
+ [PWRAP_WACS0_VLDCLR] = 0x80,
+ [PWRAP_WACS1_EN] = 0x84,
+ [PWRAP_INIT_DONE1] = 0x88,
+ [PWRAP_WACS1_CMD] = 0x8c,
+ [PWRAP_WACS1_RDATA] = 0x90,
+ [PWRAP_WACS1_VLDCLR] = 0x94,
+ [PWRAP_WACS2_EN] = 0x98,
+ [PWRAP_INIT_DONE2] = 0x9c,
+ [PWRAP_WACS2_CMD] = 0xa0,
+ [PWRAP_WACS2_RDATA] = 0xa4,
+ [PWRAP_WACS2_VLDCLR] = 0xa8,
+ [PWRAP_INT_EN] = 0xac,
+ [PWRAP_INT_FLG_RAW] = 0xb0,
+ [PWRAP_INT_FLG] = 0xb4,
+ [PWRAP_INT_CLR] = 0xb8,
+ [PWRAP_SIG_ADR] = 0xbc,
+ [PWRAP_SIG_MODE] = 0xc0,
+ [PWRAP_SIG_VALUE] = 0xc4,
+ [PWRAP_SIG_ERRVAL] = 0xc8,
+ [PWRAP_CRC_EN] = 0xcc,
+ [PWRAP_TIMER_EN] = 0xd0,
+ [PWRAP_TIMER_STA] = 0xd4,
+ [PWRAP_WDT_UNIT] = 0xd8,
+ [PWRAP_WDT_SRC_EN] = 0xdc,
+ [PWRAP_WDT_FLG] = 0xe0,
+ [PWRAP_DEBUG_INT_SEL] = 0xe4,
+ [PWRAP_DVFS_ADR0] = 0xe8,
+ [PWRAP_DVFS_WDATA0] = 0xec,
+ [PWRAP_DVFS_ADR1] = 0xf0,
+ [PWRAP_DVFS_WDATA1] = 0xf4,
+ [PWRAP_DVFS_ADR2] = 0xf8,
+ [PWRAP_DVFS_WDATA2] = 0xfc,
+ [PWRAP_DVFS_ADR3] = 0x100,
+ [PWRAP_DVFS_WDATA3] = 0x104,
+ [PWRAP_DVFS_ADR4] = 0x108,
+ [PWRAP_DVFS_WDATA4] = 0x10c,
+ [PWRAP_DVFS_ADR5] = 0x110,
+ [PWRAP_DVFS_WDATA5] = 0x114,
+ [PWRAP_DVFS_ADR6] = 0x118,
+ [PWRAP_DVFS_WDATA6] = 0x11c,
+ [PWRAP_DVFS_ADR7] = 0x120,
+ [PWRAP_DVFS_WDATA7] = 0x124,
+ [PWRAP_SPMINF_STA] = 0x128,
+ [PWRAP_CIPHER_KEY_SEL] = 0x12c,
+ [PWRAP_CIPHER_IV_SEL] = 0x130,
+ [PWRAP_CIPHER_EN] = 0x134,
+ [PWRAP_CIPHER_RDY] = 0x138,
+ [PWRAP_CIPHER_MODE] = 0x13c,
+ [PWRAP_CIPHER_SWRST] = 0x140,
+ [PWRAP_DCM_EN] = 0x144,
+ [PWRAP_DCM_DBC_PRD] = 0x148,
+};
+
+static int mt8183_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SI_SAMPLE_CTRL] = 0xC,
+ [PWRAP_RDDMY] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1C,
+ [PWRAP_CSLEXT_WRITE] = 0x20,
+ [PWRAP_CSLEXT_READ] = 0x24,
+ [PWRAP_EXT_CK_WRITE] = 0x28,
+ [PWRAP_STAUPD_CTRL] = 0x30,
+ [PWRAP_STAUPD_GRPEN] = 0x34,
+ [PWRAP_EINT_STA0_ADR] = 0x38,
+ [PWRAP_HARB_HPRIO] = 0x5C,
+ [PWRAP_HIPRIO_ARB_EN] = 0x60,
+ [PWRAP_MAN_EN] = 0x70,
+ [PWRAP_MAN_CMD] = 0x74,
+ [PWRAP_WACS0_EN] = 0x80,
+ [PWRAP_INIT_DONE0] = 0x84,
+ [PWRAP_WACS1_EN] = 0x88,
+ [PWRAP_INIT_DONE1] = 0x8C,
+ [PWRAP_WACS2_EN] = 0x90,
+ [PWRAP_INIT_DONE2] = 0x94,
+ [PWRAP_WACS_P2P_EN] = 0xA0,
+ [PWRAP_INIT_DONE_P2P] = 0xA4,
+ [PWRAP_WACS_MD32_EN] = 0xA8,
+ [PWRAP_INIT_DONE_MD32] = 0xAC,
+ [PWRAP_INT_EN] = 0xB0,
+ [PWRAP_INT_FLG] = 0xB8,
+ [PWRAP_INT_CLR] = 0xBC,
+ [PWRAP_INT1_EN] = 0xC0,
+ [PWRAP_INT1_FLG] = 0xC8,
+ [PWRAP_INT1_CLR] = 0xCC,
+ [PWRAP_SIG_ADR] = 0xD0,
+ [PWRAP_CRC_EN] = 0xE0,
+ [PWRAP_TIMER_EN] = 0xE4,
+ [PWRAP_WDT_UNIT] = 0xEC,
+ [PWRAP_WDT_SRC_EN] = 0xF0,
+ [PWRAP_WDT_SRC_EN_1] = 0xF4,
+ [PWRAP_INT_GPS_AUXADC_CMD_ADDR] = 0x1DC,
+ [PWRAP_INT_GPS_AUXADC_CMD] = 0x1E0,
+ [PWRAP_INT_GPS_AUXADC_RDATA_ADDR] = 0x1E4,
+ [PWRAP_EXT_GPS_AUXADC_RDATA_ADDR] = 0x1E8,
+ [PWRAP_GPSINF_0_STA] = 0x1EC,
+ [PWRAP_GPSINF_1_STA] = 0x1F0,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
+};
+
+static int mt8195_regs[] = {
+ [PWRAP_INIT_DONE2] = 0x0,
+ [PWRAP_STAUPD_CTRL] = 0x4C,
+ [PWRAP_TIMER_EN] = 0x3E4,
+ [PWRAP_INT_EN] = 0x420,
+ [PWRAP_INT_FLG] = 0x428,
+ [PWRAP_INT_CLR] = 0x42C,
+ [PWRAP_INT1_EN] = 0x450,
+ [PWRAP_INT1_FLG] = 0x458,
+ [PWRAP_INT1_CLR] = 0x45C,
+ [PWRAP_WACS2_CMD] = 0x880,
+ [PWRAP_SWINF_2_WDATA_31_0] = 0x884,
+ [PWRAP_SWINF_2_RDATA_31_0] = 0x894,
+ [PWRAP_WACS2_VLDCLR] = 0x8A4,
+ [PWRAP_WACS2_RDATA] = 0x8A8,
+};
+
+static int mt8516_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_SIDLY] = 0xc,
+ [PWRAP_RDDMY] = 0x10,
+ [PWRAP_SI_CK_CON] = 0x14,
+ [PWRAP_CSHEXT_WRITE] = 0x18,
+ [PWRAP_CSHEXT_READ] = 0x1c,
+ [PWRAP_CSLEXT_START] = 0x20,
+ [PWRAP_CSLEXT_END] = 0x24,
+ [PWRAP_STAUPD_PRD] = 0x28,
+ [PWRAP_STAUPD_GRPEN] = 0x2c,
+ [PWRAP_STAUPD_MAN_TRIG] = 0x40,
+ [PWRAP_STAUPD_STA] = 0x44,
+ [PWRAP_WRAP_STA] = 0x48,
+ [PWRAP_HARB_INIT] = 0x4c,
+ [PWRAP_HARB_HPRIO] = 0x50,
+ [PWRAP_HIPRIO_ARB_EN] = 0x54,
+ [PWRAP_HARB_STA0] = 0x58,
+ [PWRAP_HARB_STA1] = 0x5c,
+ [PWRAP_MAN_EN] = 0x60,
+ [PWRAP_MAN_CMD] = 0x64,
+ [PWRAP_MAN_RDATA] = 0x68,
+ [PWRAP_MAN_VLDCLR] = 0x6c,
+ [PWRAP_WACS0_EN] = 0x70,
+ [PWRAP_INIT_DONE0] = 0x74,
+ [PWRAP_WACS0_CMD] = 0x78,
+ [PWRAP_WACS0_RDATA] = 0x7c,
+ [PWRAP_WACS0_VLDCLR] = 0x80,
+ [PWRAP_WACS1_EN] = 0x84,
+ [PWRAP_INIT_DONE1] = 0x88,
+ [PWRAP_WACS1_CMD] = 0x8c,
+ [PWRAP_WACS1_RDATA] = 0x90,
+ [PWRAP_WACS1_VLDCLR] = 0x94,
+ [PWRAP_WACS2_EN] = 0x98,
+ [PWRAP_INIT_DONE2] = 0x9c,
+ [PWRAP_WACS2_CMD] = 0xa0,
+ [PWRAP_WACS2_RDATA] = 0xa4,
+ [PWRAP_WACS2_VLDCLR] = 0xa8,
+ [PWRAP_INT_EN] = 0xac,
+ [PWRAP_INT_FLG_RAW] = 0xb0,
+ [PWRAP_INT_FLG] = 0xb4,
+ [PWRAP_INT_CLR] = 0xb8,
+ [PWRAP_SIG_ADR] = 0xbc,
+ [PWRAP_SIG_MODE] = 0xc0,
+ [PWRAP_SIG_VALUE] = 0xc4,
+ [PWRAP_SIG_ERRVAL] = 0xc8,
+ [PWRAP_CRC_EN] = 0xcc,
+ [PWRAP_TIMER_EN] = 0xd0,
+ [PWRAP_TIMER_STA] = 0xd4,
+ [PWRAP_WDT_UNIT] = 0xd8,
+ [PWRAP_WDT_SRC_EN] = 0xdc,
+ [PWRAP_WDT_FLG] = 0xe0,
+ [PWRAP_DEBUG_INT_SEL] = 0xe4,
+ [PWRAP_DVFS_ADR0] = 0xe8,
+ [PWRAP_DVFS_WDATA0] = 0xec,
+ [PWRAP_DVFS_ADR1] = 0xf0,
+ [PWRAP_DVFS_WDATA1] = 0xf4,
+ [PWRAP_DVFS_ADR2] = 0xf8,
+ [PWRAP_DVFS_WDATA2] = 0xfc,
+ [PWRAP_DVFS_ADR3] = 0x100,
+ [PWRAP_DVFS_WDATA3] = 0x104,
+ [PWRAP_DVFS_ADR4] = 0x108,
+ [PWRAP_DVFS_WDATA4] = 0x10c,
+ [PWRAP_DVFS_ADR5] = 0x110,
+ [PWRAP_DVFS_WDATA5] = 0x114,
+ [PWRAP_DVFS_ADR6] = 0x118,
+ [PWRAP_DVFS_WDATA6] = 0x11c,
+ [PWRAP_DVFS_ADR7] = 0x120,
+ [PWRAP_DVFS_WDATA7] = 0x124,
+ [PWRAP_SPMINF_STA] = 0x128,
+ [PWRAP_CIPHER_KEY_SEL] = 0x12c,
+ [PWRAP_CIPHER_IV_SEL] = 0x130,
+ [PWRAP_CIPHER_EN] = 0x134,
+ [PWRAP_CIPHER_RDY] = 0x138,
+ [PWRAP_CIPHER_MODE] = 0x13c,
+ [PWRAP_CIPHER_SWRST] = 0x140,
+ [PWRAP_DCM_EN] = 0x144,
+ [PWRAP_DCM_DBC_PRD] = 0x148,
+ [PWRAP_SW_RST] = 0x168,
+ [PWRAP_OP_TYPE] = 0x16c,
+ [PWRAP_MSB_FIRST] = 0x170,
+};
+
+static int mt8186_regs[] = {
+ [PWRAP_MUX_SEL] = 0x0,
+ [PWRAP_WRAP_EN] = 0x4,
+ [PWRAP_DIO_EN] = 0x8,
+ [PWRAP_RDDMY] = 0x20,
+ [PWRAP_CSHEXT_WRITE] = 0x24,
+ [PWRAP_CSHEXT_READ] = 0x28,
+ [PWRAP_CSLEXT_WRITE] = 0x2C,
+ [PWRAP_CSLEXT_READ] = 0x30,
+ [PWRAP_EXT_CK_WRITE] = 0x34,
+ [PWRAP_STAUPD_CTRL] = 0x3C,
+ [PWRAP_STAUPD_GRPEN] = 0x40,
+ [PWRAP_EINT_STA0_ADR] = 0x44,
+ [PWRAP_EINT_STA1_ADR] = 0x48,
+ [PWRAP_INT_CLR] = 0xC8,
+ [PWRAP_INT_FLG] = 0xC4,
+ [PWRAP_MAN_EN] = 0x7C,
+ [PWRAP_MAN_CMD] = 0x80,
+ [PWRAP_WACS0_EN] = 0x8C,
+ [PWRAP_WACS1_EN] = 0x94,
+ [PWRAP_WACS2_EN] = 0x9C,
+ [PWRAP_INIT_DONE0] = 0x90,
+ [PWRAP_INIT_DONE1] = 0x98,
+ [PWRAP_INIT_DONE2] = 0xA0,
+ [PWRAP_INT_EN] = 0xBC,
+ [PWRAP_INT1_EN] = 0xCC,
+ [PWRAP_INT1_FLG] = 0xD4,
+ [PWRAP_INT1_CLR] = 0xD8,
+ [PWRAP_TIMER_EN] = 0xF0,
+ [PWRAP_WDT_UNIT] = 0xF8,
+ [PWRAP_WDT_SRC_EN] = 0xFC,
+ [PWRAP_WDT_SRC_EN_1] = 0x100,
+ [PWRAP_WDT_FLG] = 0x104,
+ [PWRAP_SPMINF_STA] = 0x1B4,
+ [PWRAP_DCM_EN] = 0x1EC,
+ [PWRAP_DCM_DBC_PRD] = 0x1F0,
+ [PWRAP_GPSINF_0_STA] = 0x204,
+ [PWRAP_GPSINF_1_STA] = 0x208,
+ [PWRAP_WACS0_CMD] = 0xC00,
+ [PWRAP_WACS0_RDATA] = 0xC04,
+ [PWRAP_WACS0_VLDCLR] = 0xC08,
+ [PWRAP_WACS1_CMD] = 0xC10,
+ [PWRAP_WACS1_RDATA] = 0xC14,
+ [PWRAP_WACS1_VLDCLR] = 0xC18,
+ [PWRAP_WACS2_CMD] = 0xC20,
+ [PWRAP_WACS2_RDATA] = 0xC24,
+ [PWRAP_WACS2_VLDCLR] = 0xC28,
+};
+
+enum pmic_type {
+ PMIC_MT6323,
+ PMIC_MT6351,
+ PMIC_MT6357,
+ PMIC_MT6358,
+ PMIC_MT6359,
+ PMIC_MT6380,
+ PMIC_MT6397,
+};
+
+enum pwrap_type {
+ PWRAP_MT2701,
+ PWRAP_MT6765,
+ PWRAP_MT6779,
+ PWRAP_MT6797,
+ PWRAP_MT6873,
+ PWRAP_MT7622,
+ PWRAP_MT8135,
+ PWRAP_MT8173,
+ PWRAP_MT8183,
+ PWRAP_MT8186,
+ PWRAP_MT8195,
+ PWRAP_MT8516,
+};
+
+struct pmic_wrapper;
+
+struct pwrap_slv_regops {
+ const struct regmap_config *regmap;
+ /*
+ * pwrap operations are highly associated with the PMIC types,
+ * so the pointers added increases flexibility allowing determination
+ * which type is used by the detection through device tree.
+ */
+ int (*pwrap_read)(struct pmic_wrapper *wrp, u32 adr, u32 *rdata);
+ int (*pwrap_write)(struct pmic_wrapper *wrp, u32 adr, u32 wdata);
+};
+
+struct pwrap_slv_type {
+ const u32 *dew_regs;
+ enum pmic_type type;
+ const struct pwrap_slv_regops *regops;
+ /* Flags indicating the capability for the target slave */
+ u32 caps;
+};
+
+struct pmic_wrapper {
+ struct device *dev;
+ void __iomem *base;
+ struct regmap *regmap;
+ const struct pmic_wrapper_type *master;
+ const struct pwrap_slv_type *slave;
+ struct clk *clk_spi;
+ struct clk *clk_wrap;
+ struct reset_control *rstc;
+
+ struct reset_control *rstc_bridge;
+ void __iomem *bridge_base;
+};
+
+struct pmic_wrapper_type {
+ int *regs;
+ enum pwrap_type type;
+ u32 arb_en_all;
+ u32 int_en_all;
+ u32 int1_en_all;
+ u32 spi_w;
+ u32 wdt_src;
+ /* Flags indicating the capability for the target pwrap */
+ u32 caps;
+ int (*init_reg_clock)(struct pmic_wrapper *wrp);
+ int (*init_soc_specific)(struct pmic_wrapper *wrp);
+};
+
+static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg)
+{
+ return readl(wrp->base + wrp->master->regs[reg]);
+}
+
+static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg)
+{
+ writel(val, wrp->base + wrp->master->regs[reg]);
+}
+
+static u32 pwrap_get_fsm_state(struct pmic_wrapper *wrp)
+{
+ u32 val;
+
+ val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ return PWRAP_GET_WACS_ARB_FSM(val);
+ else
+ return PWRAP_GET_WACS_FSM(val);
+}
+
+static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp)
+{
+ return pwrap_get_fsm_state(wrp) == PWRAP_WACS_FSM_IDLE;
+}
+
+static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp)
+{
+ return pwrap_get_fsm_state(wrp) == PWRAP_WACS_FSM_WFVLDCLR;
+}
+
+/*
+ * Timeout issue sometimes caused by the last read command
+ * failed because pmic wrap could not got the FSM_VLDCLR
+ * in time after finishing WACS2_CMD. It made state machine
+ * still on FSM_VLDCLR and timeout next time.
+ * Check the status of FSM and clear the vldclr to recovery the
+ * error.
+ */
+static inline void pwrap_leave_fsm_vldclr(struct pmic_wrapper *wrp)
+{
+ if (pwrap_is_fsm_vldclr(wrp))
+ pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+}
+
+static bool pwrap_is_sync_idle(struct pmic_wrapper *wrp)
+{
+ return pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_SYNC_IDLE0;
+}
+
+static bool pwrap_is_fsm_idle_and_sync_idle(struct pmic_wrapper *wrp)
+{
+ u32 val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+
+ return (PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_IDLE) &&
+ (val & PWRAP_STATE_SYNC_IDLE0);
+}
+
+static int pwrap_read16(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+{
+ bool tmp;
+ int ret;
+ u32 val;
+
+ ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ pwrap_leave_fsm_vldclr(wrp);
+ return ret;
+ }
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ val = adr;
+ else
+ val = (adr >> 1) << 16;
+ pwrap_writel(wrp, val, PWRAP_WACS2_CMD);
+
+ ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ val = pwrap_readl(wrp, PWRAP_SWINF_2_RDATA_31_0);
+ else
+ val = pwrap_readl(wrp, PWRAP_WACS2_RDATA);
+ *rdata = PWRAP_GET_WACS_RDATA(val);
+
+ pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+
+ return 0;
+}
+
+static int pwrap_read32(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+{
+ bool tmp;
+ int ret, msb;
+
+ *rdata = 0;
+ for (msb = 0; msb < 2; msb++) {
+ ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+
+ if (ret) {
+ pwrap_leave_fsm_vldclr(wrp);
+ return ret;
+ }
+
+ pwrap_writel(wrp, ((msb << 30) | (adr << 16)),
+ PWRAP_WACS2_CMD);
+
+ ret = readx_poll_timeout(pwrap_is_fsm_vldclr, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ *rdata += (PWRAP_GET_WACS_RDATA(pwrap_readl(wrp,
+ PWRAP_WACS2_RDATA)) << (16 * msb));
+
+ pwrap_writel(wrp, 1, PWRAP_WACS2_VLDCLR);
+ }
+
+ return 0;
+}
+
+static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+{
+ return wrp->slave->regops->pwrap_read(wrp, adr, rdata);
+}
+
+static int pwrap_write16(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+{
+ bool tmp;
+ int ret;
+
+ ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ pwrap_leave_fsm_vldclr(wrp);
+ return ret;
+ }
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB)) {
+ pwrap_writel(wrp, wdata, PWRAP_SWINF_2_WDATA_31_0);
+ pwrap_writel(wrp, BIT(29) | adr, PWRAP_WACS2_CMD);
+ } else {
+ pwrap_writel(wrp, BIT(31) | ((adr >> 1) << 16) | wdata,
+ PWRAP_WACS2_CMD);
+ }
+
+ return 0;
+}
+
+static int pwrap_write32(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+{
+ bool tmp;
+ int ret, msb, rdata;
+
+ for (msb = 0; msb < 2; msb++) {
+ ret = readx_poll_timeout(pwrap_is_fsm_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ pwrap_leave_fsm_vldclr(wrp);
+ return ret;
+ }
+
+ pwrap_writel(wrp, (1 << 31) | (msb << 30) | (adr << 16) |
+ ((wdata >> (msb * 16)) & 0xffff),
+ PWRAP_WACS2_CMD);
+
+ /*
+ * The pwrap_read operation is the requirement of hardware used
+ * for the synchronization between two successive 16-bit
+ * pwrap_writel operations composing one 32-bit bus writing.
+ * Otherwise, we'll find the result fails on the lower 16-bit
+ * pwrap writing.
+ */
+ if (!msb)
+ pwrap_read(wrp, adr, &rdata);
+ }
+
+ return 0;
+}
+
+static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+{
+ return wrp->slave->regops->pwrap_write(wrp, adr, wdata);
+}
+
+static int pwrap_regmap_read(void *context, u32 adr, u32 *rdata)
+{
+ return pwrap_read(context, adr, rdata);
+}
+
+static int pwrap_regmap_write(void *context, u32 adr, u32 wdata)
+{
+ return pwrap_write(context, adr, wdata);
+}
+
+static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
+{
+ bool tmp;
+ int ret, i;
+
+ pwrap_writel(wrp, 0, PWRAP_HIPRIO_ARB_EN);
+ pwrap_writel(wrp, 0, PWRAP_WRAP_EN);
+ pwrap_writel(wrp, 1, PWRAP_MUX_SEL);
+ pwrap_writel(wrp, 1, PWRAP_MAN_EN);
+ pwrap_writel(wrp, 0, PWRAP_DIO_EN);
+
+ pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSL,
+ PWRAP_MAN_CMD);
+ pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS,
+ PWRAP_MAN_CMD);
+ pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSH,
+ PWRAP_MAN_CMD);
+
+ for (i = 0; i < 4; i++)
+ pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS,
+ PWRAP_MAN_CMD);
+
+ ret = readx_poll_timeout(pwrap_is_sync_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ pwrap_writel(wrp, 0, PWRAP_MAN_EN);
+ pwrap_writel(wrp, 0, PWRAP_MUX_SEL);
+
+ return 0;
+}
+
+/*
+ * pwrap_init_sidly - configure serial input delay
+ *
+ * This configures the serial input delay. We can configure 0, 2, 4 or 6ns
+ * delay. Do a read test with all possible values and chose the best delay.
+ */
+static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+{
+ u32 rdata;
+ u32 i;
+ u32 pass = 0;
+ signed char dly[16] = {
+ -1, 0, 1, 0, 2, -1, 1, 1, 3, -1, -1, -1, 3, -1, 2, 1
+ };
+
+ for (i = 0; i < 4; i++) {
+ pwrap_writel(wrp, i, PWRAP_SIDLY);
+ pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_READ_TEST],
+ &rdata);
+ if (rdata == PWRAP_DEW_READ_TEST_VAL) {
+ dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i);
+ pass |= 1 << i;
+ }
+ }
+
+ if (dly[pass] < 0) {
+ dev_err(wrp->dev, "sidly pass range 0x%x not continuous\n",
+ pass);
+ return -EIO;
+ }
+
+ pwrap_writel(wrp, dly[pass], PWRAP_SIDLY);
+
+ return 0;
+}
+
+static int pwrap_init_dual_io(struct pmic_wrapper *wrp)
+{
+ int ret;
+ bool tmp;
+ u32 rdata;
+
+ /* Enable dual IO mode */
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_DIO_EN], 1);
+
+ /* Check IDLE & INIT_DONE in advance */
+ ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(wrp->dev, "%s fail, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ pwrap_writel(wrp, 1, PWRAP_DIO_EN);
+
+ /* Read Test */
+ pwrap_read(wrp,
+ wrp->slave->dew_regs[PWRAP_DEW_READ_TEST], &rdata);
+ if (rdata != PWRAP_DEW_READ_TEST_VAL) {
+ dev_err(wrp->dev,
+ "Read failed on DIO mode: 0x%04x!=0x%04x\n",
+ PWRAP_DEW_READ_TEST_VAL, rdata);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*
+ * pwrap_init_chip_select_ext is used to configure CS extension time for each
+ * phase during data transactions on the pwrap bus.
+ */
+static void pwrap_init_chip_select_ext(struct pmic_wrapper *wrp, u8 hext_write,
+ u8 hext_read, u8 lext_start,
+ u8 lext_end)
+{
+ /*
+ * After finishing a write and read transaction, extends CS high time
+ * to be at least xT of BUS CLK as hext_write and hext_read specifies
+ * respectively.
+ */
+ pwrap_writel(wrp, hext_write, PWRAP_CSHEXT_WRITE);
+ pwrap_writel(wrp, hext_read, PWRAP_CSHEXT_READ);
+
+ /*
+ * Extends CS low time after CSL and before CSH command to be at
+ * least xT of BUS CLK as lext_start and lext_end specifies
+ * respectively.
+ */
+ pwrap_writel(wrp, lext_start, PWRAP_CSLEXT_START);
+ pwrap_writel(wrp, lext_end, PWRAP_CSLEXT_END);
+}
+
+static int pwrap_common_init_reg_clock(struct pmic_wrapper *wrp)
+{
+ switch (wrp->master->type) {
+ case PWRAP_MT8173:
+ pwrap_init_chip_select_ext(wrp, 0, 4, 2, 2);
+ break;
+ case PWRAP_MT8135:
+ pwrap_writel(wrp, 0x4, PWRAP_CSHEXT);
+ pwrap_init_chip_select_ext(wrp, 0, 4, 0, 0);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int pwrap_mt2701_init_reg_clock(struct pmic_wrapper *wrp)
+{
+ switch (wrp->slave->type) {
+ case PMIC_MT6397:
+ pwrap_writel(wrp, 0xc, PWRAP_RDDMY);
+ pwrap_init_chip_select_ext(wrp, 4, 0, 2, 2);
+ break;
+
+ case PMIC_MT6323:
+ pwrap_writel(wrp, 0x8, PWRAP_RDDMY);
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_RDDMY_NO],
+ 0x8);
+ pwrap_init_chip_select_ext(wrp, 5, 0, 2, 2);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp)
+{
+ return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1;
+}
+
+static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+{
+ u32 rdata;
+ int ret;
+
+ ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY],
+ &rdata);
+ if (ret)
+ return false;
+
+ return rdata == 1;
+}
+
+static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+{
+ int ret;
+ bool tmp;
+ u32 rdata = 0;
+
+ pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
+ pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
+ pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL);
+ pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL);
+
+ switch (wrp->master->type) {
+ case PWRAP_MT8135:
+ pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD);
+ pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
+ break;
+ case PWRAP_MT2701:
+ case PWRAP_MT6765:
+ case PWRAP_MT6779:
+ case PWRAP_MT6797:
+ case PWRAP_MT8173:
+ case PWRAP_MT8186:
+ case PWRAP_MT8516:
+ pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
+ break;
+ case PWRAP_MT7622:
+ pwrap_writel(wrp, 0, PWRAP_CIPHER_EN);
+ break;
+ case PWRAP_MT6873:
+ case PWRAP_MT8183:
+ case PWRAP_MT8195:
+ break;
+ }
+
+ /* Config cipher mode @PMIC */
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x1);
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0);
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1);
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2);
+
+ switch (wrp->slave->type) {
+ case PMIC_MT6397:
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD],
+ 0x1);
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START],
+ 0x1);
+ break;
+ case PMIC_MT6323:
+ case PMIC_MT6351:
+ case PMIC_MT6357:
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN],
+ 0x1);
+ break;
+ default:
+ break;
+ }
+
+ /* wait for cipher data ready@AP */
+ ret = readx_poll_timeout(pwrap_is_cipher_ready, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(wrp->dev, "cipher data ready@AP fail, ret=%d\n", ret);
+ return ret;
+ }
+
+ /* wait for cipher data ready@PMIC */
+ ret = readx_poll_timeout(pwrap_is_pmic_cipher_ready, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(wrp->dev,
+ "timeout waiting for cipher data ready@PMIC\n");
+ return ret;
+ }
+
+ /* wait for cipher mode idle */
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_MODE], 0x1);
+ ret = readx_poll_timeout(pwrap_is_fsm_idle_and_sync_idle, wrp, tmp, tmp,
+ PWRAP_POLL_DELAY_US, PWRAP_POLL_TIMEOUT_US);
+ if (ret) {
+ dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
+ return ret;
+ }
+
+ pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE);
+
+ /* Write Test */
+ if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST],
+ PWRAP_DEW_WRITE_TEST_VAL) ||
+ pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_WRITE_TEST],
+ &rdata) ||
+ (rdata != PWRAP_DEW_WRITE_TEST_VAL)) {
+ dev_err(wrp->dev, "rdata=0x%04X\n", rdata);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int pwrap_init_security(struct pmic_wrapper *wrp)
+{
+ int ret;
+
+ /* Enable encryption */
+ ret = pwrap_init_cipher(wrp);
+ if (ret)
+ return ret;
+
+ /* Signature checking - using CRC */
+ if (pwrap_write(wrp,
+ wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1))
+ return -EFAULT;
+
+ pwrap_writel(wrp, 0x1, PWRAP_CRC_EN);
+ pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE);
+ pwrap_writel(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_VAL],
+ PWRAP_SIG_ADR);
+ pwrap_writel(wrp,
+ wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
+
+ return 0;
+}
+
+static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ /* enable pwrap events and pwrap bridge in AP side */
+ pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN);
+ pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN);
+ writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN);
+ writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN);
+ writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN);
+ writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT);
+ writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN);
+ writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN);
+ writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN);
+
+ /* enable PMIC event out and sources */
+ if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN],
+ 0x1) ||
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN],
+ 0xffff)) {
+ dev_err(wrp->dev, "enable dewrap fail\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ /* PMIC_DEWRAP enables */
+ if (pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_OUT_EN],
+ 0x1) ||
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_EVENT_SRC_EN],
+ 0xffff)) {
+ dev_err(wrp->dev, "enable dewrap fail\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int pwrap_mt2701_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ /* GPS_INTF initialization */
+ switch (wrp->slave->type) {
+ case PMIC_MT6323:
+ pwrap_writel(wrp, 0x076c, PWRAP_ADC_CMD_ADDR);
+ pwrap_writel(wrp, 0x8000, PWRAP_PWRAP_ADC_CMD);
+ pwrap_writel(wrp, 0x072c, PWRAP_ADC_RDY_ADDR);
+ pwrap_writel(wrp, 0x072e, PWRAP_ADC_RDATA_ADDR1);
+ pwrap_writel(wrp, 0x0730, PWRAP_ADC_RDATA_ADDR2);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int pwrap_mt7622_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ pwrap_writel(wrp, 0, PWRAP_STAUPD_PRD);
+ /* enable 2wire SPI master */
+ pwrap_writel(wrp, 0x8000000, PWRAP_SPI2_CTRL);
+
+ return 0;
+}
+
+static int pwrap_mt8183_init_soc_specific(struct pmic_wrapper *wrp)
+{
+ pwrap_writel(wrp, 0xf5, PWRAP_STAUPD_GRPEN);
+
+ pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1);
+ pwrap_writel(wrp, 1, PWRAP_CRC_EN);
+ pwrap_writel(wrp, 0x416, PWRAP_SIG_ADR);
+ pwrap_writel(wrp, 0x42e, PWRAP_EINT_STA0_ADR);
+
+ pwrap_writel(wrp, 1, PWRAP_WACS_P2P_EN);
+ pwrap_writel(wrp, 1, PWRAP_WACS_MD32_EN);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE_P2P);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE_MD32);
+
+ return 0;
+}
+
+static int pwrap_init(struct pmic_wrapper *wrp)
+{
+ int ret;
+
+ if (wrp->rstc)
+ reset_control_reset(wrp->rstc);
+ if (wrp->rstc_bridge)
+ reset_control_reset(wrp->rstc_bridge);
+
+ if (wrp->master->type == PWRAP_MT8173) {
+ /* Enable DCM */
+ pwrap_writel(wrp, 3, PWRAP_DCM_EN);
+ pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+ }
+
+ if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SPI)) {
+ /* Reset SPI slave */
+ ret = pwrap_reset_spislave(wrp);
+ if (ret)
+ return ret;
+ }
+
+ pwrap_writel(wrp, 1, PWRAP_WRAP_EN);
+
+ pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
+
+ pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
+
+ ret = wrp->master->init_reg_clock(wrp);
+ if (ret)
+ return ret;
+
+ if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SPI)) {
+ /* Setup serial input delay */
+ ret = pwrap_init_sidly(wrp);
+ if (ret)
+ return ret;
+ }
+
+ if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_DUALIO)) {
+ /* Enable dual I/O mode */
+ ret = pwrap_init_dual_io(wrp);
+ if (ret)
+ return ret;
+ }
+
+ if (HAS_CAP(wrp->slave->caps, PWRAP_SLV_CAP_SECURITY)) {
+ /* Enable security on bus */
+ ret = pwrap_init_security(wrp);
+ if (ret)
+ return ret;
+ }
+
+ if (wrp->master->type == PWRAP_MT8135)
+ pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
+
+ pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN);
+ pwrap_writel(wrp, 0x1, PWRAP_WACS1_EN);
+ pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN);
+ pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
+ pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
+
+ if (wrp->master->init_soc_specific) {
+ ret = wrp->master->init_soc_specific(wrp);
+ if (ret)
+ return ret;
+ }
+
+ /* Setup the init done registers */
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE2);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
+ pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
+ writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
+ writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
+ }
+
+ return 0;
+}
+
+static irqreturn_t pwrap_interrupt(int irqno, void *dev_id)
+{
+ u32 rdata;
+ struct pmic_wrapper *wrp = dev_id;
+
+ rdata = pwrap_readl(wrp, PWRAP_INT_FLG);
+ dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata);
+ pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR);
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) {
+ rdata = pwrap_readl(wrp, PWRAP_INT1_FLG);
+ dev_err(wrp->dev, "unexpected interrupt int1=0x%x\n", rdata);
+ pwrap_writel(wrp, 0xffffffff, PWRAP_INT1_CLR);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct regmap_config pwrap_regmap_config16 = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .reg_stride = 2,
+ .reg_read = pwrap_regmap_read,
+ .reg_write = pwrap_regmap_write,
+ .max_register = 0xffff,
+};
+
+static const struct regmap_config pwrap_regmap_config32 = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .reg_read = pwrap_regmap_read,
+ .reg_write = pwrap_regmap_write,
+ .max_register = 0xffff,
+};
+
+static const struct pwrap_slv_regops pwrap_regops16 = {
+ .pwrap_read = pwrap_read16,
+ .pwrap_write = pwrap_write16,
+ .regmap = &pwrap_regmap_config16,
+};
+
+static const struct pwrap_slv_regops pwrap_regops32 = {
+ .pwrap_read = pwrap_read32,
+ .pwrap_write = pwrap_write32,
+ .regmap = &pwrap_regmap_config32,
+};
+
+static const struct pwrap_slv_type pmic_mt6323 = {
+ .dew_regs = mt6323_regs,
+ .type = PMIC_MT6323,
+ .regops = &pwrap_regops16,
+ .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
+ PWRAP_SLV_CAP_SECURITY,
+};
+
+static const struct pwrap_slv_type pmic_mt6351 = {
+ .dew_regs = mt6351_regs,
+ .type = PMIC_MT6351,
+ .regops = &pwrap_regops16,
+ .caps = 0,
+};
+
+static const struct pwrap_slv_type pmic_mt6357 = {
+ .dew_regs = mt6357_regs,
+ .type = PMIC_MT6357,
+ .regops = &pwrap_regops16,
+ .caps = 0,
+};
+
+static const struct pwrap_slv_type pmic_mt6358 = {
+ .dew_regs = mt6358_regs,
+ .type = PMIC_MT6358,
+ .regops = &pwrap_regops16,
+ .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
+};
+
+static const struct pwrap_slv_type pmic_mt6359 = {
+ .dew_regs = mt6359_regs,
+ .type = PMIC_MT6359,
+ .regops = &pwrap_regops16,
+ .caps = PWRAP_SLV_CAP_DUALIO,
+};
+
+static const struct pwrap_slv_type pmic_mt6380 = {
+ .dew_regs = NULL,
+ .type = PMIC_MT6380,
+ .regops = &pwrap_regops32,
+ .caps = 0,
+};
+
+static const struct pwrap_slv_type pmic_mt6397 = {
+ .dew_regs = mt6397_regs,
+ .type = PMIC_MT6397,
+ .regops = &pwrap_regops16,
+ .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO |
+ PWRAP_SLV_CAP_SECURITY,
+};
+
+static const struct of_device_id of_slave_match_tbl[] = {
+ { .compatible = "mediatek,mt6323", .data = &pmic_mt6323 },
+ { .compatible = "mediatek,mt6351", .data = &pmic_mt6351 },
+ { .compatible = "mediatek,mt6357", .data = &pmic_mt6357 },
+ { .compatible = "mediatek,mt6358", .data = &pmic_mt6358 },
+ { .compatible = "mediatek,mt6359", .data = &pmic_mt6359 },
+
+ /* The MT6380 PMIC only implements a regulator, so we bind it
+ * directly instead of using a MFD.
+ */
+ { .compatible = "mediatek,mt6380-regulator", .data = &pmic_mt6380 },
+ { .compatible = "mediatek,mt6397", .data = &pmic_mt6397 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
+
+static const struct pmic_wrapper_type pwrap_mt2701 = {
+ .regs = mt2701_regs,
+ .type = PWRAP_MT2701,
+ .arb_en_all = 0x3f,
+ .int_en_all = ~(u32)(BIT(31) | BIT(2)),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_mt2701_init_reg_clock,
+ .init_soc_specific = pwrap_mt2701_init_soc_specific,
+};
+
+static const struct pmic_wrapper_type pwrap_mt6765 = {
+ .regs = mt6765_regs,
+ .type = PWRAP_MT6765,
+ .arb_en_all = 0x3fd35,
+ .int_en_all = 0xffffffff,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static const struct pmic_wrapper_type pwrap_mt6779 = {
+ .regs = mt6779_regs,
+ .type = PWRAP_MT6779,
+ .arb_en_all = 0xfbb7f,
+ .int_en_all = 0xfffffffe,
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = 0,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static const struct pmic_wrapper_type pwrap_mt6797 = {
+ .regs = mt6797_regs,
+ .type = PWRAP_MT6797,
+ .arb_en_all = 0x01fff,
+ .int_en_all = 0xffffffc6,
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static const struct pmic_wrapper_type pwrap_mt6873 = {
+ .regs = mt6873_regs,
+ .type = PWRAP_MT6873,
+ .arb_en_all = 0x777f,
+ .int_en_all = BIT(4) | BIT(5),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_ARB,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static const struct pmic_wrapper_type pwrap_mt7622 = {
+ .regs = mt7622_regs,
+ .type = PWRAP_MT7622,
+ .arb_en_all = 0xff,
+ .int_en_all = ~(u32)BIT(31),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt7622_init_soc_specific,
+};
+
+static const struct pmic_wrapper_type pwrap_mt8135 = {
+ .regs = mt8135_regs,
+ .type = PWRAP_MT8135,
+ .arb_en_all = 0x1ff,
+ .int_en_all = ~(u32)(BIT(31) | BIT(1)),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_BRIDGE | PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt8135_init_soc_specific,
+};
+
+static const struct pmic_wrapper_type pwrap_mt8173 = {
+ .regs = mt8173_regs,
+ .type = PWRAP_MT8173,
+ .arb_en_all = 0x3f,
+ .int_en_all = ~(u32)(BIT(31) | BIT(1)),
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
+ .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt8173_init_soc_specific,
+};
+
+static const struct pmic_wrapper_type pwrap_mt8183 = {
+ .regs = mt8183_regs,
+ .type = PWRAP_MT8183,
+ .arb_en_all = 0x3fa75,
+ .int_en_all = 0xffffffff,
+ .int1_en_all = 0xeef7ffff,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = pwrap_mt8183_init_soc_specific,
+};
+
+static struct pmic_wrapper_type pwrap_mt8195 = {
+ .regs = mt8195_regs,
+ .type = PWRAP_MT8195,
+ .arb_en_all = 0x777f, /* NEED CONFIRM */
+ .int_en_all = 0x180000, /* NEED CONFIRM */
+ .int1_en_all = 0,
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static struct pmic_wrapper_type pwrap_mt8516 = {
+ .regs = mt8516_regs,
+ .type = PWRAP_MT8516,
+ .arb_en_all = 0xff,
+ .int_en_all = ~(u32)(BIT(31) | BIT(2)),
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_DCM,
+ .init_reg_clock = pwrap_mt2701_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static struct pmic_wrapper_type pwrap_mt8186 = {
+ .regs = mt8186_regs,
+ .type = PWRAP_MT8186,
+ .arb_en_all = 0xfb27f,
+ .int_en_all = 0xfffffffe, /* disable WatchDog Timeout for bit 1 */
+ .int1_en_all = 0x000017ff, /* disable Matching interrupt for bit 13 */
+ .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+ .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+ .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB_MT8186,
+ .init_reg_clock = pwrap_common_init_reg_clock,
+ .init_soc_specific = NULL,
+};
+
+static const struct of_device_id of_pwrap_match_tbl[] = {
+ { .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701 },
+ { .compatible = "mediatek,mt6765-pwrap", .data = &pwrap_mt6765 },
+ { .compatible = "mediatek,mt6779-pwrap", .data = &pwrap_mt6779 },
+ { .compatible = "mediatek,mt6797-pwrap", .data = &pwrap_mt6797 },
+ { .compatible = "mediatek,mt6873-pwrap", .data = &pwrap_mt6873 },
+ { .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622 },
+ { .compatible = "mediatek,mt8135-pwrap", .data = &pwrap_mt8135 },
+ { .compatible = "mediatek,mt8173-pwrap", .data = &pwrap_mt8173 },
+ { .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183 },
+ { .compatible = "mediatek,mt8186-pwrap", .data = &pwrap_mt8186 },
+ { .compatible = "mediatek,mt8195-pwrap", .data = &pwrap_mt8195 },
+ { .compatible = "mediatek,mt8516-pwrap", .data = &pwrap_mt8516 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+
+static int pwrap_probe(struct platform_device *pdev)
+{
+ int ret, irq;
+ u32 mask_done;
+ struct pmic_wrapper *wrp;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_slave_id = NULL;
+
+ if (np->child)
+ of_slave_id = of_match_node(of_slave_match_tbl, np->child);
+
+ if (!of_slave_id) {
+ dev_dbg(&pdev->dev, "slave pmic should be defined in dts\n");
+ return -EINVAL;
+ }
+
+ wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
+ if (!wrp)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, wrp);
+
+ wrp->master = of_device_get_match_data(&pdev->dev);
+ wrp->slave = of_slave_id->data;
+ wrp->dev = &pdev->dev;
+
+ wrp->base = devm_platform_ioremap_resource_byname(pdev, "pwrap");
+ if (IS_ERR(wrp->base))
+ return PTR_ERR(wrp->base);
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_RESET)) {
+ wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap");
+ if (IS_ERR(wrp->rstc)) {
+ ret = PTR_ERR(wrp->rstc);
+ dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
+ wrp->bridge_base = devm_platform_ioremap_resource_byname(pdev, "pwrap-bridge");
+ if (IS_ERR(wrp->bridge_base))
+ return PTR_ERR(wrp->bridge_base);
+
+ wrp->rstc_bridge = devm_reset_control_get(wrp->dev,
+ "pwrap-bridge");
+ if (IS_ERR(wrp->rstc_bridge)) {
+ ret = PTR_ERR(wrp->rstc_bridge);
+ dev_dbg(wrp->dev,
+ "cannot get pwrap-bridge reset: %d\n", ret);
+ return ret;
+ }
+ }
+
+ wrp->clk_spi = devm_clk_get(wrp->dev, "spi");
+ if (IS_ERR(wrp->clk_spi)) {
+ dev_dbg(wrp->dev, "failed to get clock: %ld\n",
+ PTR_ERR(wrp->clk_spi));
+ return PTR_ERR(wrp->clk_spi);
+ }
+
+ wrp->clk_wrap = devm_clk_get(wrp->dev, "wrap");
+ if (IS_ERR(wrp->clk_wrap)) {
+ dev_dbg(wrp->dev, "failed to get clock: %ld\n",
+ PTR_ERR(wrp->clk_wrap));
+ return PTR_ERR(wrp->clk_wrap);
+ }
+
+ ret = clk_prepare_enable(wrp->clk_spi);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(wrp->clk_wrap);
+ if (ret)
+ goto err_out1;
+
+ /* Enable internal dynamic clock */
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
+ pwrap_writel(wrp, 1, PWRAP_DCM_EN);
+ pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
+ }
+
+ /*
+ * The PMIC could already be initialized by the bootloader.
+ * Skip initialization here in this case.
+ */
+ if (!pwrap_readl(wrp, PWRAP_INIT_DONE2)) {
+ ret = pwrap_init(wrp);
+ if (ret) {
+ dev_dbg(wrp->dev, "init failed with %d\n", ret);
+ goto err_out2;
+ }
+ }
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ mask_done = PWRAP_STATE_INIT_DONE1;
+ else if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB_MT8186))
+ mask_done = PWRAP_STATE_INIT_DONE0_MT8186;
+ else
+ mask_done = PWRAP_STATE_INIT_DONE0;
+
+ if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & mask_done)) {
+ dev_dbg(wrp->dev, "initialization isn't finished\n");
+ ret = -ENODEV;
+ goto err_out2;
+ }
+
+ /* Initialize watchdog, may not be done by the bootloader */
+ if (!HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
+
+ /*
+ * Since STAUPD was not used on mt8173 platform,
+ * so STAUPD of WDT_SRC which should be turned off
+ */
+ pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN);
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1))
+ pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1);
+
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_ARB))
+ pwrap_writel(wrp, 0x3, PWRAP_TIMER_EN);
+ else
+ pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
+
+ pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN);
+ /*
+ * We add INT1 interrupt to handle starvation and request exception
+ * If we support it, we should enable it here.
+ */
+ if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN))
+ pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto err_out2;
+ }
+
+ ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
+ IRQF_TRIGGER_HIGH,
+ "mt-pmic-pwrap", wrp);
+ if (ret)
+ goto err_out2;
+
+ wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, wrp->slave->regops->regmap);
+ if (IS_ERR(wrp->regmap)) {
+ ret = PTR_ERR(wrp->regmap);
+ goto err_out2;
+ }
+
+ ret = of_platform_populate(np, NULL, NULL, wrp->dev);
+ if (ret) {
+ dev_dbg(wrp->dev, "failed to create child devices at %pOF\n",
+ np);
+ goto err_out2;
+ }
+
+ return 0;
+
+err_out2:
+ clk_disable_unprepare(wrp->clk_wrap);
+err_out1:
+ clk_disable_unprepare(wrp->clk_spi);
+
+ return ret;
+}
+
+static struct platform_driver pwrap_drv = {
+ .driver = {
+ .name = "mt-pmic-pwrap",
+ .of_match_table = of_pwrap_match_tbl,
+ },
+ .probe = pwrap_probe,
+};
+
+module_platform_driver(pwrap_drv);
+
+MODULE_AUTHOR("Flora Fu, MediaTek");
+MODULE_DESCRIPTION("MediaTek MT8135 PMIC Wrapper Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
new file mode 100644
index 000000000..7a6688881
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -0,0 +1,1147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
+ */
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regulator/consumer.h>
+#include <linux/soc/mediatek/infracfg.h>
+
+#include <dt-bindings/power/mt2701-power.h>
+#include <dt-bindings/power/mt2712-power.h>
+#include <dt-bindings/power/mt6797-power.h>
+#include <dt-bindings/power/mt7622-power.h>
+#include <dt-bindings/power/mt7623a-power.h>
+#include <dt-bindings/power/mt8173-power.h>
+
+#define MTK_POLL_DELAY_US 10
+#define MTK_POLL_TIMEOUT USEC_PER_SEC
+
+#define MTK_SCPD_ACTIVE_WAKEUP BIT(0)
+#define MTK_SCPD_FWAIT_SRAM BIT(1)
+#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x))
+
+#define SPM_VDE_PWR_CON 0x0210
+#define SPM_MFG_PWR_CON 0x0214
+#define SPM_VEN_PWR_CON 0x0230
+#define SPM_ISP_PWR_CON 0x0238
+#define SPM_DIS_PWR_CON 0x023c
+#define SPM_CONN_PWR_CON 0x0280
+#define SPM_VEN2_PWR_CON 0x0298
+#define SPM_AUDIO_PWR_CON 0x029c /* MT8173, MT2712 */
+#define SPM_BDP_PWR_CON 0x029c /* MT2701 */
+#define SPM_ETH_PWR_CON 0x02a0
+#define SPM_HIF_PWR_CON 0x02a4
+#define SPM_IFR_MSC_PWR_CON 0x02a8
+#define SPM_MFG_2D_PWR_CON 0x02c0
+#define SPM_MFG_ASYNC_PWR_CON 0x02c4
+#define SPM_USB_PWR_CON 0x02cc
+#define SPM_USB2_PWR_CON 0x02d4 /* MT2712 */
+#define SPM_ETHSYS_PWR_CON 0x02e0 /* MT7622 */
+#define SPM_HIF0_PWR_CON 0x02e4 /* MT7622 */
+#define SPM_HIF1_PWR_CON 0x02e8 /* MT7622 */
+#define SPM_WB_PWR_CON 0x02ec /* MT7622 */
+
+#define SPM_PWR_STATUS 0x060c
+#define SPM_PWR_STATUS_2ND 0x0610
+
+#define PWR_RST_B_BIT BIT(0)
+#define PWR_ISO_BIT BIT(1)
+#define PWR_ON_BIT BIT(2)
+#define PWR_ON_2ND_BIT BIT(3)
+#define PWR_CLK_DIS_BIT BIT(4)
+
+#define PWR_STATUS_CONN BIT(1)
+#define PWR_STATUS_DISP BIT(3)
+#define PWR_STATUS_MFG BIT(4)
+#define PWR_STATUS_ISP BIT(5)
+#define PWR_STATUS_VDEC BIT(7)
+#define PWR_STATUS_BDP BIT(14)
+#define PWR_STATUS_ETH BIT(15)
+#define PWR_STATUS_HIF BIT(16)
+#define PWR_STATUS_IFR_MSC BIT(17)
+#define PWR_STATUS_USB2 BIT(19) /* MT2712 */
+#define PWR_STATUS_VENC_LT BIT(20)
+#define PWR_STATUS_VENC BIT(21)
+#define PWR_STATUS_MFG_2D BIT(22) /* MT8173 */
+#define PWR_STATUS_MFG_ASYNC BIT(23) /* MT8173 */
+#define PWR_STATUS_AUDIO BIT(24) /* MT8173, MT2712 */
+#define PWR_STATUS_USB BIT(25) /* MT8173, MT2712 */
+#define PWR_STATUS_ETHSYS BIT(24) /* MT7622 */
+#define PWR_STATUS_HIF0 BIT(25) /* MT7622 */
+#define PWR_STATUS_HIF1 BIT(26) /* MT7622 */
+#define PWR_STATUS_WB BIT(27) /* MT7622 */
+
+enum clk_id {
+ CLK_NONE,
+ CLK_MM,
+ CLK_MFG,
+ CLK_VENC,
+ CLK_VENC_LT,
+ CLK_ETHIF,
+ CLK_VDEC,
+ CLK_HIFSEL,
+ CLK_JPGDEC,
+ CLK_AUDIO,
+ CLK_MAX,
+};
+
+static const char * const clk_names[] = {
+ NULL,
+ "mm",
+ "mfg",
+ "venc",
+ "venc_lt",
+ "ethif",
+ "vdec",
+ "hif_sel",
+ "jpgdec",
+ "audio",
+ NULL,
+};
+
+#define MAX_CLKS 3
+
+/**
+ * struct scp_domain_data - scp domain data for power on/off flow
+ * @name: The domain name.
+ * @sta_mask: The mask for power on/off status bit.
+ * @ctl_offs: The offset for main power control register.
+ * @sram_pdn_bits: The mask for sram power control bits.
+ * @sram_pdn_ack_bits: The mask for sram power control acked bits.
+ * @bus_prot_mask: The mask for single step bus protection.
+ * @clk_id: The basic clocks required by this power domain.
+ * @caps: The flag for active wake-up action.
+ */
+struct scp_domain_data {
+ const char *name;
+ u32 sta_mask;
+ int ctl_offs;
+ u32 sram_pdn_bits;
+ u32 sram_pdn_ack_bits;
+ u32 bus_prot_mask;
+ enum clk_id clk_id[MAX_CLKS];
+ u8 caps;
+};
+
+struct scp;
+
+struct scp_domain {
+ struct generic_pm_domain genpd;
+ struct scp *scp;
+ struct clk *clk[MAX_CLKS];
+ const struct scp_domain_data *data;
+ struct regulator *supply;
+};
+
+struct scp_ctrl_reg {
+ int pwr_sta_offs;
+ int pwr_sta2nd_offs;
+};
+
+struct scp {
+ struct scp_domain *domains;
+ struct genpd_onecell_data pd_data;
+ struct device *dev;
+ void __iomem *base;
+ struct regmap *infracfg;
+ struct scp_ctrl_reg ctrl_reg;
+ bool bus_prot_reg_update;
+};
+
+struct scp_subdomain {
+ int origin;
+ int subdomain;
+};
+
+struct scp_soc_data {
+ const struct scp_domain_data *domains;
+ int num_domains;
+ const struct scp_subdomain *subdomains;
+ int num_subdomains;
+ const struct scp_ctrl_reg regs;
+ bool bus_prot_reg_update;
+};
+
+static int scpsys_domain_is_on(struct scp_domain *scpd)
+{
+ struct scp *scp = scpd->scp;
+
+ u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
+ scpd->data->sta_mask;
+ u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
+ scpd->data->sta_mask;
+
+ /*
+ * A domain is on when both status bits are set. If only one is set
+ * return an error. This happens while powering up a domain
+ */
+
+ if (status && status2)
+ return true;
+ if (!status && !status2)
+ return false;
+
+ return -EINVAL;
+}
+
+static int scpsys_regulator_enable(struct scp_domain *scpd)
+{
+ if (!scpd->supply)
+ return 0;
+
+ return regulator_enable(scpd->supply);
+}
+
+static int scpsys_regulator_disable(struct scp_domain *scpd)
+{
+ if (!scpd->supply)
+ return 0;
+
+ return regulator_disable(scpd->supply);
+}
+
+static void scpsys_clk_disable(struct clk *clk[], int max_num)
+{
+ int i;
+
+ for (i = max_num - 1; i >= 0; i--)
+ clk_disable_unprepare(clk[i]);
+}
+
+static int scpsys_clk_enable(struct clk *clk[], int max_num)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < max_num && clk[i]; i++) {
+ ret = clk_prepare_enable(clk[i]);
+ if (ret) {
+ scpsys_clk_disable(clk, i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int scpsys_sram_enable(struct scp_domain *scpd, void __iomem *ctl_addr)
+{
+ u32 val;
+ u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
+ int tmp;
+
+ val = readl(ctl_addr);
+ val &= ~scpd->data->sram_pdn_bits;
+ writel(val, ctl_addr);
+
+ /* Either wait until SRAM_PDN_ACK all 0 or have a force wait */
+ if (MTK_SCPD_CAPS(scpd, MTK_SCPD_FWAIT_SRAM)) {
+ /*
+ * Currently, MTK_SCPD_FWAIT_SRAM is necessary only for
+ * MT7622_POWER_DOMAIN_WB and thus just a trivial setup
+ * is applied here.
+ */
+ usleep_range(12000, 12100);
+ } else {
+ /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+ int ret = readl_poll_timeout(ctl_addr, tmp,
+ (tmp & pdn_ack) == 0,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scpsys_sram_disable(struct scp_domain *scpd, void __iomem *ctl_addr)
+{
+ u32 val;
+ u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
+ int tmp;
+
+ val = readl(ctl_addr);
+ val |= scpd->data->sram_pdn_bits;
+ writel(val, ctl_addr);
+
+ /* Either wait until SRAM_PDN_ACK all 1 or 0 */
+ return readl_poll_timeout(ctl_addr, tmp,
+ (tmp & pdn_ack) == pdn_ack,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+}
+
+static int scpsys_bus_protect_enable(struct scp_domain *scpd)
+{
+ struct scp *scp = scpd->scp;
+
+ if (!scpd->data->bus_prot_mask)
+ return 0;
+
+ return mtk_infracfg_set_bus_protection(scp->infracfg,
+ scpd->data->bus_prot_mask,
+ scp->bus_prot_reg_update);
+}
+
+static int scpsys_bus_protect_disable(struct scp_domain *scpd)
+{
+ struct scp *scp = scpd->scp;
+
+ if (!scpd->data->bus_prot_mask)
+ return 0;
+
+ return mtk_infracfg_clear_bus_protection(scp->infracfg,
+ scpd->data->bus_prot_mask,
+ scp->bus_prot_reg_update);
+}
+
+static int scpsys_power_on(struct generic_pm_domain *genpd)
+{
+ struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
+ struct scp *scp = scpd->scp;
+ void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
+ u32 val;
+ int ret, tmp;
+
+ ret = scpsys_regulator_enable(scpd);
+ if (ret < 0)
+ return ret;
+
+ ret = scpsys_clk_enable(scpd->clk, MAX_CLKS);
+ if (ret)
+ goto err_clk;
+
+ /* subsys power on */
+ val = readl(ctl_addr);
+ val |= PWR_ON_BIT;
+ writel(val, ctl_addr);
+ val |= PWR_ON_2ND_BIT;
+ writel(val, ctl_addr);
+
+ /* wait until PWR_ACK = 1 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp > 0,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ goto err_pwr_ack;
+
+ val &= ~PWR_CLK_DIS_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ISO_BIT;
+ writel(val, ctl_addr);
+
+ val |= PWR_RST_B_BIT;
+ writel(val, ctl_addr);
+
+ ret = scpsys_sram_enable(scpd, ctl_addr);
+ if (ret < 0)
+ goto err_pwr_ack;
+
+ ret = scpsys_bus_protect_disable(scpd);
+ if (ret < 0)
+ goto err_pwr_ack;
+
+ return 0;
+
+err_pwr_ack:
+ scpsys_clk_disable(scpd->clk, MAX_CLKS);
+err_clk:
+ scpsys_regulator_disable(scpd);
+
+ dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
+
+ return ret;
+}
+
+static int scpsys_power_off(struct generic_pm_domain *genpd)
+{
+ struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
+ struct scp *scp = scpd->scp;
+ void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
+ u32 val;
+ int ret, tmp;
+
+ ret = scpsys_bus_protect_enable(scpd);
+ if (ret < 0)
+ goto out;
+
+ ret = scpsys_sram_disable(scpd, ctl_addr);
+ if (ret < 0)
+ goto out;
+
+ /* subsys power off */
+ val = readl(ctl_addr);
+ val |= PWR_ISO_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_RST_B_BIT;
+ writel(val, ctl_addr);
+
+ val |= PWR_CLK_DIS_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ON_BIT;
+ writel(val, ctl_addr);
+
+ val &= ~PWR_ON_2ND_BIT;
+ writel(val, ctl_addr);
+
+ /* wait until PWR_ACK = 0 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, scpd, tmp, tmp == 0,
+ MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ goto out;
+
+ scpsys_clk_disable(scpd->clk, MAX_CLKS);
+
+ ret = scpsys_regulator_disable(scpd);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+
+out:
+ dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
+
+ return ret;
+}
+
+static void init_clks(struct platform_device *pdev, struct clk **clk)
+{
+ int i;
+
+ for (i = CLK_NONE + 1; i < CLK_MAX; i++)
+ clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
+}
+
+static struct scp *init_scp(struct platform_device *pdev,
+ const struct scp_domain_data *scp_domain_data, int num,
+ const struct scp_ctrl_reg *scp_ctrl_reg,
+ bool bus_prot_reg_update)
+{
+ struct genpd_onecell_data *pd_data;
+ struct resource *res;
+ int i, j;
+ struct scp *scp;
+ struct clk *clk[CLK_MAX];
+
+ scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
+ if (!scp)
+ return ERR_PTR(-ENOMEM);
+
+ scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
+ scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
+
+ scp->bus_prot_reg_update = bus_prot_reg_update;
+
+ scp->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ scp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(scp->base))
+ return ERR_CAST(scp->base);
+
+ scp->domains = devm_kcalloc(&pdev->dev,
+ num, sizeof(*scp->domains), GFP_KERNEL);
+ if (!scp->domains)
+ return ERR_PTR(-ENOMEM);
+
+ pd_data = &scp->pd_data;
+
+ pd_data->domains = devm_kcalloc(&pdev->dev,
+ num, sizeof(*pd_data->domains), GFP_KERNEL);
+ if (!pd_data->domains)
+ return ERR_PTR(-ENOMEM);
+
+ scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "infracfg");
+ if (IS_ERR(scp->infracfg)) {
+ dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
+ PTR_ERR(scp->infracfg));
+ return ERR_CAST(scp->infracfg);
+ }
+
+ for (i = 0; i < num; i++) {
+ struct scp_domain *scpd = &scp->domains[i];
+ const struct scp_domain_data *data = &scp_domain_data[i];
+
+ scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
+ if (IS_ERR(scpd->supply)) {
+ if (PTR_ERR(scpd->supply) == -ENODEV)
+ scpd->supply = NULL;
+ else
+ return ERR_CAST(scpd->supply);
+ }
+ }
+
+ pd_data->num_domains = num;
+
+ init_clks(pdev, clk);
+
+ for (i = 0; i < num; i++) {
+ struct scp_domain *scpd = &scp->domains[i];
+ struct generic_pm_domain *genpd = &scpd->genpd;
+ const struct scp_domain_data *data = &scp_domain_data[i];
+
+ pd_data->domains[i] = genpd;
+ scpd->scp = scp;
+
+ scpd->data = data;
+
+ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
+ struct clk *c = clk[data->clk_id[j]];
+
+ if (IS_ERR(c)) {
+ dev_err(&pdev->dev, "%s: clk unavailable\n",
+ data->name);
+ return ERR_CAST(c);
+ }
+
+ scpd->clk[j] = c;
+ }
+
+ genpd->name = data->name;
+ genpd->power_off = scpsys_power_off;
+ genpd->power_on = scpsys_power_on;
+ if (MTK_SCPD_CAPS(scpd, MTK_SCPD_ACTIVE_WAKEUP))
+ genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+ }
+
+ return scp;
+}
+
+static void mtk_register_power_domains(struct platform_device *pdev,
+ struct scp *scp, int num)
+{
+ struct genpd_onecell_data *pd_data;
+ int i, ret;
+
+ for (i = 0; i < num; i++) {
+ struct scp_domain *scpd = &scp->domains[i];
+ struct generic_pm_domain *genpd = &scpd->genpd;
+ bool on;
+
+ /*
+ * Initially turn on all domains to make the domains usable
+ * with !CONFIG_PM and to get the hardware in sync with the
+ * software. The unused domains will be switched off during
+ * late_init time.
+ */
+ on = !WARN_ON(genpd->power_on(genpd) < 0);
+
+ pm_genpd_init(genpd, NULL, !on);
+ }
+
+ /*
+ * We are not allowed to fail here since there is no way to unregister
+ * a power domain. Once registered above we have to keep the domains
+ * valid.
+ */
+
+ pd_data = &scp->pd_data;
+
+ ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
+}
+
+/*
+ * MT2701 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt2701[] = {
+ [MT2701_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = SPM_CONN_PWR_CON,
+ .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M |
+ MT2701_TOP_AXI_PROT_EN_CONN_S,
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_DISP] = {
+ .name = "disp",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .clk_id = {CLK_MM},
+ .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_MM_M0,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MFG},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_MM},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_BDP] = {
+ .name = "bdp",
+ .sta_mask = PWR_STATUS_BDP,
+ .ctl_offs = SPM_BDP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_ETH] = {
+ .name = "eth",
+ .sta_mask = PWR_STATUS_ETH,
+ .ctl_offs = SPM_ETH_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_ETHIF},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_HIF] = {
+ .name = "hif",
+ .sta_mask = PWR_STATUS_HIF,
+ .ctl_offs = SPM_HIF_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_ETHIF},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2701_POWER_DOMAIN_IFR_MSC] = {
+ .name = "ifr_msc",
+ .sta_mask = PWR_STATUS_IFR_MSC,
+ .ctl_offs = SPM_IFR_MSC_PWR_CON,
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+};
+
+/*
+ * MT2712 power domain support
+ */
+static const struct scp_domain_data scp_domain_data_mt2712[] = {
+ [MT2712_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM, CLK_VDEC},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = SPM_VEN_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_MM, CLK_VENC, CLK_JPGDEC},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_MM},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = SPM_AUDIO_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_AUDIO},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_USB] = {
+ .name = "usb",
+ .sta_mask = PWR_STATUS_USB,
+ .ctl_offs = SPM_USB_PWR_CON,
+ .sram_pdn_bits = GENMASK(10, 8),
+ .sram_pdn_ack_bits = GENMASK(14, 12),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_USB2] = {
+ .name = "usb2",
+ .sta_mask = PWR_STATUS_USB2,
+ .ctl_offs = SPM_USB2_PWR_CON,
+ .sram_pdn_bits = GENMASK(10, 8),
+ .sram_pdn_ack_bits = GENMASK(14, 12),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(16, 16),
+ .clk_id = {CLK_MFG},
+ .bus_prot_mask = BIT(14) | BIT(21) | BIT(23),
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_MFG_SC1] = {
+ .name = "mfg_sc1",
+ .sta_mask = BIT(22),
+ .ctl_offs = 0x02c0,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(16, 16),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_MFG_SC2] = {
+ .name = "mfg_sc2",
+ .sta_mask = BIT(23),
+ .ctl_offs = 0x02c4,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(16, 16),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT2712_POWER_DOMAIN_MFG_SC3] = {
+ .name = "mfg_sc3",
+ .sta_mask = BIT(30),
+ .ctl_offs = 0x01f8,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(16, 16),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+};
+
+static const struct scp_subdomain scp_subdomain_mt2712[] = {
+ {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VDEC},
+ {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_VENC},
+ {MT2712_POWER_DOMAIN_MM, MT2712_POWER_DOMAIN_ISP},
+ {MT2712_POWER_DOMAIN_MFG, MT2712_POWER_DOMAIN_MFG_SC1},
+ {MT2712_POWER_DOMAIN_MFG_SC1, MT2712_POWER_DOMAIN_MFG_SC2},
+ {MT2712_POWER_DOMAIN_MFG_SC2, MT2712_POWER_DOMAIN_MFG_SC3},
+};
+
+/*
+ * MT6797 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt6797[] = {
+ [MT6797_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x300,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_VDEC},
+ },
+ [MT6797_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(21),
+ .ctl_offs = 0x304,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x308,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x30C,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ .bus_prot_mask = (BIT(1) | BIT(2)),
+ },
+ [MT6797_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x314,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x334,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .clk_id = {CLK_MFG},
+ },
+ [MT6797_POWER_DOMAIN_MJC] = {
+ .name = "mjc",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x310,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_NONE},
+ },
+};
+
+#define SPM_PWR_STATUS_MT6797 0x0180
+#define SPM_PWR_STATUS_2ND_MT6797 0x0184
+
+static const struct scp_subdomain scp_subdomain_mt6797[] = {
+ {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VDEC},
+ {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_ISP},
+ {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_VENC},
+ {MT6797_POWER_DOMAIN_MM, MT6797_POWER_DOMAIN_MJC},
+};
+
+/*
+ * MT7622 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt7622[] = {
+ [MT7622_POWER_DOMAIN_ETHSYS] = {
+ .name = "ethsys",
+ .sta_mask = PWR_STATUS_ETHSYS,
+ .ctl_offs = SPM_ETHSYS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_ETHSYS,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7622_POWER_DOMAIN_HIF0] = {
+ .name = "hif0",
+ .sta_mask = PWR_STATUS_HIF0,
+ .ctl_offs = SPM_HIF0_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_HIFSEL},
+ .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF0,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7622_POWER_DOMAIN_HIF1] = {
+ .name = "hif1",
+ .sta_mask = PWR_STATUS_HIF1,
+ .ctl_offs = SPM_HIF1_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_HIFSEL},
+ .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_HIF1,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7622_POWER_DOMAIN_WB] = {
+ .name = "wb",
+ .sta_mask = PWR_STATUS_WB,
+ .ctl_offs = SPM_WB_PWR_CON,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .clk_id = {CLK_NONE},
+ .bus_prot_mask = MT7622_TOP_AXI_PROT_EN_WB,
+ .caps = MTK_SCPD_ACTIVE_WAKEUP | MTK_SCPD_FWAIT_SRAM,
+ },
+};
+
+/*
+ * MT7623A power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt7623a[] = {
+ [MT7623A_POWER_DOMAIN_CONN] = {
+ .name = "conn",
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = SPM_CONN_PWR_CON,
+ .bus_prot_mask = MT2701_TOP_AXI_PROT_EN_CONN_M |
+ MT2701_TOP_AXI_PROT_EN_CONN_S,
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7623A_POWER_DOMAIN_ETH] = {
+ .name = "eth",
+ .sta_mask = PWR_STATUS_ETH,
+ .ctl_offs = SPM_ETH_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_ETHIF},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7623A_POWER_DOMAIN_HIF] = {
+ .name = "hif",
+ .sta_mask = PWR_STATUS_HIF,
+ .ctl_offs = SPM_HIF_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_ETHIF},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT7623A_POWER_DOMAIN_IFR_MSC] = {
+ .name = "ifr_msc",
+ .sta_mask = PWR_STATUS_IFR_MSC,
+ .ctl_offs = SPM_IFR_MSC_PWR_CON,
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+};
+
+/*
+ * MT8173 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt8173[] = {
+ [MT8173_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = PWR_STATUS_VDEC,
+ .ctl_offs = SPM_VDE_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ },
+ [MT8173_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = PWR_STATUS_VENC,
+ .ctl_offs = SPM_VEN_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_MM, CLK_VENC},
+ },
+ [MT8173_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = PWR_STATUS_ISP,
+ .ctl_offs = SPM_ISP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_MM},
+ },
+ [MT8173_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
+ MT8173_TOP_AXI_PROT_EN_MM_M1,
+ },
+ [MT8173_POWER_DOMAIN_VENC_LT] = {
+ .name = "venc_lt",
+ .sta_mask = PWR_STATUS_VENC_LT,
+ .ctl_offs = SPM_VEN2_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_MM, CLK_VENC_LT},
+ },
+ [MT8173_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = PWR_STATUS_AUDIO,
+ .ctl_offs = SPM_AUDIO_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT8173_POWER_DOMAIN_USB] = {
+ .name = "usb",
+ .sta_mask = PWR_STATUS_USB,
+ .ctl_offs = SPM_USB_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ .caps = MTK_SCPD_ACTIVE_WAKEUP,
+ },
+ [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = PWR_STATUS_MFG_ASYNC,
+ .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = 0,
+ .clk_id = {CLK_MFG},
+ },
+ [MT8173_POWER_DOMAIN_MFG_2D] = {
+ .name = "mfg_2d",
+ .sta_mask = PWR_STATUS_MFG_2D,
+ .ctl_offs = SPM_MFG_2D_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT8173_POWER_DOMAIN_MFG] = {
+ .name = "mfg",
+ .sta_mask = PWR_STATUS_MFG,
+ .ctl_offs = SPM_MFG_PWR_CON,
+ .sram_pdn_bits = GENMASK(13, 8),
+ .sram_pdn_ack_bits = GENMASK(21, 16),
+ .clk_id = {CLK_NONE},
+ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
+ MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+ MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
+ },
+};
+
+static const struct scp_subdomain scp_subdomain_mt8173[] = {
+ {MT8173_POWER_DOMAIN_MFG_ASYNC, MT8173_POWER_DOMAIN_MFG_2D},
+ {MT8173_POWER_DOMAIN_MFG_2D, MT8173_POWER_DOMAIN_MFG},
+};
+
+static const struct scp_soc_data mt2701_data = {
+ .domains = scp_domain_data_mt2701,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt2701),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
+ },
+ .bus_prot_reg_update = true,
+};
+
+static const struct scp_soc_data mt2712_data = {
+ .domains = scp_domain_data_mt2712,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt2712),
+ .subdomains = scp_subdomain_mt2712,
+ .num_subdomains = ARRAY_SIZE(scp_subdomain_mt2712),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
+ },
+ .bus_prot_reg_update = false,
+};
+
+static const struct scp_soc_data mt6797_data = {
+ .domains = scp_domain_data_mt6797,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt6797),
+ .subdomains = scp_subdomain_mt6797,
+ .num_subdomains = ARRAY_SIZE(scp_subdomain_mt6797),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS_MT6797,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797
+ },
+ .bus_prot_reg_update = true,
+};
+
+static const struct scp_soc_data mt7622_data = {
+ .domains = scp_domain_data_mt7622,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt7622),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
+ },
+ .bus_prot_reg_update = true,
+};
+
+static const struct scp_soc_data mt7623a_data = {
+ .domains = scp_domain_data_mt7623a,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt7623a),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
+ },
+ .bus_prot_reg_update = true,
+};
+
+static const struct scp_soc_data mt8173_data = {
+ .domains = scp_domain_data_mt8173,
+ .num_domains = ARRAY_SIZE(scp_domain_data_mt8173),
+ .subdomains = scp_subdomain_mt8173,
+ .num_subdomains = ARRAY_SIZE(scp_subdomain_mt8173),
+ .regs = {
+ .pwr_sta_offs = SPM_PWR_STATUS,
+ .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND
+ },
+ .bus_prot_reg_update = true,
+};
+
+/*
+ * scpsys driver init
+ */
+
+static const struct of_device_id of_scpsys_match_tbl[] = {
+ {
+ .compatible = "mediatek,mt2701-scpsys",
+ .data = &mt2701_data,
+ }, {
+ .compatible = "mediatek,mt2712-scpsys",
+ .data = &mt2712_data,
+ }, {
+ .compatible = "mediatek,mt6797-scpsys",
+ .data = &mt6797_data,
+ }, {
+ .compatible = "mediatek,mt7622-scpsys",
+ .data = &mt7622_data,
+ }, {
+ .compatible = "mediatek,mt7623a-scpsys",
+ .data = &mt7623a_data,
+ }, {
+ .compatible = "mediatek,mt8173-scpsys",
+ .data = &mt8173_data,
+ }, {
+ /* sentinel */
+ }
+};
+
+static int scpsys_probe(struct platform_device *pdev)
+{
+ const struct scp_subdomain *sd;
+ const struct scp_soc_data *soc;
+ struct scp *scp;
+ struct genpd_onecell_data *pd_data;
+ int i, ret;
+
+ soc = of_device_get_match_data(&pdev->dev);
+
+ scp = init_scp(pdev, soc->domains, soc->num_domains, &soc->regs,
+ soc->bus_prot_reg_update);
+ if (IS_ERR(scp))
+ return PTR_ERR(scp);
+
+ mtk_register_power_domains(pdev, scp, soc->num_domains);
+
+ pd_data = &scp->pd_data;
+
+ for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) {
+ ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
+ pd_data->domains[sd->subdomain]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n",
+ ret);
+ }
+
+ return 0;
+}
+
+static struct platform_driver scpsys_drv = {
+ .probe = scpsys_probe,
+ .driver = {
+ .name = "mtk-scpsys",
+ .suppress_bind_attrs = true,
+ .owner = THIS_MODULE,
+ .of_match_table = of_scpsys_match_tbl,
+ },
+};
+builtin_platform_driver(scpsys_drv);
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
new file mode 100644
index 000000000..f00cd5c72
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -0,0 +1,2491 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/cpuidle.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+/* svs bank 1-line software id */
+#define SVSB_CPU_LITTLE BIT(0)
+#define SVSB_CPU_BIG BIT(1)
+#define SVSB_CCI BIT(2)
+#define SVSB_GPU BIT(3)
+
+/* svs bank 2-line type */
+#define SVSB_LOW BIT(8)
+#define SVSB_HIGH BIT(9)
+
+/* svs bank mode support */
+#define SVSB_MODE_ALL_DISABLE 0
+#define SVSB_MODE_INIT01 BIT(1)
+#define SVSB_MODE_INIT02 BIT(2)
+#define SVSB_MODE_MON BIT(3)
+
+/* svs bank volt flags */
+#define SVSB_INIT01_PD_REQ BIT(0)
+#define SVSB_INIT01_VOLT_IGNORE BIT(1)
+#define SVSB_INIT01_VOLT_INC_ONLY BIT(2)
+#define SVSB_MON_VOLT_IGNORE BIT(16)
+#define SVSB_REMOVE_DVTFIXED_VOLT BIT(24)
+
+/* svs bank register fields and common configuration */
+#define SVSB_PTPCONFIG_DETMAX GENMASK(15, 0)
+#define SVSB_DET_MAX FIELD_PREP(SVSB_PTPCONFIG_DETMAX, 0xffff)
+#define SVSB_DET_WINDOW 0xa28
+
+/* DESCHAR */
+#define SVSB_DESCHAR_FLD_MDES GENMASK(7, 0)
+#define SVSB_DESCHAR_FLD_BDES GENMASK(15, 8)
+
+/* TEMPCHAR */
+#define SVSB_TEMPCHAR_FLD_DVT_FIXED GENMASK(7, 0)
+#define SVSB_TEMPCHAR_FLD_MTDES GENMASK(15, 8)
+#define SVSB_TEMPCHAR_FLD_VCO GENMASK(23, 16)
+
+/* DETCHAR */
+#define SVSB_DETCHAR_FLD_DCMDET GENMASK(7, 0)
+#define SVSB_DETCHAR_FLD_DCBDET GENMASK(15, 8)
+
+/* SVSEN (PTPEN) */
+#define SVSB_PTPEN_INIT01 BIT(0)
+#define SVSB_PTPEN_MON BIT(1)
+#define SVSB_PTPEN_INIT02 (SVSB_PTPEN_INIT01 | BIT(2))
+#define SVSB_PTPEN_OFF 0x0
+
+/* FREQPCTS */
+#define SVSB_FREQPCTS_FLD_PCT0_4 GENMASK(7, 0)
+#define SVSB_FREQPCTS_FLD_PCT1_5 GENMASK(15, 8)
+#define SVSB_FREQPCTS_FLD_PCT2_6 GENMASK(23, 16)
+#define SVSB_FREQPCTS_FLD_PCT3_7 GENMASK(31, 24)
+
+/* INTSTS */
+#define SVSB_INTSTS_VAL_CLEAN 0x00ffffff
+#define SVSB_INTSTS_F0_COMPLETE BIT(0)
+#define SVSB_INTSTS_FLD_MONVOP GENMASK(23, 16)
+#define SVSB_RUNCONFIG_DEFAULT 0x80000000
+
+/* LIMITVALS */
+#define SVSB_LIMITVALS_FLD_DTLO GENMASK(7, 0)
+#define SVSB_LIMITVALS_FLD_DTHI GENMASK(15, 8)
+#define SVSB_LIMITVALS_FLD_VMIN GENMASK(23, 16)
+#define SVSB_LIMITVALS_FLD_VMAX GENMASK(31, 24)
+#define SVSB_VAL_DTHI 0x1
+#define SVSB_VAL_DTLO 0xfe
+
+/* INTEN */
+#define SVSB_INTEN_F0EN BIT(0)
+#define SVSB_INTEN_DACK0UPEN BIT(8)
+#define SVSB_INTEN_DC0EN BIT(9)
+#define SVSB_INTEN_DC1EN BIT(10)
+#define SVSB_INTEN_DACK0LOEN BIT(11)
+#define SVSB_INTEN_INITPROD_OVF_EN BIT(12)
+#define SVSB_INTEN_INITSUM_OVF_EN BIT(14)
+#define SVSB_INTEN_MONVOPEN GENMASK(23, 16)
+#define SVSB_INTEN_INIT0x (SVSB_INTEN_F0EN | SVSB_INTEN_DACK0UPEN | \
+ SVSB_INTEN_DC0EN | SVSB_INTEN_DC1EN | \
+ SVSB_INTEN_DACK0LOEN | \
+ SVSB_INTEN_INITPROD_OVF_EN | \
+ SVSB_INTEN_INITSUM_OVF_EN)
+
+/* TSCALCS */
+#define SVSB_TSCALCS_FLD_MTS GENMASK(11, 0)
+#define SVSB_TSCALCS_FLD_BTS GENMASK(23, 12)
+
+/* INIT2VALS */
+#define SVSB_INIT2VALS_FLD_DCVOFFSETIN GENMASK(15, 0)
+#define SVSB_INIT2VALS_FLD_AGEVOFFSETIN GENMASK(31, 16)
+
+/* VOPS */
+#define SVSB_VOPS_FLD_VOP0_4 GENMASK(7, 0)
+#define SVSB_VOPS_FLD_VOP1_5 GENMASK(15, 8)
+#define SVSB_VOPS_FLD_VOP2_6 GENMASK(23, 16)
+#define SVSB_VOPS_FLD_VOP3_7 GENMASK(31, 24)
+
+/* svs bank related setting */
+#define BITS8 8
+#define MAX_OPP_ENTRIES 16
+#define REG_BYTES 4
+#define SVSB_DC_SIGNED_BIT BIT(15)
+#define SVSB_DET_CLK_EN BIT(31)
+#define SVSB_TEMP_LOWER_BOUND 0xb2
+#define SVSB_TEMP_UPPER_BOUND 0x64
+
+static DEFINE_SPINLOCK(svs_lock);
+
+#ifdef CONFIG_DEBUG_FS
+#define debug_fops_ro(name) \
+ static int svs_##name##_debug_open(struct inode *inode, \
+ struct file *filp) \
+ { \
+ return single_open(filp, svs_##name##_debug_show, \
+ inode->i_private); \
+ } \
+ static const struct file_operations svs_##name##_debug_fops = { \
+ .owner = THIS_MODULE, \
+ .open = svs_##name##_debug_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ }
+
+#define debug_fops_rw(name) \
+ static int svs_##name##_debug_open(struct inode *inode, \
+ struct file *filp) \
+ { \
+ return single_open(filp, svs_##name##_debug_show, \
+ inode->i_private); \
+ } \
+ static const struct file_operations svs_##name##_debug_fops = { \
+ .owner = THIS_MODULE, \
+ .open = svs_##name##_debug_open, \
+ .read = seq_read, \
+ .write = svs_##name##_debug_write, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ }
+
+#define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops}
+#endif
+
+/**
+ * enum svsb_phase - svs bank phase enumeration
+ * @SVSB_PHASE_ERROR: svs bank encounters unexpected condition
+ * @SVSB_PHASE_INIT01: svs bank basic init for data calibration
+ * @SVSB_PHASE_INIT02: svs bank can provide voltages to opp table
+ * @SVSB_PHASE_MON: svs bank can provide voltages with thermal effect
+ * @SVSB_PHASE_MAX: total number of svs bank phase (debug purpose)
+ *
+ * Each svs bank has its own independent phase and we enable each svs bank by
+ * running their phase orderly. However, when svs bank encounters unexpected
+ * condition, it will fire an irq (PHASE_ERROR) to inform svs software.
+ *
+ * svs bank general phase-enabled order:
+ * SVSB_PHASE_INIT01 -> SVSB_PHASE_INIT02 -> SVSB_PHASE_MON
+ */
+enum svsb_phase {
+ SVSB_PHASE_ERROR = 0,
+ SVSB_PHASE_INIT01,
+ SVSB_PHASE_INIT02,
+ SVSB_PHASE_MON,
+ SVSB_PHASE_MAX,
+};
+
+enum svs_reg_index {
+ DESCHAR = 0,
+ TEMPCHAR,
+ DETCHAR,
+ AGECHAR,
+ DCCONFIG,
+ AGECONFIG,
+ FREQPCT30,
+ FREQPCT74,
+ LIMITVALS,
+ VBOOT,
+ DETWINDOW,
+ CONFIG,
+ TSCALCS,
+ RUNCONFIG,
+ SVSEN,
+ INIT2VALS,
+ DCVALUES,
+ AGEVALUES,
+ VOP30,
+ VOP74,
+ TEMP,
+ INTSTS,
+ INTSTSRAW,
+ INTEN,
+ CHKINT,
+ CHKSHIFT,
+ STATUS,
+ VDESIGN30,
+ VDESIGN74,
+ DVT30,
+ DVT74,
+ AGECOUNT,
+ SMSTATE0,
+ SMSTATE1,
+ CTL0,
+ DESDETSEC,
+ TEMPAGESEC,
+ CTRLSPARE0,
+ CTRLSPARE1,
+ CTRLSPARE2,
+ CTRLSPARE3,
+ CORESEL,
+ THERMINTST,
+ INTST,
+ THSTAGE0ST,
+ THSTAGE1ST,
+ THSTAGE2ST,
+ THAHBST0,
+ THAHBST1,
+ SPARE0,
+ SPARE1,
+ SPARE2,
+ SPARE3,
+ THSLPEVEB,
+ SVS_REG_MAX,
+};
+
+static const u32 svs_regs_v2[] = {
+ [DESCHAR] = 0xc00,
+ [TEMPCHAR] = 0xc04,
+ [DETCHAR] = 0xc08,
+ [AGECHAR] = 0xc0c,
+ [DCCONFIG] = 0xc10,
+ [AGECONFIG] = 0xc14,
+ [FREQPCT30] = 0xc18,
+ [FREQPCT74] = 0xc1c,
+ [LIMITVALS] = 0xc20,
+ [VBOOT] = 0xc24,
+ [DETWINDOW] = 0xc28,
+ [CONFIG] = 0xc2c,
+ [TSCALCS] = 0xc30,
+ [RUNCONFIG] = 0xc34,
+ [SVSEN] = 0xc38,
+ [INIT2VALS] = 0xc3c,
+ [DCVALUES] = 0xc40,
+ [AGEVALUES] = 0xc44,
+ [VOP30] = 0xc48,
+ [VOP74] = 0xc4c,
+ [TEMP] = 0xc50,
+ [INTSTS] = 0xc54,
+ [INTSTSRAW] = 0xc58,
+ [INTEN] = 0xc5c,
+ [CHKINT] = 0xc60,
+ [CHKSHIFT] = 0xc64,
+ [STATUS] = 0xc68,
+ [VDESIGN30] = 0xc6c,
+ [VDESIGN74] = 0xc70,
+ [DVT30] = 0xc74,
+ [DVT74] = 0xc78,
+ [AGECOUNT] = 0xc7c,
+ [SMSTATE0] = 0xc80,
+ [SMSTATE1] = 0xc84,
+ [CTL0] = 0xc88,
+ [DESDETSEC] = 0xce0,
+ [TEMPAGESEC] = 0xce4,
+ [CTRLSPARE0] = 0xcf0,
+ [CTRLSPARE1] = 0xcf4,
+ [CTRLSPARE2] = 0xcf8,
+ [CTRLSPARE3] = 0xcfc,
+ [CORESEL] = 0xf00,
+ [THERMINTST] = 0xf04,
+ [INTST] = 0xf08,
+ [THSTAGE0ST] = 0xf0c,
+ [THSTAGE1ST] = 0xf10,
+ [THSTAGE2ST] = 0xf14,
+ [THAHBST0] = 0xf18,
+ [THAHBST1] = 0xf1c,
+ [SPARE0] = 0xf20,
+ [SPARE1] = 0xf24,
+ [SPARE2] = 0xf28,
+ [SPARE3] = 0xf2c,
+ [THSLPEVEB] = 0xf30,
+};
+
+/**
+ * struct svs_platform - svs platform control
+ * @name: svs platform name
+ * @base: svs platform register base
+ * @dev: svs platform device
+ * @main_clk: main clock for svs bank
+ * @pbank: svs bank pointer needing to be protected by spin_lock section
+ * @banks: svs banks that svs platform supports
+ * @rst: svs platform reset control
+ * @efuse_parsing: svs platform efuse parsing function pointer
+ * @probe: svs platform probe function pointer
+ * @efuse_max: total number of svs efuse
+ * @tefuse_max: total number of thermal efuse
+ * @regs: svs platform registers map
+ * @bank_max: total number of svs banks
+ * @efuse: svs efuse data received from NVMEM framework
+ * @tefuse: thermal efuse data received from NVMEM framework
+ */
+struct svs_platform {
+ char *name;
+ void __iomem *base;
+ struct device *dev;
+ struct clk *main_clk;
+ struct svs_bank *pbank;
+ struct svs_bank *banks;
+ struct reset_control *rst;
+ bool (*efuse_parsing)(struct svs_platform *svsp);
+ int (*probe)(struct svs_platform *svsp);
+ size_t efuse_max;
+ size_t tefuse_max;
+ const u32 *regs;
+ u32 bank_max;
+ u32 *efuse;
+ u32 *tefuse;
+};
+
+struct svs_platform_data {
+ char *name;
+ struct svs_bank *banks;
+ bool (*efuse_parsing)(struct svs_platform *svsp);
+ int (*probe)(struct svs_platform *svsp);
+ const u32 *regs;
+ u32 bank_max;
+};
+
+/**
+ * struct svs_bank - svs bank representation
+ * @dev: bank device
+ * @opp_dev: device for opp table/buck control
+ * @init_completion: the timeout completion for bank init
+ * @buck: regulator used by opp_dev
+ * @tzd: thermal zone device for getting temperature
+ * @lock: mutex lock to protect voltage update process
+ * @set_freq_pct: function pointer to set bank frequency percent table
+ * @get_volts: function pointer to get bank voltages
+ * @name: bank name
+ * @buck_name: regulator name
+ * @tzone_name: thermal zone name
+ * @phase: bank current phase
+ * @volt_od: bank voltage overdrive
+ * @reg_data: bank register data in different phase for debug purpose
+ * @pm_runtime_enabled_count: bank pm runtime enabled count
+ * @mode_support: bank mode support.
+ * @freq_base: reference frequency for bank init
+ * @turn_freq_base: refenrece frequency for 2-line turn point
+ * @vboot: voltage request for bank init01 only
+ * @opp_dfreq: default opp frequency table
+ * @opp_dvolt: default opp voltage table
+ * @freq_pct: frequency percent table for bank init
+ * @volt: bank voltage table
+ * @volt_step: bank voltage step
+ * @volt_base: bank voltage base
+ * @volt_flags: bank voltage flags
+ * @vmax: bank voltage maximum
+ * @vmin: bank voltage minimum
+ * @age_config: bank age configuration
+ * @age_voffset_in: bank age voltage offset
+ * @dc_config: bank dc configuration
+ * @dc_voffset_in: bank dc voltage offset
+ * @dvt_fixed: bank dvt fixed value
+ * @vco: bank VCO value
+ * @chk_shift: bank chicken shift
+ * @core_sel: bank selection
+ * @opp_count: bank opp count
+ * @int_st: bank interrupt identification
+ * @sw_id: bank software identification
+ * @cpu_id: cpu core id for SVS CPU bank use only
+ * @ctl0: TS-x selection
+ * @temp: bank temperature
+ * @tzone_htemp: thermal zone high temperature threshold
+ * @tzone_htemp_voffset: thermal zone high temperature voltage offset
+ * @tzone_ltemp: thermal zone low temperature threshold
+ * @tzone_ltemp_voffset: thermal zone low temperature voltage offset
+ * @bts: svs efuse data
+ * @mts: svs efuse data
+ * @bdes: svs efuse data
+ * @mdes: svs efuse data
+ * @mtdes: svs efuse data
+ * @dcbdet: svs efuse data
+ * @dcmdet: svs efuse data
+ * @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank
+ * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank
+ *
+ * Svs bank will generate suitalbe voltages by below general math equation
+ * and provide these voltages to opp voltage table.
+ *
+ * opp_volt[i] = (volt[i] * volt_step) + volt_base;
+ */
+struct svs_bank {
+ struct device *dev;
+ struct device *opp_dev;
+ struct completion init_completion;
+ struct regulator *buck;
+ struct thermal_zone_device *tzd;
+ struct mutex lock; /* lock to protect voltage update process */
+ void (*set_freq_pct)(struct svs_platform *svsp);
+ void (*get_volts)(struct svs_platform *svsp);
+ char *name;
+ char *buck_name;
+ char *tzone_name;
+ enum svsb_phase phase;
+ s32 volt_od;
+ u32 reg_data[SVSB_PHASE_MAX][SVS_REG_MAX];
+ u32 pm_runtime_enabled_count;
+ u32 mode_support;
+ u32 freq_base;
+ u32 turn_freq_base;
+ u32 vboot;
+ u32 opp_dfreq[MAX_OPP_ENTRIES];
+ u32 opp_dvolt[MAX_OPP_ENTRIES];
+ u32 freq_pct[MAX_OPP_ENTRIES];
+ u32 volt[MAX_OPP_ENTRIES];
+ u32 volt_step;
+ u32 volt_base;
+ u32 volt_flags;
+ u32 vmax;
+ u32 vmin;
+ u32 age_config;
+ u32 age_voffset_in;
+ u32 dc_config;
+ u32 dc_voffset_in;
+ u32 dvt_fixed;
+ u32 vco;
+ u32 chk_shift;
+ u32 core_sel;
+ u32 opp_count;
+ u32 int_st;
+ u32 sw_id;
+ u32 cpu_id;
+ u32 ctl0;
+ u32 temp;
+ u32 tzone_htemp;
+ u32 tzone_htemp_voffset;
+ u32 tzone_ltemp;
+ u32 tzone_ltemp_voffset;
+ u32 bts;
+ u32 mts;
+ u32 bdes;
+ u32 mdes;
+ u32 mtdes;
+ u32 dcbdet;
+ u32 dcmdet;
+ u32 turn_pt;
+ u32 type;
+};
+
+static u32 percent(u32 numerator, u32 denominator)
+{
+ /* If not divide 1000, "numerator * 100" will have data overflow. */
+ numerator /= 1000;
+ denominator /= 1000;
+
+ return DIV_ROUND_UP(numerator * 100, denominator);
+}
+
+static u32 svs_readl_relaxed(struct svs_platform *svsp, enum svs_reg_index rg_i)
+{
+ return readl_relaxed(svsp->base + svsp->regs[rg_i]);
+}
+
+static void svs_writel_relaxed(struct svs_platform *svsp, u32 val,
+ enum svs_reg_index rg_i)
+{
+ writel_relaxed(val, svsp->base + svsp->regs[rg_i]);
+}
+
+static void svs_switch_bank(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+
+ svs_writel_relaxed(svsp, svsb->core_sel, CORESEL);
+}
+
+static u32 svs_bank_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
+ u32 svsb_volt_base)
+{
+ return (svsb_volt * svsb_volt_step) + svsb_volt_base;
+}
+
+static u32 svs_opp_volt_to_bank_volt(u32 opp_u_volt, u32 svsb_volt_step,
+ u32 svsb_volt_base)
+{
+ return (opp_u_volt - svsb_volt_base) / svsb_volt_step;
+}
+
+static int svs_sync_bank_volts_from_opp(struct svs_bank *svsb)
+{
+ struct dev_pm_opp *opp;
+ u32 i, opp_u_volt;
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
+ svsb->opp_dfreq[i],
+ true);
+ if (IS_ERR(opp)) {
+ dev_err(svsb->dev, "cannot find freq = %u (%ld)\n",
+ svsb->opp_dfreq[i], PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ opp_u_volt = dev_pm_opp_get_voltage(opp);
+ svsb->volt[i] = svs_opp_volt_to_bank_volt(opp_u_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ dev_pm_opp_put(opp);
+ }
+
+ return 0;
+}
+
+static int svs_adjust_pm_opp_volts(struct svs_bank *svsb)
+{
+ int ret = -EPERM, tzone_temp = 0;
+ u32 i, svsb_volt, opp_volt, temp_voffset = 0, opp_start, opp_stop;
+
+ mutex_lock(&svsb->lock);
+
+ /*
+ * 2-line bank updates its corresponding opp volts.
+ * 1-line bank updates all opp volts.
+ */
+ if (svsb->type == SVSB_HIGH) {
+ opp_start = 0;
+ opp_stop = svsb->turn_pt;
+ } else if (svsb->type == SVSB_LOW) {
+ opp_start = svsb->turn_pt;
+ opp_stop = svsb->opp_count;
+ } else {
+ opp_start = 0;
+ opp_stop = svsb->opp_count;
+ }
+
+ /* Get thermal effect */
+ if (svsb->phase == SVSB_PHASE_MON) {
+ ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
+ if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND &&
+ svsb->temp < SVSB_TEMP_LOWER_BOUND)) {
+ dev_err(svsb->dev, "%s: %d (0x%x), run default volts\n",
+ svsb->tzone_name, ret, svsb->temp);
+ svsb->phase = SVSB_PHASE_ERROR;
+ }
+
+ if (tzone_temp >= svsb->tzone_htemp)
+ temp_voffset += svsb->tzone_htemp_voffset;
+ else if (tzone_temp <= svsb->tzone_ltemp)
+ temp_voffset += svsb->tzone_ltemp_voffset;
+
+ /* 2-line bank update all opp volts when running mon mode */
+ if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+ opp_start = 0;
+ opp_stop = svsb->opp_count;
+ }
+ }
+
+ /* vmin <= svsb_volt (opp_volt) <= default opp voltage */
+ for (i = opp_start; i < opp_stop; i++) {
+ switch (svsb->phase) {
+ case SVSB_PHASE_ERROR:
+ opp_volt = svsb->opp_dvolt[i];
+ break;
+ case SVSB_PHASE_INIT01:
+ /* do nothing */
+ goto unlock_mutex;
+ case SVSB_PHASE_INIT02:
+ svsb_volt = max(svsb->volt[i], svsb->vmin);
+ opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ break;
+ case SVSB_PHASE_MON:
+ svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin);
+ opp_volt = svs_bank_volt_to_opp_volt(svsb_volt,
+ svsb->volt_step,
+ svsb->volt_base);
+ break;
+ default:
+ dev_err(svsb->dev, "unknown phase: %u\n", svsb->phase);
+ ret = -EINVAL;
+ goto unlock_mutex;
+ }
+
+ opp_volt = min(opp_volt, svsb->opp_dvolt[i]);
+ ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
+ svsb->opp_dfreq[i],
+ opp_volt, opp_volt,
+ svsb->opp_dvolt[i]);
+ if (ret) {
+ dev_err(svsb->dev, "set %uuV fail: %d\n",
+ opp_volt, ret);
+ goto unlock_mutex;
+ }
+ }
+
+unlock_mutex:
+ mutex_unlock(&svsb->lock);
+
+ return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int svs_dump_debug_show(struct seq_file *m, void *p)
+{
+ struct svs_platform *svsp = (struct svs_platform *)m->private;
+ struct svs_bank *svsb;
+ unsigned long svs_reg_addr;
+ u32 idx, i, j, bank_id;
+
+ for (i = 0; i < svsp->efuse_max; i++)
+ if (svsp->efuse && svsp->efuse[i])
+ seq_printf(m, "M_HW_RES%d = 0x%08x\n",
+ i, svsp->efuse[i]);
+
+ for (i = 0; i < svsp->tefuse_max; i++)
+ if (svsp->tefuse)
+ seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n",
+ i, svsp->tefuse[i]);
+
+ for (bank_id = 0, idx = 0; idx < svsp->bank_max; idx++, bank_id++) {
+ svsb = &svsp->banks[idx];
+
+ for (i = SVSB_PHASE_INIT01; i <= SVSB_PHASE_MON; i++) {
+ seq_printf(m, "Bank_number = %u\n", bank_id);
+
+ if (i == SVSB_PHASE_INIT01 || i == SVSB_PHASE_INIT02)
+ seq_printf(m, "mode = init%d\n", i);
+ else if (i == SVSB_PHASE_MON)
+ seq_puts(m, "mode = mon\n");
+ else
+ seq_puts(m, "mode = error\n");
+
+ for (j = DESCHAR; j < SVS_REG_MAX; j++) {
+ svs_reg_addr = (unsigned long)(svsp->base +
+ svsp->regs[j]);
+ seq_printf(m, "0x%08lx = 0x%08x\n",
+ svs_reg_addr, svsb->reg_data[i][j]);
+ }
+ }
+ }
+
+ return 0;
+}
+
+debug_fops_ro(dump);
+
+static int svs_enable_debug_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+
+ switch (svsb->phase) {
+ case SVSB_PHASE_ERROR:
+ seq_puts(m, "disabled\n");
+ break;
+ case SVSB_PHASE_INIT01:
+ seq_puts(m, "init1\n");
+ break;
+ case SVSB_PHASE_INIT02:
+ seq_puts(m, "init2\n");
+ break;
+ case SVSB_PHASE_MON:
+ seq_puts(m, "mon mode\n");
+ break;
+ default:
+ seq_puts(m, "unknown\n");
+ break;
+ }
+
+ return 0;
+}
+
+static ssize_t svs_enable_debug_write(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct svs_bank *svsb = file_inode(filp)->i_private;
+ struct svs_platform *svsp = dev_get_drvdata(svsb->dev);
+ unsigned long flags;
+ int enabled, ret;
+ char *buf = NULL;
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+
+ buf = (char *)memdup_user_nul(buffer, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ ret = kstrtoint(buf, 10, &enabled);
+ if (ret)
+ return ret;
+
+ if (!enabled) {
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svsb->mode_support = SVSB_MODE_ALL_DISABLE;
+ svs_switch_bank(svsp);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_adjust_pm_opp_volts(svsb);
+ }
+
+ kfree(buf);
+
+ return count;
+}
+
+debug_fops_rw(enable);
+
+static int svs_status_debug_show(struct seq_file *m, void *v)
+{
+ struct svs_bank *svsb = (struct svs_bank *)m->private;
+ struct dev_pm_opp *opp;
+ int tzone_temp = 0, ret;
+ u32 i;
+
+ ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp);
+ if (ret)
+ seq_printf(m, "%s: temperature ignore, turn_pt = %u\n",
+ svsb->name, svsb->turn_pt);
+ else
+ seq_printf(m, "%s: temperature = %d, turn_pt = %u\n",
+ svsb->name, tzone_temp, svsb->turn_pt);
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ opp = dev_pm_opp_find_freq_exact(svsb->opp_dev,
+ svsb->opp_dfreq[i], true);
+ if (IS_ERR(opp)) {
+ seq_printf(m, "%s: cannot find freq = %u (%ld)\n",
+ svsb->name, svsb->opp_dfreq[i],
+ PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ seq_printf(m, "opp_freq[%02u]: %u, opp_volt[%02u]: %lu, ",
+ i, svsb->opp_dfreq[i], i,
+ dev_pm_opp_get_voltage(opp));
+ seq_printf(m, "svsb_volt[%02u]: 0x%x, freq_pct[%02u]: %u\n",
+ i, svsb->volt[i], i, svsb->freq_pct[i]);
+ dev_pm_opp_put(opp);
+ }
+
+ return 0;
+}
+
+debug_fops_ro(status);
+
+static int svs_create_debug_cmds(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ struct dentry *svs_dir, *svsb_dir, *file_entry;
+ const char *d = "/sys/kernel/debug/svs";
+ u32 i, idx;
+
+ struct svs_dentry {
+ const char *name;
+ const struct file_operations *fops;
+ };
+
+ struct svs_dentry svs_entries[] = {
+ svs_dentry_data(dump),
+ };
+
+ struct svs_dentry svsb_entries[] = {
+ svs_dentry_data(enable),
+ svs_dentry_data(status),
+ };
+
+ svs_dir = debugfs_create_dir("svs", NULL);
+ if (IS_ERR(svs_dir)) {
+ dev_err(svsp->dev, "cannot create %s: %ld\n",
+ d, PTR_ERR(svs_dir));
+ return PTR_ERR(svs_dir);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(svs_entries); i++) {
+ file_entry = debugfs_create_file(svs_entries[i].name, 0664,
+ svs_dir, svsp,
+ svs_entries[i].fops);
+ if (IS_ERR(file_entry)) {
+ dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
+ d, svs_entries[i].name, PTR_ERR(file_entry));
+ return PTR_ERR(file_entry);
+ }
+ }
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
+ continue;
+
+ svsb_dir = debugfs_create_dir(svsb->name, svs_dir);
+ if (IS_ERR(svsb_dir)) {
+ dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
+ d, svsb->name, PTR_ERR(svsb_dir));
+ return PTR_ERR(svsb_dir);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(svsb_entries); i++) {
+ file_entry = debugfs_create_file(svsb_entries[i].name,
+ 0664, svsb_dir, svsb,
+ svsb_entries[i].fops);
+ if (IS_ERR(file_entry)) {
+ dev_err(svsp->dev, "no %s/%s/%s?: %ld\n",
+ d, svsb->name, svsb_entries[i].name,
+ PTR_ERR(file_entry));
+ return PTR_ERR(file_entry);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
+{
+ u32 vx;
+
+ if (v0 == v1 || f0 == f1)
+ return v0;
+
+ /* *100 to have decimal fraction factor */
+ vx = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
+
+ return DIV_ROUND_UP(vx, 100);
+}
+
+static void svs_get_bank_volts_v3(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ u32 i, j, *vop, vop74, vop30, turn_pt = svsb->turn_pt;
+ u32 b_sft, shift_byte = 0, opp_start = 0, opp_stop = 0;
+ u32 middle_index = (svsb->opp_count / 2);
+
+ if (svsb->phase == SVSB_PHASE_MON &&
+ svsb->volt_flags & SVSB_MON_VOLT_IGNORE)
+ return;
+
+ vop74 = svs_readl_relaxed(svsp, VOP74);
+ vop30 = svs_readl_relaxed(svsp, VOP30);
+
+ /* Target is to set svsb->volt[] by algorithm */
+ if (turn_pt < middle_index) {
+ if (svsb->type == SVSB_HIGH) {
+ /* volt[0] ~ volt[turn_pt - 1] */
+ for (i = 0; i < turn_pt; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ vop = (shift_byte < REG_BYTES) ? &vop30 :
+ &vop74;
+ svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+ shift_byte++;
+ }
+ } else if (svsb->type == SVSB_LOW) {
+ /* volt[turn_pt] + volt[j] ~ volt[opp_count - 1] */
+ j = svsb->opp_count - 7;
+ svsb->volt[turn_pt] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
+ shift_byte++;
+ for (i = j; i < svsb->opp_count; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ vop = (shift_byte < REG_BYTES) ? &vop30 :
+ &vop74;
+ svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+ shift_byte++;
+ }
+
+ /* volt[turn_pt + 1] ~ volt[j - 1] by interpolate */
+ for (i = turn_pt + 1; i < j; i++)
+ svsb->volt[i] = interpolate(svsb->freq_pct[turn_pt],
+ svsb->freq_pct[j],
+ svsb->volt[turn_pt],
+ svsb->volt[j],
+ svsb->freq_pct[i]);
+ }
+ } else {
+ if (svsb->type == SVSB_HIGH) {
+ /* volt[0] + volt[j] ~ volt[turn_pt - 1] */
+ j = turn_pt - 7;
+ svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, vop30);
+ shift_byte++;
+ for (i = j; i < turn_pt; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ vop = (shift_byte < REG_BYTES) ? &vop30 :
+ &vop74;
+ svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+ shift_byte++;
+ }
+
+ /* volt[1] ~ volt[j - 1] by interpolate */
+ for (i = 1; i < j; i++)
+ svsb->volt[i] = interpolate(svsb->freq_pct[0],
+ svsb->freq_pct[j],
+ svsb->volt[0],
+ svsb->volt[j],
+ svsb->freq_pct[i]);
+ } else if (svsb->type == SVSB_LOW) {
+ /* volt[turn_pt] ~ volt[opp_count - 1] */
+ for (i = turn_pt; i < svsb->opp_count; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ vop = (shift_byte < REG_BYTES) ? &vop30 :
+ &vop74;
+ svsb->volt[i] = (*vop >> b_sft) & GENMASK(7, 0);
+ shift_byte++;
+ }
+ }
+ }
+
+ if (svsb->type == SVSB_HIGH) {
+ opp_start = 0;
+ opp_stop = svsb->turn_pt;
+ } else if (svsb->type == SVSB_LOW) {
+ opp_start = svsb->turn_pt;
+ opp_stop = svsb->opp_count;
+ }
+
+ for (i = opp_start; i < opp_stop; i++)
+ if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT)
+ svsb->volt[i] -= svsb->dvt_fixed;
+}
+
+static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ u32 i, j, *freq_pct, freq_pct74 = 0, freq_pct30 = 0;
+ u32 b_sft, shift_byte = 0, turn_pt;
+ u32 middle_index = (svsb->opp_count / 2);
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ if (svsb->opp_dfreq[i] <= svsb->turn_freq_base) {
+ svsb->turn_pt = i;
+ break;
+ }
+ }
+
+ turn_pt = svsb->turn_pt;
+
+ /* Target is to fill out freq_pct74 / freq_pct30 by algorithm */
+ if (turn_pt < middle_index) {
+ if (svsb->type == SVSB_HIGH) {
+ /*
+ * If we don't handle this situation,
+ * SVSB_HIGH's FREQPCT74 / FREQPCT30 would keep "0"
+ * and this leads SVSB_LOW to work abnormally.
+ */
+ if (turn_pt == 0)
+ freq_pct30 = svsb->freq_pct[0];
+
+ /* freq_pct[0] ~ freq_pct[turn_pt - 1] */
+ for (i = 0; i < turn_pt; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ freq_pct = (shift_byte < REG_BYTES) ?
+ &freq_pct30 : &freq_pct74;
+ *freq_pct |= (svsb->freq_pct[i] << b_sft);
+ shift_byte++;
+ }
+ } else if (svsb->type == SVSB_LOW) {
+ /*
+ * freq_pct[turn_pt] +
+ * freq_pct[opp_count - 7] ~ freq_pct[opp_count -1]
+ */
+ freq_pct30 = svsb->freq_pct[turn_pt];
+ shift_byte++;
+ j = svsb->opp_count - 7;
+ for (i = j; i < svsb->opp_count; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ freq_pct = (shift_byte < REG_BYTES) ?
+ &freq_pct30 : &freq_pct74;
+ *freq_pct |= (svsb->freq_pct[i] << b_sft);
+ shift_byte++;
+ }
+ }
+ } else {
+ if (svsb->type == SVSB_HIGH) {
+ /*
+ * freq_pct[0] +
+ * freq_pct[turn_pt - 7] ~ freq_pct[turn_pt - 1]
+ */
+ freq_pct30 = svsb->freq_pct[0];
+ shift_byte++;
+ j = turn_pt - 7;
+ for (i = j; i < turn_pt; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ freq_pct = (shift_byte < REG_BYTES) ?
+ &freq_pct30 : &freq_pct74;
+ *freq_pct |= (svsb->freq_pct[i] << b_sft);
+ shift_byte++;
+ }
+ } else if (svsb->type == SVSB_LOW) {
+ /* freq_pct[turn_pt] ~ freq_pct[opp_count - 1] */
+ for (i = turn_pt; i < svsb->opp_count; i++) {
+ b_sft = BITS8 * (shift_byte % REG_BYTES);
+ freq_pct = (shift_byte < REG_BYTES) ?
+ &freq_pct30 : &freq_pct74;
+ *freq_pct |= (svsb->freq_pct[i] << b_sft);
+ shift_byte++;
+ }
+ }
+ }
+
+ svs_writel_relaxed(svsp, freq_pct74, FREQPCT74);
+ svs_writel_relaxed(svsp, freq_pct30, FREQPCT30);
+}
+
+static void svs_get_bank_volts_v2(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ u32 temp, i;
+
+ temp = svs_readl_relaxed(svsp, VOP74);
+ svsb->volt[14] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp);
+ svsb->volt[12] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp);
+ svsb->volt[10] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp);
+ svsb->volt[8] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp);
+
+ temp = svs_readl_relaxed(svsp, VOP30);
+ svsb->volt[6] = FIELD_GET(SVSB_VOPS_FLD_VOP3_7, temp);
+ svsb->volt[4] = FIELD_GET(SVSB_VOPS_FLD_VOP2_6, temp);
+ svsb->volt[2] = FIELD_GET(SVSB_VOPS_FLD_VOP1_5, temp);
+ svsb->volt[0] = FIELD_GET(SVSB_VOPS_FLD_VOP0_4, temp);
+
+ for (i = 0; i <= 12; i += 2)
+ svsb->volt[i + 1] = interpolate(svsb->freq_pct[i],
+ svsb->freq_pct[i + 2],
+ svsb->volt[i],
+ svsb->volt[i + 2],
+ svsb->freq_pct[i + 1]);
+
+ svsb->volt[15] = interpolate(svsb->freq_pct[12],
+ svsb->freq_pct[14],
+ svsb->volt[12],
+ svsb->volt[14],
+ svsb->freq_pct[15]);
+
+ for (i = 0; i < svsb->opp_count; i++)
+ svsb->volt[i] += svsb->volt_od;
+}
+
+static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ u32 freqpct74_val, freqpct30_val;
+
+ freqpct74_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[8]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[10]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[12]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[14]);
+
+ freqpct30_val = FIELD_PREP(SVSB_FREQPCTS_FLD_PCT0_4, svsb->freq_pct[0]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT1_5, svsb->freq_pct[2]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT2_6, svsb->freq_pct[4]) |
+ FIELD_PREP(SVSB_FREQPCTS_FLD_PCT3_7, svsb->freq_pct[6]);
+
+ svs_writel_relaxed(svsp, freqpct74_val, FREQPCT74);
+ svs_writel_relaxed(svsp, freqpct30_val, FREQPCT30);
+}
+
+static void svs_set_bank_phase(struct svs_platform *svsp,
+ enum svsb_phase target_phase)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ u32 des_char, temp_char, det_char, limit_vals, init2vals, ts_calcs;
+
+ svs_switch_bank(svsp);
+
+ des_char = FIELD_PREP(SVSB_DESCHAR_FLD_BDES, svsb->bdes) |
+ FIELD_PREP(SVSB_DESCHAR_FLD_MDES, svsb->mdes);
+ svs_writel_relaxed(svsp, des_char, DESCHAR);
+
+ temp_char = FIELD_PREP(SVSB_TEMPCHAR_FLD_VCO, svsb->vco) |
+ FIELD_PREP(SVSB_TEMPCHAR_FLD_MTDES, svsb->mtdes) |
+ FIELD_PREP(SVSB_TEMPCHAR_FLD_DVT_FIXED, svsb->dvt_fixed);
+ svs_writel_relaxed(svsp, temp_char, TEMPCHAR);
+
+ det_char = FIELD_PREP(SVSB_DETCHAR_FLD_DCBDET, svsb->dcbdet) |
+ FIELD_PREP(SVSB_DETCHAR_FLD_DCMDET, svsb->dcmdet);
+ svs_writel_relaxed(svsp, det_char, DETCHAR);
+
+ svs_writel_relaxed(svsp, svsb->dc_config, DCCONFIG);
+ svs_writel_relaxed(svsp, svsb->age_config, AGECONFIG);
+ svs_writel_relaxed(svsp, SVSB_RUNCONFIG_DEFAULT, RUNCONFIG);
+
+ svsb->set_freq_pct(svsp);
+
+ limit_vals = FIELD_PREP(SVSB_LIMITVALS_FLD_DTLO, SVSB_VAL_DTLO) |
+ FIELD_PREP(SVSB_LIMITVALS_FLD_DTHI, SVSB_VAL_DTHI) |
+ FIELD_PREP(SVSB_LIMITVALS_FLD_VMIN, svsb->vmin) |
+ FIELD_PREP(SVSB_LIMITVALS_FLD_VMAX, svsb->vmax);
+ svs_writel_relaxed(svsp, limit_vals, LIMITVALS);
+
+ svs_writel_relaxed(svsp, SVSB_DET_WINDOW, DETWINDOW);
+ svs_writel_relaxed(svsp, SVSB_DET_MAX, CONFIG);
+ svs_writel_relaxed(svsp, svsb->chk_shift, CHKSHIFT);
+ svs_writel_relaxed(svsp, svsb->ctl0, CTL0);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+
+ switch (target_phase) {
+ case SVSB_PHASE_INIT01:
+ svs_writel_relaxed(svsp, svsb->vboot, VBOOT);
+ svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_INIT01, SVSEN);
+ break;
+ case SVSB_PHASE_INIT02:
+ init2vals = FIELD_PREP(SVSB_INIT2VALS_FLD_AGEVOFFSETIN, svsb->age_voffset_in) |
+ FIELD_PREP(SVSB_INIT2VALS_FLD_DCVOFFSETIN, svsb->dc_voffset_in);
+ svs_writel_relaxed(svsp, SVSB_INTEN_INIT0x, INTEN);
+ svs_writel_relaxed(svsp, init2vals, INIT2VALS);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_INIT02, SVSEN);
+ break;
+ case SVSB_PHASE_MON:
+ ts_calcs = FIELD_PREP(SVSB_TSCALCS_FLD_BTS, svsb->bts) |
+ FIELD_PREP(SVSB_TSCALCS_FLD_MTS, svsb->mts);
+ svs_writel_relaxed(svsp, ts_calcs, TSCALCS);
+ svs_writel_relaxed(svsp, SVSB_INTEN_MONVOPEN, INTEN);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_MON, SVSEN);
+ break;
+ default:
+ dev_err(svsb->dev, "requested unknown target phase: %u\n",
+ target_phase);
+ break;
+ }
+}
+
+static inline void svs_save_bank_register_data(struct svs_platform *svsp,
+ enum svsb_phase phase)
+{
+ struct svs_bank *svsb = svsp->pbank;
+ enum svs_reg_index rg_i;
+
+ for (rg_i = DESCHAR; rg_i < SVS_REG_MAX; rg_i++)
+ svsb->reg_data[phase][rg_i] = svs_readl_relaxed(svsp, rg_i);
+}
+
+static inline void svs_error_isr_handler(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+
+ dev_err(svsb->dev, "%s: CORESEL = 0x%08x\n",
+ __func__, svs_readl_relaxed(svsp, CORESEL));
+ dev_err(svsb->dev, "SVSEN = 0x%08x, INTSTS = 0x%08x\n",
+ svs_readl_relaxed(svsp, SVSEN),
+ svs_readl_relaxed(svsp, INTSTS));
+ dev_err(svsb->dev, "SMSTATE0 = 0x%08x, SMSTATE1 = 0x%08x\n",
+ svs_readl_relaxed(svsp, SMSTATE0),
+ svs_readl_relaxed(svsp, SMSTATE1));
+ dev_err(svsb->dev, "TEMP = 0x%08x\n", svs_readl_relaxed(svsp, TEMP));
+
+ svs_save_bank_register_data(svsp, SVSB_PHASE_ERROR);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+}
+
+static inline void svs_init01_isr_handler(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+
+ dev_info(svsb->dev, "%s: VDN74~30:0x%08x~0x%08x, DC:0x%08x\n",
+ __func__, svs_readl_relaxed(svsp, VDESIGN74),
+ svs_readl_relaxed(svsp, VDESIGN30),
+ svs_readl_relaxed(svsp, DCVALUES));
+
+ svs_save_bank_register_data(svsp, SVSB_PHASE_INIT01);
+
+ svsb->phase = SVSB_PHASE_INIT01;
+ svsb->dc_voffset_in = ~(svs_readl_relaxed(svsp, DCVALUES) &
+ GENMASK(15, 0)) + 1;
+ if (svsb->volt_flags & SVSB_INIT01_VOLT_IGNORE ||
+ (svsb->dc_voffset_in & SVSB_DC_SIGNED_BIT &&
+ svsb->volt_flags & SVSB_INIT01_VOLT_INC_ONLY))
+ svsb->dc_voffset_in = 0;
+
+ svsb->age_voffset_in = svs_readl_relaxed(svsp, AGEVALUES) &
+ GENMASK(15, 0);
+
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS);
+ svsb->core_sel &= ~SVSB_DET_CLK_EN;
+}
+
+static inline void svs_init02_isr_handler(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+
+ dev_info(svsb->dev, "%s: VOP74~30:0x%08x~0x%08x, DC:0x%08x\n",
+ __func__, svs_readl_relaxed(svsp, VOP74),
+ svs_readl_relaxed(svsp, VOP30),
+ svs_readl_relaxed(svsp, DCVALUES));
+
+ svs_save_bank_register_data(svsp, SVSB_PHASE_INIT02);
+
+ svsb->phase = SVSB_PHASE_INIT02;
+ svsb->get_volts(svsp);
+
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_F0_COMPLETE, INTSTS);
+}
+
+static inline void svs_mon_mode_isr_handler(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb = svsp->pbank;
+
+ svs_save_bank_register_data(svsp, SVSB_PHASE_MON);
+
+ svsb->phase = SVSB_PHASE_MON;
+ svsb->get_volts(svsp);
+
+ svsb->temp = svs_readl_relaxed(svsp, TEMP) & GENMASK(7, 0);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_FLD_MONVOP, INTSTS);
+}
+
+static irqreturn_t svs_isr(int irq, void *data)
+{
+ struct svs_platform *svsp = data;
+ struct svs_bank *svsb = NULL;
+ unsigned long flags;
+ u32 idx, int_sts, svs_en;
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+ WARN(!svsb, "%s: svsb(%s) is null", __func__, svsb->name);
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+
+ /* Find out which svs bank fires interrupt */
+ if (svsb->int_st & svs_readl_relaxed(svsp, INTST)) {
+ spin_unlock_irqrestore(&svs_lock, flags);
+ continue;
+ }
+
+ svs_switch_bank(svsp);
+ int_sts = svs_readl_relaxed(svsp, INTSTS);
+ svs_en = svs_readl_relaxed(svsp, SVSEN);
+
+ if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
+ svs_en == SVSB_PTPEN_INIT01)
+ svs_init01_isr_handler(svsp);
+ else if (int_sts == SVSB_INTSTS_F0_COMPLETE &&
+ svs_en == SVSB_PTPEN_INIT02)
+ svs_init02_isr_handler(svsp);
+ else if (int_sts & SVSB_INTSTS_FLD_MONVOP)
+ svs_mon_mode_isr_handler(svsp);
+ else
+ svs_error_isr_handler(svsp);
+
+ spin_unlock_irqrestore(&svs_lock, flags);
+ break;
+ }
+
+ svs_adjust_pm_opp_volts(svsb);
+
+ if (svsb->phase == SVSB_PHASE_INIT01 ||
+ svsb->phase == SVSB_PHASE_INIT02)
+ complete(&svsb->init_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int svs_init01(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ unsigned long flags, time_left;
+ bool search_done;
+ int ret = 0, r;
+ u32 opp_freq, opp_vboot, buck_volt, idx, i;
+
+ /* Keep CPUs' core power on for svs_init01 initialization */
+ cpuidle_pause_and_lock();
+
+ /* Svs bank init01 preparation - power enable */
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT01))
+ continue;
+
+ ret = regulator_enable(svsb->buck);
+ if (ret) {
+ dev_err(svsb->dev, "%s enable fail: %d\n",
+ svsb->buck_name, ret);
+ goto svs_init01_resume_cpuidle;
+ }
+
+ /* Some buck doesn't support mode change. Show fail msg only */
+ ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST);
+ if (ret)
+ dev_notice(svsb->dev, "set fast mode fail: %d\n", ret);
+
+ if (svsb->volt_flags & SVSB_INIT01_PD_REQ) {
+ if (!pm_runtime_enabled(svsb->opp_dev)) {
+ pm_runtime_enable(svsb->opp_dev);
+ svsb->pm_runtime_enabled_count++;
+ }
+
+ ret = pm_runtime_resume_and_get(svsb->opp_dev);
+ if (ret < 0) {
+ dev_err(svsb->dev, "mtcmos on fail: %d\n", ret);
+ goto svs_init01_resume_cpuidle;
+ }
+ }
+ }
+
+ /*
+ * Svs bank init01 preparation - vboot voltage adjustment
+ * Sometimes two svs banks use the same buck. Therefore,
+ * we have to set each svs bank to target voltage(vboot) first.
+ */
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT01))
+ continue;
+
+ /*
+ * Find the fastest freq that can be run at vboot and
+ * fix to that freq until svs_init01 is done.
+ */
+ search_done = false;
+ opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ opp_freq = svsb->opp_dfreq[i];
+ if (!search_done && svsb->opp_dvolt[i] <= opp_vboot) {
+ ret = dev_pm_opp_adjust_voltage(svsb->opp_dev,
+ opp_freq,
+ opp_vboot,
+ opp_vboot,
+ opp_vboot);
+ if (ret) {
+ dev_err(svsb->dev,
+ "set opp %uuV vboot fail: %d\n",
+ opp_vboot, ret);
+ goto svs_init01_finish;
+ }
+
+ search_done = true;
+ } else {
+ ret = dev_pm_opp_disable(svsb->opp_dev,
+ svsb->opp_dfreq[i]);
+ if (ret) {
+ dev_err(svsb->dev,
+ "opp %uHz disable fail: %d\n",
+ svsb->opp_dfreq[i], ret);
+ goto svs_init01_finish;
+ }
+ }
+ }
+ }
+
+ /* Svs bank init01 begins */
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT01))
+ continue;
+
+ opp_vboot = svs_bank_volt_to_opp_volt(svsb->vboot,
+ svsb->volt_step,
+ svsb->volt_base);
+
+ buck_volt = regulator_get_voltage(svsb->buck);
+ if (buck_volt != opp_vboot) {
+ dev_err(svsb->dev,
+ "buck voltage: %uuV, expected vboot: %uuV\n",
+ buck_volt, opp_vboot);
+ ret = -EPERM;
+ goto svs_init01_finish;
+ }
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_set_bank_phase(svsp, SVSB_PHASE_INIT01);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ time_left = wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(5000));
+ if (!time_left) {
+ dev_err(svsb->dev, "init01 completion timeout\n");
+ ret = -EBUSY;
+ goto svs_init01_finish;
+ }
+ }
+
+svs_init01_finish:
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT01))
+ continue;
+
+ for (i = 0; i < svsb->opp_count; i++) {
+ r = dev_pm_opp_enable(svsb->opp_dev,
+ svsb->opp_dfreq[i]);
+ if (r)
+ dev_err(svsb->dev, "opp %uHz enable fail: %d\n",
+ svsb->opp_dfreq[i], r);
+ }
+
+ if (svsb->volt_flags & SVSB_INIT01_PD_REQ) {
+ r = pm_runtime_put_sync(svsb->opp_dev);
+ if (r)
+ dev_err(svsb->dev, "mtcmos off fail: %d\n", r);
+
+ if (svsb->pm_runtime_enabled_count > 0) {
+ pm_runtime_disable(svsb->opp_dev);
+ svsb->pm_runtime_enabled_count--;
+ }
+ }
+
+ r = regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL);
+ if (r)
+ dev_notice(svsb->dev, "set normal mode fail: %d\n", r);
+
+ r = regulator_disable(svsb->buck);
+ if (r)
+ dev_err(svsb->dev, "%s disable fail: %d\n",
+ svsb->buck_name, r);
+ }
+
+svs_init01_resume_cpuidle:
+ cpuidle_resume_and_unlock();
+
+ return ret;
+}
+
+static int svs_init02(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ unsigned long flags, time_left;
+ int ret;
+ u32 idx;
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT02))
+ continue;
+
+ reinit_completion(&svsb->init_completion);
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_set_bank_phase(svsp, SVSB_PHASE_INIT02);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ time_left = wait_for_completion_timeout(&svsb->init_completion,
+ msecs_to_jiffies(5000));
+ if (!time_left) {
+ dev_err(svsb->dev, "init02 completion timeout\n");
+ ret = -EBUSY;
+ goto out_of_init02;
+ }
+ }
+
+ /*
+ * 2-line high/low bank update its corresponding opp voltages only.
+ * Therefore, we sync voltages from opp for high/low bank voltages
+ * consistency.
+ */
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_INIT02))
+ continue;
+
+ if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) {
+ if (svs_sync_bank_volts_from_opp(svsb)) {
+ dev_err(svsb->dev, "sync volt fail\n");
+ ret = -EPERM;
+ goto out_of_init02;
+ }
+ }
+ }
+
+ return 0;
+
+out_of_init02:
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_switch_bank(svsp);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_adjust_pm_opp_volts(svsb);
+ }
+
+ return ret;
+}
+
+static void svs_mon_mode(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ unsigned long flags;
+ u32 idx;
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (!(svsb->mode_support & SVSB_MODE_MON))
+ continue;
+
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_set_bank_phase(svsp, SVSB_PHASE_MON);
+ spin_unlock_irqrestore(&svs_lock, flags);
+ }
+}
+
+static int svs_start(struct svs_platform *svsp)
+{
+ int ret;
+
+ ret = svs_init01(svsp);
+ if (ret)
+ return ret;
+
+ ret = svs_init02(svsp);
+ if (ret)
+ return ret;
+
+ svs_mon_mode(svsp);
+
+ return 0;
+}
+
+static int svs_suspend(struct device *dev)
+{
+ struct svs_platform *svsp = dev_get_drvdata(dev);
+ struct svs_bank *svsb;
+ unsigned long flags;
+ int ret;
+ u32 idx;
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ /* This might wait for svs_isr() process */
+ spin_lock_irqsave(&svs_lock, flags);
+ svsp->pbank = svsb;
+ svs_switch_bank(svsp);
+ svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN);
+ svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS);
+ spin_unlock_irqrestore(&svs_lock, flags);
+
+ svsb->phase = SVSB_PHASE_ERROR;
+ svs_adjust_pm_opp_volts(svsb);
+ }
+
+ ret = reset_control_assert(svsp->rst);
+ if (ret) {
+ dev_err(svsp->dev, "cannot assert reset %d\n", ret);
+ return ret;
+ }
+
+ clk_disable_unprepare(svsp->main_clk);
+
+ return 0;
+}
+
+static int svs_resume(struct device *dev)
+{
+ struct svs_platform *svsp = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(svsp->main_clk);
+ if (ret) {
+ dev_err(svsp->dev, "cannot enable main_clk, disable svs\n");
+ return ret;
+ }
+
+ ret = reset_control_deassert(svsp->rst);
+ if (ret) {
+ dev_err(svsp->dev, "cannot deassert reset %d\n", ret);
+ goto out_of_resume;
+ }
+
+ ret = svs_init02(svsp);
+ if (ret)
+ goto svs_resume_reset_assert;
+
+ svs_mon_mode(svsp);
+
+ return 0;
+
+svs_resume_reset_assert:
+ dev_err(svsp->dev, "assert reset: %d\n",
+ reset_control_assert(svsp->rst));
+
+out_of_resume:
+ clk_disable_unprepare(svsp->main_clk);
+ return ret;
+}
+
+static int svs_bank_resource_setup(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ int count, ret;
+ u32 idx, i;
+
+ dev_set_drvdata(svsp->dev, svsp);
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ switch (svsb->sw_id) {
+ case SVSB_CPU_LITTLE:
+ svsb->name = "SVSB_CPU_LITTLE";
+ break;
+ case SVSB_CPU_BIG:
+ svsb->name = "SVSB_CPU_BIG";
+ break;
+ case SVSB_CCI:
+ svsb->name = "SVSB_CCI";
+ break;
+ case SVSB_GPU:
+ if (svsb->type == SVSB_HIGH)
+ svsb->name = "SVSB_GPU_HIGH";
+ else if (svsb->type == SVSB_LOW)
+ svsb->name = "SVSB_GPU_LOW";
+ else
+ svsb->name = "SVSB_GPU";
+ break;
+ default:
+ dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ return -EINVAL;
+ }
+
+ svsb->dev = devm_kzalloc(svsp->dev, sizeof(*svsb->dev),
+ GFP_KERNEL);
+ if (!svsb->dev)
+ return -ENOMEM;
+
+ ret = dev_set_name(svsb->dev, "%s", svsb->name);
+ if (ret)
+ return ret;
+
+ dev_set_drvdata(svsb->dev, svsp);
+
+ ret = devm_pm_opp_of_add_table(svsb->opp_dev);
+ if (ret) {
+ dev_err(svsb->dev, "add opp table fail: %d\n", ret);
+ return ret;
+ }
+
+ mutex_init(&svsb->lock);
+ init_completion(&svsb->init_completion);
+
+ if (svsb->mode_support & SVSB_MODE_INIT01) {
+ svsb->buck = devm_regulator_get_optional(svsb->opp_dev,
+ svsb->buck_name);
+ if (IS_ERR(svsb->buck)) {
+ dev_err(svsb->dev, "cannot get \"%s-supply\"\n",
+ svsb->buck_name);
+ return PTR_ERR(svsb->buck);
+ }
+ }
+
+ if (svsb->mode_support & SVSB_MODE_MON) {
+ svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
+ if (IS_ERR(svsb->tzd)) {
+ dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n",
+ svsb->tzone_name);
+ return PTR_ERR(svsb->tzd);
+ }
+ }
+
+ count = dev_pm_opp_get_opp_count(svsb->opp_dev);
+ if (svsb->opp_count != count) {
+ dev_err(svsb->dev,
+ "opp_count not \"%u\" but get \"%d\"?\n",
+ svsb->opp_count, count);
+ return count;
+ }
+
+ for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
+ opp = dev_pm_opp_find_freq_floor(svsb->opp_dev, &freq);
+ if (IS_ERR(opp)) {
+ dev_err(svsb->dev, "cannot find freq = %ld\n",
+ PTR_ERR(opp));
+ return PTR_ERR(opp);
+ }
+
+ svsb->opp_dfreq[i] = freq;
+ svsb->opp_dvolt[i] = dev_pm_opp_get_voltage(opp);
+ svsb->freq_pct[i] = percent(svsb->opp_dfreq[i],
+ svsb->freq_base);
+ dev_pm_opp_put(opp);
+ }
+ }
+
+ return 0;
+}
+
+static int svs_thermal_efuse_get_data(struct svs_platform *svsp)
+{
+ struct nvmem_cell *cell;
+
+ /* Thermal efuse parsing */
+ cell = nvmem_cell_get(svsp->dev, "t-calibration-data");
+ if (IS_ERR_OR_NULL(cell)) {
+ dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell));
+ return PTR_ERR(cell);
+ }
+
+ svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max);
+ if (IS_ERR(svsp->tefuse)) {
+ dev_err(svsp->dev, "cannot read thermal efuse: %ld\n",
+ PTR_ERR(svsp->tefuse));
+ nvmem_cell_put(cell);
+ return PTR_ERR(svsp->tefuse);
+ }
+
+ svsp->tefuse_max /= sizeof(u32);
+ nvmem_cell_put(cell);
+
+ return 0;
+}
+
+static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ u32 idx, i, vmin, golden_temp;
+ int ret;
+
+ for (i = 0; i < svsp->efuse_max; i++)
+ if (svsp->efuse[i])
+ dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
+ i, svsp->efuse[i]);
+
+ if (!svsp->efuse[9]) {
+ dev_notice(svsp->dev, "svs_efuse[9] = 0x0?\n");
+ return false;
+ }
+
+ /* Svs efuse parsing */
+ vmin = (svsp->efuse[19] >> 4) & GENMASK(1, 0);
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (vmin == 0x1)
+ svsb->vmin = 0x1e;
+
+ if (svsb->type == SVSB_LOW) {
+ svsb->mtdes = svsp->efuse[10] & GENMASK(7, 0);
+ svsb->bdes = (svsp->efuse[10] >> 16) & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[10] >> 24) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[17]) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[17] >> 8) & GENMASK(7, 0);
+ } else if (svsb->type == SVSB_HIGH) {
+ svsb->mtdes = svsp->efuse[9] & GENMASK(7, 0);
+ svsb->bdes = (svsp->efuse[9] >> 16) & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[9] >> 24) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[17] >> 24) & GENMASK(7, 0);
+ }
+
+ svsb->vmax += svsb->dvt_fixed;
+ }
+
+ ret = svs_thermal_efuse_get_data(svsp);
+ if (ret)
+ return false;
+
+ for (i = 0; i < svsp->tefuse_max; i++)
+ if (svsp->tefuse[i] != 0)
+ break;
+
+ if (i == svsp->tefuse_max)
+ golden_temp = 50; /* All thermal efuse data are 0 */
+ else
+ golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0);
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mts = 500;
+ svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4;
+ }
+
+ return true;
+}
+
+static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp)
+{
+ struct svs_bank *svsb;
+ int format[6], x_roomt[6], o_vtsmcu[5], o_vtsabb, tb_roomt = 0;
+ int adc_ge_t, adc_oe_t, ge, oe, gain, degc_cali, adc_cali_en_t;
+ int o_slope, o_slope_sign, ts_id;
+ u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
+ int ret;
+
+ for (i = 0; i < svsp->efuse_max; i++)
+ if (svsp->efuse[i])
+ dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n",
+ i, svsp->efuse[i]);
+
+ if (!svsp->efuse[2]) {
+ dev_notice(svsp->dev, "svs_efuse[2] = 0x0?\n");
+ return false;
+ }
+
+ /* Svs efuse parsing */
+ ft_pgm = (svsp->efuse[0] >> 4) & GENMASK(3, 0);
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (ft_pgm <= 1)
+ svsb->volt_flags |= SVSB_INIT01_VOLT_IGNORE;
+
+ switch (svsb->sw_id) {
+ case SVSB_CPU_LITTLE:
+ svsb->bdes = svsp->efuse[16] & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[16] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[16] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[16] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = (svsp->efuse[17] >> 16) & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_od += 10;
+ else
+ svsb->volt_od += 2;
+ break;
+ case SVSB_CPU_BIG:
+ svsb->bdes = svsp->efuse[18] & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[18] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[18] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[18] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = svsp->efuse[17] & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_od += 15;
+ else
+ svsb->volt_od += 12;
+ break;
+ case SVSB_CCI:
+ svsb->bdes = svsp->efuse[4] & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[4] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[4] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[4] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = (svsp->efuse[5] >> 16) & GENMASK(7, 0);
+
+ if (ft_pgm <= 3)
+ svsb->volt_od += 10;
+ else
+ svsb->volt_od += 2;
+ break;
+ case SVSB_GPU:
+ svsb->bdes = svsp->efuse[6] & GENMASK(7, 0);
+ svsb->mdes = (svsp->efuse[6] >> 8) & GENMASK(7, 0);
+ svsb->dcbdet = (svsp->efuse[6] >> 16) & GENMASK(7, 0);
+ svsb->dcmdet = (svsp->efuse[6] >> 24) & GENMASK(7, 0);
+ svsb->mtdes = svsp->efuse[5] & GENMASK(7, 0);
+
+ if (ft_pgm >= 2) {
+ svsb->freq_base = 800000000; /* 800MHz */
+ svsb->dvt_fixed = 2;
+ }
+ break;
+ default:
+ dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ return false;
+ }
+ }
+
+ ret = svs_thermal_efuse_get_data(svsp);
+ if (ret)
+ return false;
+
+ /* Thermal efuse parsing */
+ adc_ge_t = (svsp->tefuse[1] >> 22) & GENMASK(9, 0);
+ adc_oe_t = (svsp->tefuse[1] >> 12) & GENMASK(9, 0);
+
+ o_vtsmcu[0] = (svsp->tefuse[0] >> 17) & GENMASK(8, 0);
+ o_vtsmcu[1] = (svsp->tefuse[0] >> 8) & GENMASK(8, 0);
+ o_vtsmcu[2] = svsp->tefuse[1] & GENMASK(8, 0);
+ o_vtsmcu[3] = (svsp->tefuse[2] >> 23) & GENMASK(8, 0);
+ o_vtsmcu[4] = (svsp->tefuse[2] >> 5) & GENMASK(8, 0);
+ o_vtsabb = (svsp->tefuse[2] >> 14) & GENMASK(8, 0);
+
+ degc_cali = (svsp->tefuse[0] >> 1) & GENMASK(5, 0);
+ adc_cali_en_t = svsp->tefuse[0] & BIT(0);
+ o_slope_sign = (svsp->tefuse[0] >> 7) & BIT(0);
+
+ ts_id = (svsp->tefuse[1] >> 9) & BIT(0);
+ o_slope = (svsp->tefuse[0] >> 26) & GENMASK(5, 0);
+
+ if (adc_cali_en_t == 1) {
+ if (!ts_id)
+ o_slope = 0;
+
+ if (adc_ge_t < 265 || adc_ge_t > 758 ||
+ adc_oe_t < 265 || adc_oe_t > 758 ||
+ o_vtsmcu[0] < -8 || o_vtsmcu[0] > 484 ||
+ o_vtsmcu[1] < -8 || o_vtsmcu[1] > 484 ||
+ o_vtsmcu[2] < -8 || o_vtsmcu[2] > 484 ||
+ o_vtsmcu[3] < -8 || o_vtsmcu[3] > 484 ||
+ o_vtsmcu[4] < -8 || o_vtsmcu[4] > 484 ||
+ o_vtsabb < -8 || o_vtsabb > 484 ||
+ degc_cali < 1 || degc_cali > 63) {
+ dev_err(svsp->dev, "bad thermal efuse, no mon mode\n");
+ goto remove_mt8183_svsb_mon_mode;
+ }
+ } else {
+ dev_err(svsp->dev, "no thermal efuse, no mon mode\n");
+ goto remove_mt8183_svsb_mon_mode;
+ }
+
+ ge = ((adc_ge_t - 512) * 10000) / 4096;
+ oe = (adc_oe_t - 512);
+ gain = (10000 + ge);
+
+ format[0] = (o_vtsmcu[0] + 3350 - oe);
+ format[1] = (o_vtsmcu[1] + 3350 - oe);
+ format[2] = (o_vtsmcu[2] + 3350 - oe);
+ format[3] = (o_vtsmcu[3] + 3350 - oe);
+ format[4] = (o_vtsmcu[4] + 3350 - oe);
+ format[5] = (o_vtsabb + 3350 - oe);
+
+ for (i = 0; i < 6; i++)
+ x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / gain;
+
+ temp0 = (10000 * 100000 / gain) * 15 / 18;
+
+ if (!o_slope_sign)
+ mts = (temp0 * 10) / (1534 + o_slope * 10);
+ else
+ mts = (temp0 * 10) / (1534 - o_slope * 10);
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mts = mts;
+
+ switch (svsb->sw_id) {
+ case SVSB_CPU_LITTLE:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVSB_CPU_BIG:
+ tb_roomt = x_roomt[4];
+ break;
+ case SVSB_CCI:
+ tb_roomt = x_roomt[3];
+ break;
+ case SVSB_GPU:
+ tb_roomt = x_roomt[1];
+ break;
+ default:
+ dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ goto remove_mt8183_svsb_mon_mode;
+ }
+
+ temp0 = (degc_cali * 10 / 2);
+ temp1 = ((10000 * 100000 / 4096 / gain) *
+ oe + tb_roomt * 10) * 15 / 18;
+
+ if (!o_slope_sign)
+ temp2 = temp1 * 100 / (1534 + o_slope * 10);
+ else
+ temp2 = temp1 * 100 / (1534 - o_slope * 10);
+
+ svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
+ }
+
+ return true;
+
+remove_mt8183_svsb_mon_mode:
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+ svsb->mode_support &= ~SVSB_MODE_MON;
+ }
+
+ return true;
+}
+
+static bool svs_is_efuse_data_correct(struct svs_platform *svsp)
+{
+ struct nvmem_cell *cell;
+
+ /* Get svs efuse by nvmem */
+ cell = nvmem_cell_get(svsp->dev, "svs-calibration-data");
+ if (IS_ERR(cell)) {
+ dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n",
+ PTR_ERR(cell));
+ return false;
+ }
+
+ svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max);
+ if (IS_ERR(svsp->efuse)) {
+ dev_err(svsp->dev, "cannot read svs efuse: %ld\n",
+ PTR_ERR(svsp->efuse));
+ nvmem_cell_put(cell);
+ return false;
+ }
+
+ svsp->efuse_max /= sizeof(u32);
+ nvmem_cell_put(cell);
+
+ return svsp->efuse_parsing(svsp);
+}
+
+static struct device *svs_get_subsys_device(struct svs_platform *svsp,
+ const char *node_name)
+{
+ struct platform_device *pdev;
+ struct device_node *np;
+
+ np = of_find_node_by_name(NULL, node_name);
+ if (!np) {
+ dev_err(svsp->dev, "cannot find %s node\n", node_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ of_node_put(np);
+ dev_err(svsp->dev, "cannot find pdev by %s\n", node_name);
+ return ERR_PTR(-ENXIO);
+ }
+
+ of_node_put(np);
+
+ return &pdev->dev;
+}
+
+static struct device *svs_add_device_link(struct svs_platform *svsp,
+ const char *node_name)
+{
+ struct device *dev;
+ struct device_link *sup_link;
+
+ if (!node_name) {
+ dev_err(svsp->dev, "node name cannot be null\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dev = svs_get_subsys_device(svsp, node_name);
+ if (IS_ERR(dev))
+ return dev;
+
+ sup_link = device_link_add(svsp->dev, dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!sup_link) {
+ dev_err(svsp->dev, "sup_link is NULL\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return dev;
+}
+
+static int svs_mt8192_platform_probe(struct svs_platform *svsp)
+{
+ struct device *dev;
+ struct svs_bank *svsb;
+ u32 idx;
+
+ svsp->rst = devm_reset_control_get_optional(svsp->dev, "svs_rst");
+ if (IS_ERR(svsp->rst))
+ return dev_err_probe(svsp->dev, PTR_ERR(svsp->rst),
+ "cannot get svs reset control\n");
+
+ dev = svs_add_device_link(svsp, "lvts");
+ if (IS_ERR(dev))
+ return dev_err_probe(svsp->dev, PTR_ERR(dev),
+ "failed to get lvts device\n");
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ if (svsb->type == SVSB_HIGH)
+ svsb->opp_dev = svs_add_device_link(svsp, "gpu");
+ else if (svsb->type == SVSB_LOW)
+ svsb->opp_dev = svs_get_subsys_device(svsp, "gpu");
+
+ if (IS_ERR(svsb->opp_dev))
+ return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
+ "failed to get OPP device for bank %d\n",
+ idx);
+ }
+
+ return 0;
+}
+
+static int svs_mt8183_platform_probe(struct svs_platform *svsp)
+{
+ struct device *dev;
+ struct svs_bank *svsb;
+ u32 idx;
+
+ dev = svs_add_device_link(svsp, "thermal");
+ if (IS_ERR(dev))
+ return dev_err_probe(svsp->dev, PTR_ERR(dev),
+ "failed to get thermal device\n");
+
+ for (idx = 0; idx < svsp->bank_max; idx++) {
+ svsb = &svsp->banks[idx];
+
+ switch (svsb->sw_id) {
+ case SVSB_CPU_LITTLE:
+ case SVSB_CPU_BIG:
+ svsb->opp_dev = get_cpu_device(svsb->cpu_id);
+ break;
+ case SVSB_CCI:
+ svsb->opp_dev = svs_add_device_link(svsp, "cci");
+ break;
+ case SVSB_GPU:
+ svsb->opp_dev = svs_add_device_link(svsp, "gpu");
+ break;
+ default:
+ dev_err(svsb->dev, "unknown sw_id: %u\n", svsb->sw_id);
+ return -EINVAL;
+ }
+
+ if (IS_ERR(svsb->opp_dev))
+ return dev_err_probe(svsp->dev, PTR_ERR(svsb->opp_dev),
+ "failed to get OPP device for bank %d\n",
+ idx);
+ }
+
+ return 0;
+}
+
+static struct svs_bank svs_mt8192_banks[] = {
+ {
+ .sw_id = SVSB_GPU,
+ .type = SVSB_LOW,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT,
+ .mode_support = SVSB_MODE_INIT02,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 688000000,
+ .turn_freq_base = 688000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .vmax = 0x60,
+ .vmin = 0x1a,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .dvt_fixed = 0x1,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .core_sel = 0x0fff0100,
+ .int_st = BIT(0),
+ .ctl0 = 0x00540003,
+ },
+ {
+ .sw_id = SVSB_GPU,
+ .type = SVSB_HIGH,
+ .set_freq_pct = svs_set_bank_freq_pct_v3,
+ .get_volts = svs_get_bank_volts_v3,
+ .tzone_name = "gpu1",
+ .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT |
+ SVSB_MON_VOLT_IGNORE,
+ .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 902000000,
+ .turn_freq_base = 688000000,
+ .volt_step = 6250,
+ .volt_base = 400000,
+ .vmax = 0x60,
+ .vmin = 0x1a,
+ .age_config = 0x555555,
+ .dc_config = 0x1,
+ .dvt_fixed = 0x6,
+ .vco = 0x18,
+ .chk_shift = 0x87,
+ .core_sel = 0x0fff0101,
+ .int_st = BIT(1),
+ .ctl0 = 0x00540003,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 7,
+ },
+};
+
+static struct svs_bank svs_mt8183_banks[] = {
+ {
+ .sw_id = SVSB_CPU_LITTLE,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .cpu_id = 0,
+ .buck_name = "proc",
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .core_sel = 0x8fff0000,
+ .int_st = BIT(0),
+ .ctl0 = 0x00010001,
+ },
+ {
+ .sw_id = SVSB_CPU_BIG,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .cpu_id = 4,
+ .buck_name = "proc",
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 1989000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .vmax = 0x58,
+ .vmin = 0x10,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .core_sel = 0x8fff0001,
+ .int_st = BIT(1),
+ .ctl0 = 0x00000001,
+ },
+ {
+ .sw_id = SVSB_CCI,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .buck_name = "proc",
+ .volt_flags = SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 1196000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .vmax = 0x64,
+ .vmin = 0x18,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x7,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .core_sel = 0x8fff0002,
+ .int_st = BIT(2),
+ .ctl0 = 0x00100003,
+ },
+ {
+ .sw_id = SVSB_GPU,
+ .set_freq_pct = svs_set_bank_freq_pct_v2,
+ .get_volts = svs_get_bank_volts_v2,
+ .buck_name = "mali",
+ .tzone_name = "tzts2",
+ .volt_flags = SVSB_INIT01_PD_REQ |
+ SVSB_INIT01_VOLT_INC_ONLY,
+ .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
+ SVSB_MODE_MON,
+ .opp_count = MAX_OPP_ENTRIES,
+ .freq_base = 900000000,
+ .vboot = 0x30,
+ .volt_step = 6250,
+ .volt_base = 500000,
+ .vmax = 0x40,
+ .vmin = 0x14,
+ .age_config = 0x555555,
+ .dc_config = 0x555555,
+ .dvt_fixed = 0x3,
+ .vco = 0x10,
+ .chk_shift = 0x77,
+ .core_sel = 0x8fff0003,
+ .int_st = BIT(3),
+ .ctl0 = 0x00050001,
+ .tzone_htemp = 85000,
+ .tzone_htemp_voffset = 0,
+ .tzone_ltemp = 25000,
+ .tzone_ltemp_voffset = 3,
+ },
+};
+
+static const struct svs_platform_data svs_mt8192_platform_data = {
+ .name = "mt8192-svs",
+ .banks = svs_mt8192_banks,
+ .efuse_parsing = svs_mt8192_efuse_parsing,
+ .probe = svs_mt8192_platform_probe,
+ .regs = svs_regs_v2,
+ .bank_max = ARRAY_SIZE(svs_mt8192_banks),
+};
+
+static const struct svs_platform_data svs_mt8183_platform_data = {
+ .name = "mt8183-svs",
+ .banks = svs_mt8183_banks,
+ .efuse_parsing = svs_mt8183_efuse_parsing,
+ .probe = svs_mt8183_platform_probe,
+ .regs = svs_regs_v2,
+ .bank_max = ARRAY_SIZE(svs_mt8183_banks),
+};
+
+static const struct of_device_id svs_of_match[] = {
+ {
+ .compatible = "mediatek,mt8192-svs",
+ .data = &svs_mt8192_platform_data,
+ }, {
+ .compatible = "mediatek,mt8183-svs",
+ .data = &svs_mt8183_platform_data,
+ }, {
+ /* Sentinel */
+ },
+};
+
+static struct svs_platform *svs_platform_probe(struct platform_device *pdev)
+{
+ struct svs_platform *svsp;
+ const struct svs_platform_data *svsp_data;
+ int ret;
+
+ svsp_data = of_device_get_match_data(&pdev->dev);
+ if (!svsp_data) {
+ dev_err(&pdev->dev, "no svs platform data?\n");
+ return ERR_PTR(-EPERM);
+ }
+
+ svsp = devm_kzalloc(&pdev->dev, sizeof(*svsp), GFP_KERNEL);
+ if (!svsp)
+ return ERR_PTR(-ENOMEM);
+
+ svsp->dev = &pdev->dev;
+ svsp->name = svsp_data->name;
+ svsp->banks = svsp_data->banks;
+ svsp->efuse_parsing = svsp_data->efuse_parsing;
+ svsp->probe = svsp_data->probe;
+ svsp->regs = svsp_data->regs;
+ svsp->bank_max = svsp_data->bank_max;
+
+ ret = svsp->probe(svsp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return svsp;
+}
+
+static int svs_probe(struct platform_device *pdev)
+{
+ struct svs_platform *svsp;
+ int svsp_irq, ret;
+
+ svsp = svs_platform_probe(pdev);
+ if (IS_ERR(svsp))
+ return PTR_ERR(svsp);
+
+ if (!svs_is_efuse_data_correct(svsp)) {
+ dev_notice(svsp->dev, "efuse data isn't correct\n");
+ ret = -EPERM;
+ goto svs_probe_free_resource;
+ }
+
+ ret = svs_bank_resource_setup(svsp);
+ if (ret) {
+ dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret);
+ goto svs_probe_free_resource;
+ }
+
+ svsp_irq = platform_get_irq(pdev, 0);
+ if (svsp_irq < 0) {
+ ret = svsp_irq;
+ goto svs_probe_free_resource;
+ }
+
+ svsp->main_clk = devm_clk_get(svsp->dev, "main");
+ if (IS_ERR(svsp->main_clk)) {
+ dev_err(svsp->dev, "failed to get clock: %ld\n",
+ PTR_ERR(svsp->main_clk));
+ ret = PTR_ERR(svsp->main_clk);
+ goto svs_probe_free_resource;
+ }
+
+ ret = clk_prepare_enable(svsp->main_clk);
+ if (ret) {
+ dev_err(svsp->dev, "cannot enable main clk: %d\n", ret);
+ goto svs_probe_free_resource;
+ }
+
+ svsp->base = of_iomap(svsp->dev->of_node, 0);
+ if (IS_ERR_OR_NULL(svsp->base)) {
+ dev_err(svsp->dev, "cannot find svs register base\n");
+ ret = -EINVAL;
+ goto svs_probe_clk_disable;
+ }
+
+ ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr,
+ IRQF_ONESHOT, svsp->name, svsp);
+ if (ret) {
+ dev_err(svsp->dev, "register irq(%d) failed: %d\n",
+ svsp_irq, ret);
+ goto svs_probe_iounmap;
+ }
+
+ ret = svs_start(svsp);
+ if (ret) {
+ dev_err(svsp->dev, "svs start fail: %d\n", ret);
+ goto svs_probe_iounmap;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ ret = svs_create_debug_cmds(svsp);
+ if (ret) {
+ dev_err(svsp->dev, "svs create debug cmds fail: %d\n", ret);
+ goto svs_probe_iounmap;
+ }
+#endif
+
+ return 0;
+
+svs_probe_iounmap:
+ iounmap(svsp->base);
+
+svs_probe_clk_disable:
+ clk_disable_unprepare(svsp->main_clk);
+
+svs_probe_free_resource:
+ if (!IS_ERR_OR_NULL(svsp->efuse))
+ kfree(svsp->efuse);
+ if (!IS_ERR_OR_NULL(svsp->tefuse))
+ kfree(svsp->tefuse);
+
+ return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(svs_pm_ops, svs_suspend, svs_resume);
+
+static struct platform_driver svs_driver = {
+ .probe = svs_probe,
+ .driver = {
+ .name = "mtk-svs",
+ .pm = &svs_pm_ops,
+ .of_match_table = svs_of_match,
+ },
+};
+
+module_platform_driver(svs_driver);
+
+MODULE_AUTHOR("Roger Lu <roger.lu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SVS driver");
+MODULE_LICENSE("GPL");