summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/domain/Kconfig89
-rw-r--r--drivers/power/domain/Makefile15
-rw-r--r--drivers/power/domain/mt2701-power-domain.c89
-rw-r--r--drivers/power/domain/mt7622-power-domain.c56
-rw-r--r--drivers/power/domain/mt8188-power-domain.c665
-rw-r--r--drivers/power/domain/mtk-power-domain.c576
-rw-r--r--drivers/power/domain/mtk-power-domain.h131
-rw-r--r--drivers/power/domain/renesas-r8a78000-power-domain.c4
-rw-r--r--drivers/power/pmic/Kconfig23
-rw-r--r--drivers/power/pmic/Makefile2
-rw-r--r--drivers/power/pmic/pf9453.c170
-rw-r--r--drivers/power/pmic/pmic_spacemit_p1.c94
-rw-r--r--drivers/power/pmic/tps65219.c1
-rw-r--r--drivers/power/regulator/Kconfig22
-rw-r--r--drivers/power/regulator/Makefile2
-rw-r--r--drivers/power/regulator/pf9453.c256
-rw-r--r--drivers/power/regulator/spacemit_p1_regulator.c464
17 files changed, 2382 insertions, 277 deletions
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index bb9c52155d2..12b0e2c9914 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -9,6 +9,14 @@ config POWER_DOMAIN
domains). This may be used to save power. This API provides the
means to control such power management hardware.
+config AGILEX5_PMGR_POWER_DOMAIN
+ bool "Enable the Agilex5 PMGR power domain driver"
+ depends on SPL_POWER_DOMAIN && ARCH_SOCFPGA_SOC64
+ help
+ Enable support for power gating peripherals' SRAM specified in
+ the handoff data values obtained from the bitstream to reduce
+ power consumption.
+
config APPLE_PMGR_POWER_DOMAIN
bool "Enable the Apple PMGR power domain driver"
depends on POWER_DOMAIN
@@ -18,14 +26,6 @@ config APPLE_PMGR_POWER_DOMAIN
This driver is needed to power on parts of the SoC that have
not been powered on by previous boot stages.
-config AGILEX5_PMGR_POWER_DOMAIN
- bool "Enable the Agilex5 PMGR power domain driver"
- depends on SPL_POWER_DOMAIN && ARCH_SOCFPGA_SOC64
- help
- Enable support for power gating peripherals' SRAM specified in
- the handoff data values obtained from the bitstream to reduce
- power consumption.
-
config BCM6328_POWER_DOMAIN
bool "Enable the BCM6328 power domain driver"
depends on POWER_DOMAIN && ARCH_BMIPS
@@ -62,12 +62,12 @@ config IMX8MP_MEDIAMIX_BLKCTRL
help
Enable support for manipulating NXP i.MX8MP on-SoC MEDIAMIX block controller.
-config MTK_POWER_DOMAIN
- bool "Enable the MediaTek power domain driver"
- depends on POWER_DOMAIN && ARCH_MEDIATEK
+config MESON_EE_POWER_DOMAIN
+ bool "Enable Amlogic Everything-Else power domain driver"
+ depends on POWER_DOMAIN && ARCH_MESON
help
- Enable support for manipulating MediaTek power domains via MMIO
- mapped registers.
+ Enable support for manipulating Amlogic Meson Everything-Else power
+ domains.
config MESON_GX_VPU_POWER_DOMAIN
bool "Enable Amlogic Meson GX VPU power domain driver"
@@ -76,13 +76,6 @@ config MESON_GX_VPU_POWER_DOMAIN
Enable support for manipulating Amlogic Meson GX Video Processing
Unit power domain.
-config MESON_EE_POWER_DOMAIN
- bool "Enable Amlogic Everything-Else power domain driver"
- depends on POWER_DOMAIN && ARCH_MESON
- help
- Enable support for manipulating Amlogic Meson Everything-Else power
- domains.
-
config MESON_SECURE_POWER_DOMAIN
bool "Enable Amlogic Secure power domain driver"
depends on POWER_DOMAIN && ARCH_MESON && MESON_A1
@@ -90,6 +83,40 @@ config MESON_SECURE_POWER_DOMAIN
Enable support for manipulating Amlogic Meson Secure power domains.
Support for Amlogic A1 series.
+config MT2701_POWER_DOMAIN
+ bool "Enable the MediaTek power domain driver for MT2701 compatible SoC"
+ depends on POWER_DOMAIN && ARCH_MEDIATEK
+ select MTK_POWER_DOMAIN
+ help
+ Enable support for manipulating MediaTek power domains via MMIO
+ mapped registers for MT2701 compatible SoC. The driver powers
+ the SoC power domains on and off and handles the associated bus
+ protection bits. It is also used on MT7623.
+
+config MT7622_POWER_DOMAIN
+ bool "Enable the MediaTek power domain driver for MT7622 compatible SoC"
+ depends on POWER_DOMAIN && ARCH_MEDIATEK
+ select MTK_POWER_DOMAIN
+ help
+ Enable support for manipulating MediaTek power domains via MMIO
+ mapped registers for MT7622 compatible SoC. The driver powers
+ the SoC power domains on and off and handles the associated bus
+ protection bits. It is also used on MT7629.
+
+config MT8188_POWER_DOMAIN
+ bool "Enable the MediaTek power domain driver for MT8188 compatible SoC"
+ depends on POWER_DOMAIN && ARCH_MEDIATEK
+ select MTK_POWER_DOMAIN
+ help
+ Enable support for manipulating MediaTek power domains via MMIO
+ mapped registers for MT8188 compatible SoC. The driver powers
+ the SoC power domains on and off and handles the associated bus
+ protection steps, per-domain clocks and parent domains.
+
+config MTK_POWER_DOMAIN
+ bool
+ depends on POWER_DOMAIN && ARCH_MEDIATEK
+
config QCOM_RPMH_POWER_DOMAIN
bool "Enable the QCOM RPMH Power domain driver"
depends on POWER_DOMAIN && ARCH_SNAPDRAGON
@@ -128,12 +155,13 @@ config TEGRA186_POWER_DOMAIN
Enable support for manipulating Tegra's on-SoC power domains via IPC
requests to the BPMP (Boot and Power Management Processor).
-config TI_SCI_POWER_DOMAIN
- bool "Enable the TI SCI-based power domain driver"
- depends on POWER_DOMAIN && TI_SCI_PROTOCOL
+config TI_OMAP_PRM_POWER_DOMAIN
+ bool "Enable the TI OMAP PRM power domain driver"
+ depends on POWER_DOMAIN && ARCH_OMAP2PLUS
help
- Generic power domain implementation for TI devices implementing the
- TI SCI protocol.
+ Enable support for TI OMAP Power and Reset Manager (PRM) power domains.
+ The driver is currently a stub to be able to probe devices that
+ require this type of power domain device.
config TI_POWER_DOMAIN
bool "Enable the TI K3 Power domain driver"
@@ -141,13 +169,12 @@ config TI_POWER_DOMAIN
help
Generic power domain implementation for TI K3 devices.
-config TI_OMAP_PRM_POWER_DOMAIN
- bool "Enable the TI OMAP PRM power domain driver"
- depends on POWER_DOMAIN && ARCH_OMAP2PLUS
+config TI_SCI_POWER_DOMAIN
+ bool "Enable the TI SCI-based power domain driver"
+ depends on POWER_DOMAIN && TI_SCI_PROTOCOL
help
- Enable support for TI OMAP Power and Reset Manager (PRM) power domains.
- The driver is currently a stub to be able to probe devices that
- require this type of power domain device.
+ Generic power domain implementation for TI devices implementing the
+ TI SCI protocol.
config ZYNQMP_POWER_DOMAIN
bool "Enable the Xilinx ZynqMP Power domain driver"
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 110153d5cf8..e6fe71c374a 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -4,24 +4,27 @@
#
obj-$(CONFIG_$(PHASE_)POWER_DOMAIN) += power-domain-uclass.o
-obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o
obj-$(CONFIG_AGILEX5_PMGR_POWER_DOMAIN) += altr-pmgr-agilex5.o
+obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o
obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o
obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o
obj-$(CONFIG_IMX8MP_MEDIAMIX_BLKCTRL) += imx8mp-mediamix.o
-obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
-obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
+obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o
+obj-$(CONFIG_MT2701_POWER_DOMAIN) += mt2701-power-domain.o
+obj-$(CONFIG_MT7622_POWER_DOMAIN) += mt7622-power-domain.o
+obj-$(CONFIG_MT8188_POWER_DOMAIN) += mt8188-power-domain.o
+obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
+obj-$(CONFIG_QCOM_RPMH_POWER_DOMAIN) += qcom-rpmhpd.o
obj-$(CONFIG_RENESAS_R8A78000_POWER_DOMAIN) += renesas-r8a78000-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
-obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
-obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
obj-$(CONFIG_TI_OMAP_PRM_POWER_DOMAIN) += ti-omap-prm.o
+obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
+obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
obj-$(CONFIG_ZYNQMP_POWER_DOMAIN) += zynqmp-power-domain.o
-obj-$(CONFIG_QCOM_RPMH_POWER_DOMAIN) += qcom-rpmhpd.o
diff --git a/drivers/power/domain/mt2701-power-domain.c b/drivers/power/domain/mt2701-power-domain.c
new file mode 100644
index 00000000000..5bef4aa97ea
--- /dev/null
+++ b/drivers/power/domain/mt2701-power-domain.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Copyright (C) 2026 BayLibre, SAS
+ * Author: Ryder Lee <[email protected]>
+ * Julien Stephan <[email protected]>
+ */
+
+#include <dm.h>
+#include <dt-bindings/power/mt2701-power.h>
+#include <linux/bitops.h>
+
+#include "mtk-power-domain.h"
+
+static const struct mtk_scp_domain_data mt2701_scp_domain[] = {
+ [MT2701_POWER_DOMAIN_CONN] = {
+ .sta_mask = PWR_STATUS_CONN,
+ .ctl_offs = SPM_CONN_PWR_CON,
+ .bus_prot_mask = BIT(8) | BIT(2),
+ },
+ [MT2701_POWER_DOMAIN_DISP] = {
+ .sta_mask = PWR_STATUS_DISP,
+ .ctl_offs = SPM_DIS_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .bus_prot_mask = BIT(2),
+ },
+ [MT2701_POWER_DOMAIN_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),
+ },
+ [MT2701_POWER_DOMAIN_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),
+ },
+ [MT2701_POWER_DOMAIN_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),
+ },
+ [MT2701_POWER_DOMAIN_BDP] = {
+ .sta_mask = PWR_STATUS_BDP,
+ .ctl_offs = SPM_BDP_PWR_CON,
+ .sram_pdn_bits = GENMASK(11, 8),
+ },
+ [MT2701_POWER_DOMAIN_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),
+ },
+ [MT2701_POWER_DOMAIN_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),
+ },
+ [MT2701_POWER_DOMAIN_IFR_MSC] = {
+ .sta_mask = PWR_STATUS_IFR_MSC,
+ .ctl_offs = SPM_IFR_MSC_PWR_CON,
+ },
+};
+
+MTK_SCP_SOC_DATA(mt2701, mt2701_scp_domain);
+
+static const struct udevice_id mt2701_power_domain_ids[] = {
+ {
+ .compatible = "mediatek,mt2701-scpsys",
+ .data = (ulong)&mt2701_scp_soc_data,
+ },
+ {
+ .compatible = "mediatek,mt7623-scpsys",
+ .data = (ulong)&mt2701_scp_soc_data,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt2701_power_domain) = {
+ .name = "mt2701_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .ops = &mtk_power_domain_ops,
+ .probe = mtk_scpsys_probe,
+ .of_match = mt2701_power_domain_ids,
+ .priv_auto = sizeof(struct mtk_scpsys),
+};
diff --git a/drivers/power/domain/mt7622-power-domain.c b/drivers/power/domain/mt7622-power-domain.c
new file mode 100644
index 00000000000..13f2154e145
--- /dev/null
+++ b/drivers/power/domain/mt7622-power-domain.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Copyright (C) 2026 BayLibre, SAS
+ * Author: Ryder Lee <[email protected]>
+ * Julien Stephan <[email protected]>
+ */
+
+#include <dm.h>
+#include <dt-bindings/power/mt7622-power.h>
+#include <linux/bitops.h>
+
+#include "mtk-power-domain.h"
+
+static const struct mtk_scp_domain_data mt7622_scp_domain[] = {
+ [MT7622_POWER_DOMAIN_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),
+ .bus_prot_mask = (BIT(3) | BIT(17)),
+ },
+ [MT7622_POWER_DOMAIN_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),
+ .bus_prot_mask = GENMASK(25, 24),
+ },
+ [MT7622_POWER_DOMAIN_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),
+ .bus_prot_mask = GENMASK(28, 26),
+ },
+};
+
+MTK_SCP_SOC_DATA(mt7622, mt7622_scp_domain);
+
+static const struct udevice_id mt7622_power_domain_ids[] = {
+ {
+ .compatible = "mediatek,mt7622-scpsys",
+ .data = (ulong)&mt7622_scp_soc_data,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7622_power_domain) = {
+ .name = "mt7622_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .ops = &mtk_power_domain_ops,
+ .probe = mtk_scpsys_probe,
+ .of_match = mt7622_power_domain_ids,
+ .priv_auto = sizeof(struct mtk_scpsys),
+};
diff --git a/drivers/power/domain/mt8188-power-domain.c b/drivers/power/domain/mt8188-power-domain.c
new file mode 100644
index 00000000000..265d222f17a
--- /dev/null
+++ b/drivers/power/domain/mt8188-power-domain.c
@@ -0,0 +1,665 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 MediaTek Inc.
+ * Copyright (C) 2026 BayLibre, SAS.
+ * Authors: Chris-QJ Chen <[email protected]>
+ * Julien Stephan <[email protected]>
+ */
+
+#include <dm.h>
+#include <dt-bindings/power/mediatek,mt8188-power.h>
+#include <linux/bitops.h>
+
+#include "mtk-power-domain.h"
+
+/* Infra bus protection register offsets */
+#define MT8188_TOP_AXI_PROT_EN_SET 0x2A0
+#define MT8188_TOP_AXI_PROT_EN_CLR 0x2A4
+#define MT8188_TOP_AXI_PROT_EN_STA 0x228
+#define MT8188_TOP_AXI_PROT_EN_1_SET 0x2A8
+#define MT8188_TOP_AXI_PROT_EN_1_CLR 0x2AC
+#define MT8188_TOP_AXI_PROT_EN_1_STA 0x258
+#define MT8188_TOP_AXI_PROT_EN_2_SET 0x714
+#define MT8188_TOP_AXI_PROT_EN_2_CLR 0x718
+#define MT8188_TOP_AXI_PROT_EN_2_STA 0x724
+#define MT8188_TOP_AXI_PROT_EN_MM_SET 0x2D4
+#define MT8188_TOP_AXI_PROT_EN_MM_CLR 0x2D8
+#define MT8188_TOP_AXI_PROT_EN_MM_STA 0x2EC
+#define MT8188_TOP_AXI_PROT_EN_MM_2_SET 0xDCC
+#define MT8188_TOP_AXI_PROT_EN_MM_2_CLR 0xDD0
+#define MT8188_TOP_AXI_PROT_EN_MM_2_STA 0xDD8
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET 0xB84
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR 0xB88
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA 0xB90
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET 0xBCC
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR 0xBD0
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA 0xBD8
+
+/* MFG1 bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_MFG1_STEP1 BIT(11)
+#define MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP2 BIT(7)
+#define MT8188_TOP_AXI_PROT_EN_1_MFG1_STEP3 BIT(19)
+#define MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP4 BIT(5)
+#define MT8188_TOP_AXI_PROT_EN_MFG1_STEP5 GENMASK(22, 21)
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1_STEP6 BIT(17)
+
+/* PCIe bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_PEXTP_MAC_P0_STEP1 BIT(2)
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_PEXTP_MAC_P0_STEP2 (BIT(8) | BIT(18) | BIT(30))
+
+/* Ethernet / HDMI / DP / eDP bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_ETHER_STEP1 BIT(24)
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_HDMI_TX_STEP1 BIT(20)
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_DP_TX_STEP1 BIT(23)
+#define MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_EDP_TX_STEP1 BIT(22)
+
+/* ADSP bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP1 GENMASK(31, 29)
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP2 (GENMASK(4, 3) | BIT(28))
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP1 (GENMASK(16, 14) | BIT(23) | BIT(27))
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP2 (GENMASK(19, 17) | GENMASK(26, 25))
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP1 GENMASK(11, 8)
+#define MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP2 GENMASK(22, 21)
+
+/* Audio bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP1 BIT(20)
+#define MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP2 BIT(12)
+#define MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP1 BIT(24)
+#define MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP2 BIT(13)
+
+/* Video / display bus protection bits */
+#define MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP1 BIT(10)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP2 GENMASK(9, 8)
+#define MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP3 BIT(23)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP4 (BIT(1) | BIT(4) | BIT(11))
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0_STEP5 BIT(20)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDOSYS0_STEP1 (GENMASK(18, 17) | GENMASK(21, 20))
+#define MT8188_TOP_AXI_PROT_EN_VDOSYS0_STEP2 BIT(6)
+#define MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0_STEP3 BIT(21)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP1 GENMASK(31, 30)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP2 BIT(22)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VDOSYS1_STEP3 BIT(10)
+#define MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP1 GENMASK(6, 5)
+#define MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP2 BIT(23)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS1_STEP3 BIT(18)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP1 BIT(23)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP2 BIT(21)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDEC0_STEP1 BIT(13)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VDEC0_STEP2 BIT(13)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP1 BIT(14)
+#define MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP2 BIT(29)
+#define MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP1 (BIT(9) | BIT(11))
+#define MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP2 BIT(26)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_VENC_STEP3 BIT(2)
+#define MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP1 (BIT(1) | BIT(3))
+#define MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP2 BIT(25)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_IMG_VCORE_STEP3 BIT(16)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP1 GENMASK(27, 26)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP2 GENMASK(25, 24)
+#define MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP1 (BIT(2) | BIT(4))
+#define MT8188_TOP_AXI_PROT_EN_2_CAM_VCORE_STEP2 BIT(0)
+#define MT8188_TOP_AXI_PROT_EN_1_CAM_VCORE_STEP3 BIT(22)
+#define MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP4 BIT(24)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_CAM_VCORE_STEP5 BIT(17)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP1 GENMASK(31, 30)
+#define MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP2 BIT(2)
+#define MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP3 GENMASK(29, 28)
+#define MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP4 BIT(1)
+
+static const struct mtk_scp_domain_data mt8188_scp_domain[] = {
+ [MT8188_POWER_DOMAIN_MFG0] = {
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x300,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_MFG1] = {
+ .sta_mask = BIT(2),
+ .ctl_offs = 0x304,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MFG1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_1_MFG1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_1_SET,
+ MT8188_TOP_AXI_PROT_EN_1_CLR,
+ MT8188_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_MFG1_STEP4,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MFG1_STEP5,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_MFG1_STEP6,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_MFG2] = {
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x308,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_MFG3] = {
+ .sta_mask = BIT(4),
+ .ctl_offs = 0x30C,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_MFG4] = {
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x310,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_PEXTP_MAC_P0] = {
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x324,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_PEXTP_MAC_P0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_PEXTP_MAC_P0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_PEXTP_PHY_TOP] = {
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x328,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ },
+ [MT8188_POWER_DOMAIN_CSIRX_TOP] = {
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x3C4,
+ .pwr_sta_offs = 0x174,
+ .pwr_sta2nd_offs = 0x178,
+ },
+ [MT8188_POWER_DOMAIN_ETHER] = {
+ .sta_mask = BIT(1),
+ .ctl_offs = 0x338,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_ETHER_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_HDMI_TX] = {
+ .sta_mask = BIT(18),
+ .ctl_offs = 0x37C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_HDMI_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_ADSP_AO] = {
+ .sta_mask = BIT(10),
+ .ctl_offs = 0x35C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_AO_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_ADSP_INFRA] = {
+ .sta_mask = BIT(9),
+ .ctl_offs = 0x358,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_INFRA_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_ADSP] = {
+ .sta_mask = BIT(8),
+ .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(MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_ADSP_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_AUDIO] = {
+ .sta_mask = BIT(6),
+ .ctl_offs = 0x34C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_AUDIO_ASRC] = {
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x350,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP1,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_AUDIO_ASRC_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VPPSYS0] = {
+ .sta_mask = BIT(11),
+ .ctl_offs = 0x360,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VPPSYS0_STEP3,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS0_STEP4,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VPPSYS0_STEP5,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDOSYS0] = {
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x368,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_VDOSYS0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_SET,
+ MT8188_TOP_AXI_PROT_EN_CLR,
+ MT8188_TOP_AXI_PROT_EN_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_VDOSYS0_STEP3,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_SUB_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDOSYS1] = {
+ .sta_mask = BIT(14),
+ .ctl_offs = 0x36C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDOSYS1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VDOSYS1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_DP_TX] = {
+ .sta_mask = BIT(16),
+ .ctl_offs = 0x374,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_DP_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_EDP_TX] = {
+ .sta_mask = BIT(17),
+ .ctl_offs = 0x378,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_EDP_TX_STEP1,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_SET,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_CLR,
+ MT8188_TOP_AXI_PROT_EN_INFRA_VDNR_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VPPSYS1] = {
+ .sta_mask = BIT(12),
+ .ctl_offs = 0x364,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VPPSYS1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VPPSYS1_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_WPE] = {
+ .sta_mask = BIT(15),
+ .ctl_offs = 0x370,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_WPE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDEC0] = {
+ .sta_mask = BIT(19),
+ .ctl_offs = 0x380,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC0_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VDEC0_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VDEC1] = {
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x384,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VDEC1_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_VENC] = {
+ .sta_mask = BIT(22),
+ .ctl_offs = 0x38C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_VENC_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_VENC_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_IMG_VCORE] = {
+ .sta_mask = BIT(28),
+ .ctl_offs = 0x3A4,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_IMG_VCORE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_VCORE_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_IMG_MAIN] = {
+ .sta_mask = BIT(29),
+ .ctl_offs = 0x3A8,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_IMG_MAIN_STEP2,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_DIP] = {
+ .sta_mask = BIT(30),
+ .ctl_offs = 0x3AC,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_IPE] = {
+ .sta_mask = BIT(31),
+ .ctl_offs = 0x3B0,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_CAM_VCORE] = {
+ .sta_mask = BIT(27),
+ .ctl_offs = 0x3A0,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_VCORE_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_1_CAM_VCORE_STEP3,
+ MT8188_TOP_AXI_PROT_EN_1_SET,
+ MT8188_TOP_AXI_PROT_EN_1_CLR,
+ MT8188_TOP_AXI_PROT_EN_1_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_CAM_VCORE_STEP4,
+ MT8188_TOP_AXI_PROT_EN_MM_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_VCORE_STEP5,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_CAM_MAIN] = {
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x394,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ .bp_infracfg = {
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP1,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP2,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_MM_2_CAM_MAIN_STEP3,
+ MT8188_TOP_AXI_PROT_EN_MM_2_SET,
+ MT8188_TOP_AXI_PROT_EN_MM_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_MM_2_STA),
+ BUS_PROT_WR(MT8188_TOP_AXI_PROT_EN_2_CAM_MAIN_STEP4,
+ MT8188_TOP_AXI_PROT_EN_2_SET,
+ MT8188_TOP_AXI_PROT_EN_2_CLR,
+ MT8188_TOP_AXI_PROT_EN_2_STA),
+ },
+ },
+ [MT8188_POWER_DOMAIN_CAM_SUBA] = {
+ .sta_mask = BIT(25),
+ .ctl_offs = 0x398,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+ [MT8188_POWER_DOMAIN_CAM_SUBB] = {
+ .sta_mask = BIT(26),
+ .ctl_offs = 0x39C,
+ .pwr_sta_offs = 0x16C,
+ .pwr_sta2nd_offs = 0x170,
+ .sram_pdn_bits = BIT(8),
+ .sram_pdn_ack_bits = BIT(12),
+ },
+};
+
+MTK_SCP_SOC_DATA(mt8188, mt8188_scp_domain);
+
+static const struct udevice_id mt8188_power_domain_ids[] = {
+ {
+ .compatible = "mediatek,mt8188-power-controller",
+ .data = (ulong)&mt8188_scp_soc_data,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt8188_power_domain) = {
+ .name = "mt8188_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .ops = &mtk_power_domain_ops,
+ .probe = mtk_power_controller_probe,
+ .of_match = mt8188_power_domain_ids,
+ .priv_auto = sizeof(struct mtk_scpsys),
+};
diff --git a/drivers/power/domain/mtk-power-domain.c b/drivers/power/domain/mtk-power-domain.c
index 24dd540897d..9eef58d2d57 100644
--- a/drivers/power/domain/mtk-power-domain.c
+++ b/drivers/power/domain/mtk-power-domain.c
@@ -6,161 +6,15 @@
#include <clk.h>
#include <dm.h>
-#include <malloc.h>
-#include <power-domain-uclass.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
-#include <asm/processor.h>
-#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/iopoll.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
-#include <dt-bindings/power/mt7623-power.h>
-#include <dt-bindings/power/mt7629-power.h>
-
-#define SPM_EN (0xb16 << 16 | 0x1)
-#define SPM_VDE_PWR_CON 0x0210
-#define SPM_MFG_PWR_CON 0x0214
-#define SPM_ISP_PWR_CON 0x0238
-#define SPM_DIS_PWR_CON 0x023c
-#define SPM_CONN_PWR_CON 0x0280
-#define SPM_BDP_PWR_CON 0x029c
-#define SPM_ETH_PWR_CON 0x02a0
-#define SPM_HIF_PWR_CON 0x02a4
-#define SPM_IFR_MSC_PWR_CON 0x02a8
-#define SPM_ETHSYS_PWR_CON 0x2e0
-#define SPM_HIF0_PWR_CON 0x2e4
-#define SPM_HIF1_PWR_CON 0x2e8
-#define SPM_PWR_STATUS 0x60c
-#define SPM_PWR_STATUS_2ND 0x610
-
-#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_ETHSYS BIT(24)
-#define PWR_STATUS_HIF0 BIT(25)
-#define PWR_STATUS_HIF1 BIT(26)
-
-/* Infrasys configuration */
-#define INFRA_TOPDCM_CTRL 0x10
-#define INFRA_TOPAXI_PROT_EN 0x220
-#define INFRA_TOPAXI_PROT_STA1 0x228
-
-#define DCM_TOP_EN BIT(0)
-
-enum scp_domain_type {
- SCPSYS_MT7622,
- SCPSYS_MT7623,
- SCPSYS_MT7629,
-};
-
-struct scp_domain;
-
-struct scp_domain_data {
- struct scp_domain *scpd;
- u32 sta_mask;
- int ctl_offs;
- u32 sram_pdn_bits;
- u32 sram_pdn_ack_bits;
- u32 bus_prot_mask;
-};
-
-struct scp_domain {
- void __iomem *base;
- void __iomem *infracfg;
- enum scp_domain_type type;
- struct scp_domain_data *data;
-};
-
-static struct scp_domain_data scp_domain_mt7623[] = {
- [MT7623_POWER_DOMAIN_CONN] = {
- .sta_mask = PWR_STATUS_CONN,
- .ctl_offs = SPM_CONN_PWR_CON,
- .bus_prot_mask = BIT(8) | BIT(2),
- },
- [MT7623_POWER_DOMAIN_DISP] = {
- .sta_mask = PWR_STATUS_DISP,
- .ctl_offs = SPM_DIS_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- .bus_prot_mask = BIT(2),
- },
- [MT7623_POWER_DOMAIN_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),
- },
- [MT7623_POWER_DOMAIN_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),
- },
- [MT7623_POWER_DOMAIN_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),
- },
- [MT7623_POWER_DOMAIN_BDP] = {
- .sta_mask = PWR_STATUS_BDP,
- .ctl_offs = SPM_BDP_PWR_CON,
- .sram_pdn_bits = GENMASK(11, 8),
- },
- [MT7623_POWER_DOMAIN_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),
- },
- [MT7623_POWER_DOMAIN_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),
- },
- [MT7623_POWER_DOMAIN_IFR_MSC] = {
- .sta_mask = PWR_STATUS_IFR_MSC,
- .ctl_offs = SPM_IFR_MSC_PWR_CON,
- },
-};
-
-static struct scp_domain_data scp_domain_mt7629[] = {
- [MT7629_POWER_DOMAIN_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),
- .bus_prot_mask = (BIT(3) | BIT(17)),
- },
- [MT7629_POWER_DOMAIN_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),
- .bus_prot_mask = GENMASK(25, 24),
- },
- [MT7629_POWER_DOMAIN_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),
- .bus_prot_mask = GENMASK(28, 26),
- },
-};
+#include "mtk-power-domain.h"
/**
* This function enables the bus protection bits for disabled power
@@ -189,13 +43,79 @@ static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg,
!(val & mask), 100);
}
-static int scpsys_domain_is_on(struct scp_domain_data *data)
+static int _scpsys_bus_protect_enable(const struct mtk_scpsys_bus_prot_data *bpd,
+ void __iomem *reg)
+{
+ u32 val = 0, mask = bpd->bus_prot_mask;
+
+ if (!mask)
+ return 0;
+
+ if (bpd->bus_prot_reg_update)
+ clrsetbits_le32(reg + bpd->bus_prot_set, mask, mask);
+ else
+ writel(mask, reg + bpd->bus_prot_set);
+
+ return readl_poll_timeout(reg + bpd->bus_prot_sta, val, (val & mask) == mask, 1000);
+}
+
+static int _scpsys_bus_protect_disable(const struct mtk_scpsys_bus_prot_data *bpd,
+ void __iomem *reg)
+{
+ u32 val = 0, mask = bpd->bus_prot_mask;
+
+ if (!mask)
+ return 0;
+
+ if (bpd->bus_prot_reg_update)
+ clrbits_le32(reg + bpd->bus_prot_clr, mask);
+ else
+ writel(mask, reg + bpd->bus_prot_clr);
+
+ if (bpd->ignore_clr_ack)
+ return 0;
+
+ return readl_poll_timeout(reg + bpd->bus_prot_sta, val, !(val & mask), 1000);
+}
+
+static int scpsys_bus_protect_enable(const struct mtk_scpsys_bus_prot_data *bpd,
+ int bpd_size, void __iomem *reg)
{
- struct scp_domain *scpd = data->scpd;
- u32 sta = readl(scpd->base + SPM_PWR_STATUS) &
- data->sta_mask;
- u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) &
- data->sta_mask;
+ int ret, i;
+
+ for (i = 0; i < bpd_size; i++) {
+ ret = _scpsys_bus_protect_enable(&bpd[i], reg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scpsys_bus_protect_disable(const struct mtk_scpsys_bus_prot_data *bpd,
+ int bpd_size, void __iomem *reg)
+{
+ int i, ret;
+
+ for (i = bpd_size - 1; i >= 0; i--) {
+ ret = _scpsys_bus_protect_disable(&bpd[i], reg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_scpsys_domain_is_on(struct power_domain *power_domain)
+{
+ struct mtk_scpsys *scpsys = dev_get_priv(power_domain->dev);
+ const struct mtk_scp_domain_data *data = scpsys->domains[power_domain->id].data;
+ u32 spm_pwr_status = data->pwr_sta_offs ?: SPM_PWR_STATUS;
+ u32 spm_pwr_status_2nd = data->pwr_sta2nd_offs ?: SPM_PWR_STATUS_2ND;
+ u32 sta, sta2;
+
+ sta = readl(scpsys->base + spm_pwr_status) & data->sta_mask;
+ sta2 = readl(scpsys->base + spm_pwr_status_2nd) & data->sta_mask;
/*
* A domain is on when both status bits are set. If only one is set
@@ -209,16 +129,40 @@ static int scpsys_domain_is_on(struct scp_domain_data *data)
return -EINVAL;
}
-static int scpsys_power_on(struct power_domain *power_domain)
+static int mtk_scpsys_power_on(struct power_domain *power_domain)
{
- struct scp_domain *scpd = dev_get_priv(power_domain->dev);
- struct scp_domain_data *data = &scpd->data[power_domain->id];
- void __iomem *ctl_addr = scpd->base + data->ctl_offs;
- u32 pdn_ack = data->sram_pdn_ack_bits;
+ struct mtk_scpsys *scpsys = dev_get_priv(power_domain->dev);
+ struct mtk_scp_domain *domain;
+ const struct mtk_scp_domain_data *data;
+ void __iomem *ctl_addr;
+ void __iomem *infracfg;
+ u32 pdn_ack;
u32 val;
int ret, tmp;
- writel(SPM_EN, scpd->base);
+ if (power_domain->id >= scpsys->soc_data->num_domains)
+ return -EINVAL;
+
+ domain = &scpsys->domains[power_domain->id];
+ data = domain->data;
+ if (!data)
+ return -EINVAL;
+
+ ctl_addr = scpsys->base + data->ctl_offs;
+ infracfg = domain->infracfg ? domain->infracfg : scpsys->infracfg;
+ pdn_ack = data->sram_pdn_ack_bits;
+
+ if (domain->has_pd) {
+ ret = power_domain_on(&domain->parent_pd);
+ if (ret)
+ return ret;
+ }
+
+ ret = clk_enable_bulk(&domain->clks);
+ if (ret)
+ return ret;
+
+ writel(SPM_EN, scpsys->base);
val = readl(ctl_addr);
val |= PWR_ON_BIT;
@@ -227,7 +171,7 @@ static int scpsys_power_on(struct power_domain *power_domain)
val |= PWR_ON_2ND_BIT;
writel(val, ctl_addr);
- ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0,
+ ret = readx_poll_timeout(mtk_scpsys_domain_is_on, power_domain, tmp, tmp > 0,
100);
if (ret < 0)
return ret;
@@ -241,6 +185,10 @@ static int scpsys_power_on(struct power_domain *power_domain)
val |= PWR_RST_B_BIT;
writel(val, ctl_addr);
+ ret = clk_enable_bulk(&domain->subsys_clks);
+ if (ret)
+ return ret;
+
val &= ~data->sram_pdn_bits;
writel(val, ctl_addr);
@@ -249,31 +197,52 @@ static int scpsys_power_on(struct power_domain *power_domain)
return ret;
if (data->bus_prot_mask) {
- ret = mtk_infracfg_clear_bus_protection(scpd->infracfg,
+ ret = mtk_infracfg_clear_bus_protection(infracfg,
data->bus_prot_mask);
if (ret)
return ret;
}
+ ret = scpsys_bus_protect_disable(data->bp_infracfg, SPM_MAX_BUS_PROT_DATA, infracfg);
+ if (ret < 0)
+ return ret;
return 0;
}
-static int scpsys_power_off(struct power_domain *power_domain)
+static int mtk_scpsys_power_off(struct power_domain *power_domain)
{
- struct scp_domain *scpd = dev_get_priv(power_domain->dev);
- struct scp_domain_data *data = &scpd->data[power_domain->id];
- void __iomem *ctl_addr = scpd->base + data->ctl_offs;
- u32 pdn_ack = data->sram_pdn_ack_bits;
+ struct mtk_scpsys *scpsys = dev_get_priv(power_domain->dev);
+ struct mtk_scp_domain *domain;
+ const struct mtk_scp_domain_data *data;
+ void __iomem *ctl_addr;
+ void __iomem *infracfg;
+ u32 pdn_ack;
u32 val;
int ret, tmp;
+ if (power_domain->id >= scpsys->soc_data->num_domains)
+ return -EINVAL;
+
+ domain = &scpsys->domains[power_domain->id];
+ data = domain->data;
+ if (!data)
+ return -EINVAL;
+
+ ctl_addr = scpsys->base + data->ctl_offs;
+ infracfg = domain->infracfg ?: scpsys->infracfg;
+ pdn_ack = data->sram_pdn_ack_bits;
+
if (data->bus_prot_mask) {
- ret = mtk_infracfg_set_bus_protection(scpd->infracfg,
+ ret = mtk_infracfg_set_bus_protection(infracfg,
data->bus_prot_mask);
if (ret)
return ret;
}
+ ret = scpsys_bus_protect_enable(data->bp_infracfg, SPM_MAX_BUS_PROT_DATA, infracfg);
+ if (ret < 0)
+ return ret;
+
val = readl(ctl_addr);
val |= data->sram_pdn_bits;
writel(val, ctl_addr);
@@ -283,6 +252,10 @@ static int scpsys_power_off(struct power_domain *power_domain)
if (ret < 0)
return ret;
+ ret = clk_disable_bulk(&domain->subsys_clks);
+ if (ret)
+ return ret;
+
val |= PWR_ISO_BIT;
writel(val, ctl_addr);
@@ -298,60 +271,38 @@ static int scpsys_power_off(struct power_domain *power_domain)
val &= ~PWR_ON_2ND_BIT;
writel(val, ctl_addr);
- ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100);
+ ret = readx_poll_timeout(mtk_scpsys_domain_is_on, power_domain, tmp, !tmp, 100);
if (ret < 0)
return ret;
- return 0;
-}
-
-static int scpsys_power_request(struct power_domain *power_domain)
-{
- struct scp_domain *scpd = dev_get_priv(power_domain->dev);
- struct scp_domain_data *data;
-
- data = &scpd->data[power_domain->id];
- data->scpd = scpd;
-
- return 0;
-}
-
-static int mtk_power_domain_hook(struct udevice *dev)
-{
- struct scp_domain *scpd = dev_get_priv(dev);
-
- scpd->type = (enum scp_domain_type)dev_get_driver_data(dev);
-
- switch (scpd->type) {
- case SCPSYS_MT7623:
- scpd->data = scp_domain_mt7623;
- break;
- case SCPSYS_MT7622:
- case SCPSYS_MT7629:
- scpd->data = scp_domain_mt7629;
- break;
- default:
- return -EINVAL;
- }
+ ret = clk_disable_bulk(&domain->clks);
+ if (ret)
+ return ret;
return 0;
}
-static int mtk_power_domain_probe(struct udevice *dev)
+int mtk_scpsys_probe(struct udevice *dev)
{
struct ofnode_phandle_args args;
- struct scp_domain *scpd = dev_get_priv(dev);
+ struct mtk_scpsys *scpsys = dev_get_priv(dev);
struct regmap *regmap;
struct clk_bulk bulk;
- int err;
+ int err, i;
- scpd->base = dev_read_addr_ptr(dev);
- if (!scpd->base)
+ scpsys->base = dev_read_addr_ptr(dev);
+ if (!scpsys->base)
return -ENOENT;
- err = mtk_power_domain_hook(dev);
- if (err)
- return err;
+ scpsys->soc_data = (const struct mtk_scp_soc_data *)dev_get_driver_data(dev);
+
+ scpsys->domains = devm_kcalloc(dev, scpsys->soc_data->num_domains,
+ sizeof(*scpsys->domains), GFP_KERNEL);
+ if (!scpsys->domains)
+ return -ENOMEM;
+
+ for (i = 0; i < scpsys->soc_data->num_domains; i++)
+ scpsys->domains[i].data = &scpsys->soc_data->data[i];
/* get corresponding syscon phandle */
err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args);
@@ -362,12 +313,12 @@ static int mtk_power_domain_probe(struct udevice *dev)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- scpd->infracfg = regmap_get_range(regmap, 0);
- if (!scpd->infracfg)
+ scpsys->infracfg = regmap_get_range(regmap, 0);
+ if (!scpsys->infracfg)
return -ENOENT;
/* enable Infra DCM */
- setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
+ setbits_le32(scpsys->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
err = clk_get_bulk(dev, &bulk);
if (err)
@@ -376,33 +327,180 @@ static int mtk_power_domain_probe(struct udevice *dev)
return clk_enable_bulk(&bulk);
}
-static const struct udevice_id mtk_power_domain_ids[] = {
- {
- .compatible = "mediatek,mt7622-scpsys",
- .data = SCPSYS_MT7622,
- },
- {
- .compatible = "mediatek,mt7623-scpsys",
- .data = SCPSYS_MT7623,
- },
- {
- .compatible = "mediatek,mt7629-scpsys",
- .data = SCPSYS_MT7629,
- },
- { /* sentinel */ }
-};
+static int mtk_scpsys_add_one_domain(struct udevice *dev, ofnode node, int parent_id)
+{
+ struct mtk_scpsys *scpsys = dev_get_priv(dev);
+ struct ofnode_phandle_args args;
+ struct mtk_scp_domain *domain;
+ struct regmap *regmap;
+ const char *clk_name;
+ int i, ret, num_clks;
+ u32 id;
-static const struct power_domain_ops mtk_power_domain_ops = {
- .off = scpsys_power_off,
- .on = scpsys_power_on,
- .request = scpsys_power_request,
-};
+ ret = ofnode_read_u32(node, "reg", &id);
+ if (ret) {
+ dev_err(dev, "%s: failed to retrieve domain id from reg: %d\n",
+ ofnode_get_name(node), ret);
+ return ret;
+ }
+
+ if (id >= scpsys->soc_data->num_domains) {
+ dev_err(dev, "%s: invalid domain id %d\n", ofnode_get_name(node), id);
+ return -EINVAL;
+ }
+
+ domain = &scpsys->domains[id];
+ domain->data = &scpsys->soc_data->data[id];
+
+ if (parent_id >= 0) {
+ domain->has_pd = true;
+ domain->parent_pd.dev = dev;
+ domain->parent_pd.id = parent_id;
+ }
+
+ if (ofnode_read_bool(node, "mediatek,infracfg")) {
+ ret = ofnode_parse_phandle_with_args(node, "mediatek,infracfg", NULL, 0, 0, &args);
+ if (ret)
+ return ret;
+
+ regmap = syscon_node_to_regmap(args.node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ domain->infracfg = regmap_get_range(regmap, 0);
+
+ /* enable Infra DCM */
+ if (domain->infracfg)
+ setbits_le32(domain->infracfg + INFRA_TOPDCM_CTRL,
+ DCM_TOP_EN);
+ }
+
+ num_clks = ofnode_read_string_count(node, "clock-names");
+ for (i = 0; i < num_clks; i++) {
+ ret = ofnode_read_string_index(node, "clock-names", i, &clk_name);
+ if (ret) {
+ dev_err(dev, "%s: failed to retrieve clock-names at index %i: %d\n",
+ ofnode_get_name(node), i, ret);
+ return ret;
+ }
+
+ if (strchr(clk_name, '-'))
+ domain->subsys_clks.count++;
+ else
+ domain->clks.count++;
+ }
+
+ if (domain->clks.count) {
+ domain->clks.clks = devm_kcalloc(dev, domain->clks.count,
+ sizeof(struct clk), GFP_KERNEL);
+ if (!domain->clks.clks)
+ return -ENOMEM;
+ }
+
+ if (domain->subsys_clks.count) {
+ domain->subsys_clks.clks = devm_kcalloc(dev,
+ domain->subsys_clks.count,
+ sizeof(struct clk), GFP_KERNEL);
+ if (!domain->subsys_clks.clks)
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < domain->clks.count; i++) {
+ ret = clk_get_by_index_nodev(node, i, &domain->clks.clks[i]);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to get clk at index %d: %d\n",
+ ofnode_get_name(node), i, ret);
+ goto err_put_clocks;
+ }
+ }
+
+ for (i = 0; i < domain->subsys_clks.count; i++) {
+ ret = clk_get_by_index_nodev(node, i + domain->clks.count,
+ &domain->subsys_clks.clks[i]);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to get subsys clk at index %d: %d\n",
+ ofnode_get_name(node), i + domain->clks.count, ret);
+ goto err_put_subsys_clocks;
+ }
+ }
+
+ return 0;
+
+err_put_subsys_clocks:
+ clk_release_all(domain->subsys_clks.clks, domain->subsys_clks.count);
+ domain->subsys_clks.count = 0;
+err_put_clocks:
+ clk_release_all(domain->clks.clks, domain->clks.count);
+ domain->clks.count = 0;
+ domain->data = NULL;
+ return ret;
+}
+
+static int mtk_scpsys_add_subdomain(struct udevice *dev, ofnode node)
+{
+ ofnode subnode;
+ int ret;
+ u32 id;
+
+ ret = ofnode_read_u32(node, "reg", &id);
+ if (ret) {
+ dev_err(dev, "%s: failed to get domain id\n", ofnode_get_name(node));
+ return ret;
+ }
+
+ ofnode_for_each_subnode(subnode, node) {
+ ret = mtk_scpsys_add_one_domain(dev, subnode, id);
+ if (ret) {
+ dev_err(dev, "failed to add child domain: %s\n",
+ ofnode_get_name(subnode));
+ continue;
+ }
+
+ ret = mtk_scpsys_add_subdomain(dev, subnode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mtk_power_controller_probe(struct udevice *dev)
+{
+ struct mtk_scpsys *scpsys = dev_get_priv(dev);
+ ofnode subnode;
+ int ret;
+
+ scpsys->base = dev_read_addr_ptr(dev_get_parent(dev));
+ if (!scpsys->base)
+ return -ENOENT;
+
+ scpsys->soc_data = (const struct mtk_scp_soc_data *)dev_get_driver_data(dev);
+
+ scpsys->domains = devm_kcalloc(dev, scpsys->soc_data->num_domains,
+ sizeof(*scpsys->domains), GFP_KERNEL);
+ if (!scpsys->domains)
+ return -ENOMEM;
+
+ dev_for_each_subnode(subnode, dev) {
+ ret = mtk_scpsys_add_one_domain(dev, subnode, -1);
+ if (ret) {
+ dev_err(dev, "failed to add child domain: %s\n",
+ ofnode_get_name(subnode));
+ continue;
+ }
+
+ ret = mtk_scpsys_add_subdomain(dev, subnode);
+ if (ret) {
+ dev_err(dev, "failed to add sub domain: %s\n",
+ ofnode_get_name(subnode));
+ return ret;
+ }
+ }
+
+ return 0;
+}
-U_BOOT_DRIVER(mtk_power_domain) = {
- .name = "mtk_power_domain",
- .id = UCLASS_POWER_DOMAIN,
- .ops = &mtk_power_domain_ops,
- .probe = mtk_power_domain_probe,
- .of_match = mtk_power_domain_ids,
- .priv_auto = sizeof(struct scp_domain),
+const struct power_domain_ops mtk_power_domain_ops = {
+ .off = mtk_scpsys_power_off,
+ .on = mtk_scpsys_power_on,
};
diff --git a/drivers/power/domain/mtk-power-domain.h b/drivers/power/domain/mtk-power-domain.h
new file mode 100644
index 00000000000..5bf0ca850ec
--- /dev/null
+++ b/drivers/power/domain/mtk-power-domain.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Copyright (C) 2026 BayLibre, SAS
+ * Author: Ryder Lee <[email protected]>
+ * Julien Stephan <[email protected]>
+ */
+
+#ifndef __MTK_POWER_DOMAIN_H
+#define __MTK_POWER_DOMAIN_H
+
+#include <clk.h>
+#include <power-domain-uclass.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+struct udevice;
+
+#define SPM_EN (0xb16 << 16 | 0x1)
+#define SPM_VDE_PWR_CON 0x0210
+#define SPM_MFG_PWR_CON 0x0214
+#define SPM_ISP_PWR_CON 0x0238
+#define SPM_DIS_PWR_CON 0x023c
+#define SPM_CONN_PWR_CON 0x0280
+#define SPM_BDP_PWR_CON 0x029c
+#define SPM_ETH_PWR_CON 0x02a0
+#define SPM_HIF_PWR_CON 0x02a4
+#define SPM_IFR_MSC_PWR_CON 0x02a8
+#define SPM_ETHSYS_PWR_CON 0x2e0
+#define SPM_HIF0_PWR_CON 0x2e4
+#define SPM_HIF1_PWR_CON 0x2e8
+#define SPM_PWR_STATUS 0x60c
+#define SPM_PWR_STATUS_2ND 0x610
+
+#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_ETHSYS BIT(24)
+#define PWR_STATUS_HIF0 BIT(25)
+#define PWR_STATUS_HIF1 BIT(26)
+
+/* Infrasys configuration */
+#define INFRA_TOPDCM_CTRL 0x10
+#define INFRA_TOPAXI_PROT_EN 0x220
+#define INFRA_TOPAXI_PROT_STA1 0x228
+
+#define DCM_TOP_EN BIT(0)
+
+#define SPM_MAX_BUS_PROT_DATA 6
+
+struct mtk_scp_domain;
+
+struct mtk_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 mtk_scp_domain_data {
+ u32 sta_mask;
+ int ctl_offs;
+ u32 sram_pdn_bits;
+ u32 sram_pdn_ack_bits;
+ u32 bus_prot_mask;
+ const struct mtk_scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA];
+ int pwr_sta_offs;
+ int pwr_sta2nd_offs;
+};
+
+struct mtk_scp_soc_data {
+ const struct mtk_scp_domain_data *data;
+ int num_domains;
+};
+
+#define MTK_SCP_SOC_DATA(_name, _domains) \
+static const struct mtk_scp_soc_data _name##_scp_soc_data = { \
+ .data = _domains, \
+ .num_domains = ARRAY_SIZE(_domains), \
+}
+
+struct mtk_scp_domain {
+ const struct mtk_scp_domain_data *data;
+ void __iomem *infracfg;
+ struct clk_bulk clks;
+ struct clk_bulk subsys_clks;
+ bool has_pd;
+ struct power_domain parent_pd;
+};
+
+struct mtk_scpsys {
+ void __iomem *base;
+ void __iomem *infracfg;
+ const struct mtk_scp_soc_data *soc_data;
+ struct mtk_scp_domain *domains;
+};
+
+#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)
+
+int mtk_scpsys_probe(struct udevice *dev);
+int mtk_power_controller_probe(struct udevice *dev);
+
+extern const struct power_domain_ops mtk_power_domain_ops;
+
+#endif /* __MTK_POWER_DOMAIN_H */
diff --git a/drivers/power/domain/renesas-r8a78000-power-domain.c b/drivers/power/domain/renesas-r8a78000-power-domain.c
index 57b3b56b2d9..62b56fd8ae0 100644
--- a/drivers/power/domain/renesas-r8a78000-power-domain.c
+++ b/drivers/power/domain/renesas-r8a78000-power-domain.c
@@ -166,6 +166,7 @@ struct rst_map_in {
#define GEN5_SCMI_SDK_4_30 0x010c0000
#define GEN5_SCMI_SDK_4_31 0x010d0000
#define GEN5_SCMI_SDK_4_32 0x010e0000
+#define GEN5_SCMI_SDK_4_36 0x01100000
static const struct rst_map_in gen5_rst_map_dt_sdk_4_28[] = {
{ SCP_RESET_DOMAIN_ID_UFS0, 202 },
@@ -220,7 +221,8 @@ static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl,
map = gen5_rst_map_dt_sdk_4_28;
map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_28);
} else if (priv->basever == GEN5_SCMI_SDK_4_31 ||
- priv->basever == GEN5_SCMI_SDK_4_32) {
+ priv->basever == GEN5_SCMI_SDK_4_32 ||
+ priv->basever == GEN5_SCMI_SDK_4_36) {
map = gen5_rst_map_dt_sdk_4_31;
map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_31);
} else {
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 4bd9b4e1940..95687d0bdfd 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -171,6 +171,21 @@ config SPL_DM_PMIC_PCA9450
This config enables implementation of driver-model pmic uclass features
for PMIC PCA9450 in SPL. The driver implements read/write operations.
+config DM_PMIC_PF9453
+ bool "Enable Driver Model for PMIC PF9453"
+ depends on DM_I2C
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PF9453. The driver implements read/write operations.
+
+config SPL_DM_PMIC_PF9453
+ bool "Enable Driver Model for PMIC PF9453 in SPL"
+ depends on SPL_DM_PMIC
+ depends on SPL_DM_I2C
+ help
+ This config enables implementation of driver-model pmic uclass features
+ for PMIC PF9453 in SPL. The driver implements read/write operations.
+
config DM_PMIC_PFUZE100
bool "Enable Driver Model for PMIC PFUZE100"
help
@@ -434,6 +449,14 @@ config PMIC_RAA215300
allows register access and will bind the sysreset driver
(CONFIG_SYSRESET_RAA215300) if it is enabled.
+config PMIC_SPACEMIT_P1
+ bool "Enable driver for Spacemit P1 power management chip"
+ depends on DM_PMIC
+ help
+ The P1 PMIC integrates multiple functions including
+ voltage regulators, a watchdog timer, GPIO interfaces, and a
+ real-time clock.
+
config DM_PMIC_MTK_PWRAP
bool "Enable driver for MediaTek PMIC Wrapper Support"
help
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 2cda5a892fd..da9b810de90 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(PHASE_)DM_PMIC_BD71837) += bd71837.o
obj-$(CONFIG_$(PHASE_)DM_PMIC_MP5416) += mp5416.o
obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o
obj-$(CONFIG_$(PHASE_)DM_PMIC_PCA9450) += pca9450.o
+obj-$(CONFIG_$(PHASE_)DM_PMIC_PF9453) += pf9453.o
obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
obj-$(CONFIG_PMIC_AB8500) += ab8500.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_$(PHASE_)DM_PMIC_TPS80031) += tps80031.o
obj-$(CONFIG_$(PHASE_)PMIC_PALMAS) += palmas.o
obj-$(CONFIG_$(PHASE_)PMIC_LP873X) += lp873x.o
obj-$(CONFIG_$(PHASE_)PMIC_LP87565) += lp87565.o
+obj-$(CONFIG_PMIC_SPACEMIT_P1) += pmic_spacemit_p1.o
obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
obj-$(CONFIG_PMIC_TPS65217) += pmic_tps65217.o
obj-$(CONFIG_PMIC_TPS65219) += tps65219.o
diff --git a/drivers/power/pmic/pf9453.c b/drivers/power/pmic/pf9453.c
new file mode 100644
index 00000000000..71d766bce5b
--- /dev/null
+++ b/drivers/power/pmic/pf9453.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP
+ */
+
+#include <asm/global_data.h>
+#include <asm-generic/gpio.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <i2c.h>
+#include <linux/err.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/pf9453.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+ /* buck */
+ { .prefix = "b", .driver = PF9453_REGULATOR_DRIVER},
+ { .prefix = "B", .driver = PF9453_REGULATOR_DRIVER},
+ /* ldo */
+ { .prefix = "l", .driver = PF9453_REGULATOR_DRIVER},
+ { .prefix = "L", .driver = PF9453_REGULATOR_DRIVER},
+ { },
+};
+
+struct pf9453_priv {
+ struct gpio_desc *sd_vsel_gpio;
+};
+
+static int pf9453_reg_count(struct udevice *dev)
+{
+ return PF9453_REG_NUM;
+}
+
+static bool is_reg_protect(uint reg)
+{
+ switch (reg) {
+ case PF9453_BUCK1OUT:
+ case PF9453_BUCK2OUT:
+ case PF9453_BUCK3OUT:
+ case PF9453_BUCK4OUT:
+ case PF9453_LDO1OUT_L:
+ case PF9453_LDO1OUT_H:
+ case PF9453_LDO2OUT:
+ case PF9453_LDOSNVS_CFG1:
+ case PF9453_BUCK2OUT_MAX_LIMIT:
+ case PF9453_BUCK2OUT_MIN_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int pf9453_write(struct udevice *dev, uint reg, const uint8_t *buff, int len)
+{
+ bool is_pro;
+ u32 val = PF9453_UNLOCK_KEY;
+
+ is_pro = is_reg_protect(reg);
+ if (is_pro) {
+ if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ val = PF9453_LOCK_KEY;
+ if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+ } else {
+ if (dm_i2c_write(dev, reg, buff, len)) {
+ pr_err("write error to device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int pf9453_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+{
+ if (dm_i2c_read(dev, reg, buff, len)) {
+ pr_err("read error from device: %p register: %#x!\n", dev, reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pf9453_bind(struct udevice *dev)
+{
+ int children;
+ ofnode regulators_node;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s: %s regulators subnode not found!", __func__,
+ dev->name);
+ return -ENXIO;
+ }
+
+ debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
+
+ children = pmic_bind_children(dev, regulators_node,
+ pmic_children_info);
+ if (!children)
+ debug("%s: %s - no child found\n", __func__, dev->name);
+
+ /* Always return success for this device */
+ return 0;
+}
+
+static int pf9453_probe(struct udevice *dev)
+{
+ struct pf9453_priv *priv = dev_get_priv(dev);
+ unsigned int reset_ctrl;
+ int ret = 0;
+
+ if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PF9453)) {
+ priv->sd_vsel_gpio = devm_gpiod_get_optional(dev, "sd-vsel",
+ GPIOD_IS_OUT |
+ GPIOD_IS_OUT_ACTIVE);
+ if (IS_ERR(priv->sd_vsel_gpio)) {
+ ret = PTR_ERR(priv->sd_vsel_gpio);
+ dev_err(dev, "Failed to request SD_VSEL GPIO: %d\n", ret);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset"))
+ reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_WARM;
+ else
+ reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_COLD;
+
+ return pmic_clrsetbits(dev, PF9453_RESET_CTRL,
+ PF9453_PMIC_RESET_WDOG_B_CFG_MASK, reset_ctrl);
+}
+
+static struct dm_pmic_ops pf9453_ops = {
+ .reg_count = pf9453_reg_count,
+ .read = pf9453_read,
+ .write = pf9453_write,
+};
+
+static const struct udevice_id pf9453_ids[] = {
+ { .compatible = "nxp,pf9453", .data = NXP_CHIP_TYPE_PF9453, },
+ { }
+};
+
+U_BOOT_DRIVER(pmic_pf9453) = {
+ .name = "pf9453 pmic",
+ .id = UCLASS_PMIC,
+ .of_match = pf9453_ids,
+ .bind = pf9453_bind,
+ .probe = pf9453_probe,
+ .ops = &pf9453_ops,
+ .priv_auto = sizeof(struct pf9453_priv),
+};
diff --git a/drivers/power/pmic/pmic_spacemit_p1.c b/drivers/power/pmic/pmic_spacemit_p1.c
new file mode 100644
index 00000000000..46c5926874c
--- /dev/null
+++ b/drivers/power/pmic/pmic_spacemit_p1.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025-2026 RISCstar Ltd.
+ */
+
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/spacemit_p1.h>
+
+static int pmic_p1_reg_count(struct udevice *dev)
+{
+ return P1_MAX_REGS;
+}
+
+static int pmic_p1_write(struct udevice *dev, uint reg, const u8 *buffer,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_write(dev, reg, buffer, len);
+ if (ret)
+ pr_err("%s write error on register %02x\n", dev->name, reg);
+
+ return ret;
+}
+
+static int pmic_p1_read(struct udevice *dev, uint reg, u8 *buffer,
+ int len)
+{
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, buffer, len);
+ if (ret)
+ pr_err("%s read error on register %02x\n", dev->name, reg);
+
+ return ret;
+}
+
+static const struct pmic_child_info p1_children_info[] = {
+ { .prefix = "buck", .driver = P1_BUCK_DRIVER },
+ { .prefix = "aldo", .driver = P1_ALDO_DRIVER },
+ { .prefix = "dldo", .driver = P1_DLDO_DRIVER },
+ { },
+};
+
+static int pmic_p1_bind(struct udevice *dev)
+{
+ const struct pmic_child_info *p1_children_info =
+ (struct pmic_child_info *)dev_get_driver_data(dev);
+ ofnode regulators_node;
+ int children;
+
+ regulators_node = dev_read_subnode(dev, "regulators");
+ if (!ofnode_valid(regulators_node)) {
+ debug("%s regulators subnode not found\n", dev->name);
+ return -EINVAL;
+ }
+
+ children = pmic_bind_children(dev, regulators_node,
+ p1_children_info);
+ if (!children)
+ debug("%s has no children (regulators)\n", dev->name);
+
+ return 0;
+}
+
+static int pmic_p1_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static struct dm_pmic_ops pmic_p1_ops = {
+ .reg_count = pmic_p1_reg_count,
+ .read = pmic_p1_read,
+ .write = pmic_p1_write,
+};
+
+static const struct udevice_id pmic_p1_match[] = {
+ {
+ .compatible = "spacemit,p1",
+ .data = (ulong)&p1_children_info,
+ }, {
+ /* sentinel */
+ }
+};
+
+U_BOOT_DRIVER(pmic_p1) = {
+ .name = "pmic_p1",
+ .id = UCLASS_PMIC,
+ .of_match = pmic_p1_match,
+ .bind = pmic_p1_bind,
+ .probe = pmic_p1_probe,
+ .ops = &pmic_p1_ops,
+};
diff --git a/drivers/power/pmic/tps65219.c b/drivers/power/pmic/tps65219.c
index 0716af027a3..1fecde84795 100644
--- a/drivers/power/pmic/tps65219.c
+++ b/drivers/power/pmic/tps65219.c
@@ -55,6 +55,7 @@ static int tps65219_bind(struct udevice *dev)
if (!ofnode_valid(regulators_node)) {
debug("%s: %s regulators subnode not found!\n", __func__,
dev->name);
+ return -ENXIO;
}
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 9f80bb953e8..00a25acfdf9 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -103,6 +103,21 @@ config SPL_DM_REGULATOR_PCA9450
This config enables implementation of driver-model regulator uclass
features for regulators on ROHM PCA9450 in SPL.
+config DM_REGULATOR_PF9453
+ bool "Enable Driver Model for NXP PF9453 regulators"
+ depends on DM_REGULATOR && DM_PMIC_PF9453
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on NXP PF9453 PMICs. PF9453 contains 6 bucks
+ and 5 LDOS. The driver implements get/set api for value and enable.
+
+config SPL_DM_REGULATOR_PF9453
+ bool "Enable Driver Model for NXP PF9453 regulators in SPL"
+ depends on DM_REGULATOR_PF9453 && SPL
+ help
+ This config enables implementation of driver-model regulator uclass
+ features for regulators on ROHM PF9453 in SPL.
+
config DM_REGULATOR_DA9063
bool "Enable Driver Model for REGULATOR DA9063"
depends on DM_REGULATOR && DM_PMIC_DA9063
@@ -600,3 +615,10 @@ config SANDBOX_PMBUS
(DM_REGULATOR_PMBUS_GENERIC) and the pmbus CLI command can be
exercised by the dm unit tests with no real hardware. Only
useful for testing; say N on real boards.
+
+config DM_REGULATOR_SPACEMIT_P1
+ bool "Enable driver for Spacemit P1 PMIC regulators"
+ depends on DM_REGULATOR && PMIC_SPACEMIT_P1
+ help
+ Enable implementation of driver-model regulator uclass features
+ for regulator P1. The driver supports BUCKs, LDOs and SWITCHes.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index b8599ea7fd9..a40c9d340d9 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PFUZE100) += pfuze100.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_BD71837) += bd71837.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PCA9450) += pca9450.o
+obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PF9453) += pf9453.o
obj-$(CONFIG_$(PHASE_)REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_COMMON) += regulator_common.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o
obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
+obj-$(CONFIG_DM_REGULATOR_SPACEMIT_P1) += spacemit_p1_regulator.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PALMAS) += palmas_regulator.o
obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PBIAS) += pbias_regulator.o
diff --git a/drivers/power/regulator/pf9453.c b/drivers/power/regulator/pf9453.c
new file mode 100644
index 00000000000..6ecde09bafa
--- /dev/null
+++ b/drivers/power/regulator/pf9453.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NXP PF9453 regulator driver
+ * Copyright 2024 NXP
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include <power/pf9453.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+
+/**
+ * struct pf9453_vrange - describe linear range of voltages
+ *
+ * @min_volt: smallest voltage in range
+ * @step: how much voltage changes at each selector step
+ * @min_sel: smallest selector in the range
+ * @max_sel: maximum selector in the range
+ */
+struct pf9453_vrange {
+ unsigned int min_volt;
+ unsigned int step;
+ u8 min_sel;
+ u8 max_sel;
+};
+
+/**
+ * struct pf9453_plat - describe regulator control registers
+ *
+ * @name: name of the regulator. Used for matching the dt-entry
+ * @enable_reg: register address used to enable/disable regulator
+ * @enablemask: register mask used to enable/disable regulator
+ * @volt_reg: register address used to configure regulator voltage
+ * @volt_mask: register mask used to configure regulator voltage
+ * @ranges: pointer to ranges of regulator voltages and matching register
+ * values
+ * @numranges: number of voltage ranges pointed by ranges
+ */
+struct pf9453_plat {
+ const char *name;
+ u8 enable_reg;
+ u8 enablemask;
+ u8 volt_reg;
+ u8 volt_mask;
+ struct pf9453_vrange *ranges;
+ unsigned int numranges;
+};
+
+#define PCA_RANGE(_min, _vstep, _sel_low, _sel_hi) \
+{ \
+ .min_volt = (_min), .step = (_vstep), \
+ .min_sel = (_sel_low), .max_sel = (_sel_hi), \
+}
+
+#define PCA_DATA(_name, enreg, enmask, vreg, vmask, _range, _numranges) \
+{ \
+ .name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
+ .volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
+ .numranges = _numranges \
+}
+
+static struct pf9453_vrange pf9453_buck134_vranges[] = {
+ PCA_RANGE(600000, 25000, 0, 0x7f),
+};
+
+static struct pf9453_vrange pf9453_buck2_vranges[] = {
+ PCA_RANGE(600000, 12500, 0, 0x7f),
+};
+
+static struct pf9453_vrange pf9453_ldo1_vranges[] = {
+ PCA_RANGE(800000, 25000, 0x0, 0x64),
+};
+
+static struct pf9453_vrange pf9453_ldo2_vranges[] = {
+ PCA_RANGE(500000, 25000, 0x0, 0x3a),
+};
+
+static struct pf9453_vrange pf9453_ldosnvs_vranges[] = {
+ PCA_RANGE(800000, 25000, 0x0, 0x58),
+};
+
+static struct pf9453_plat pf9453_reg_data[] = {
+ PCA_DATA("BUCK1", PF9453_BUCK1CTRL, PF9453_EN_MODE_MASK,
+ PF9453_BUCK1OUT, PF9453_BUCK_RUN_MASK,
+ pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
+ PCA_DATA("BUCK2", PF9453_BUCK2CTRL, PF9453_EN_MODE_MASK,
+ PF9453_BUCK2OUT, PF9453_BUCK_RUN_MASK,
+ pf9453_buck2_vranges, ARRAY_SIZE(pf9453_buck2_vranges)),
+ PCA_DATA("BUCK3", PF9453_BUCK3CTRL, PF9453_EN_MODE_MASK,
+ PF9453_BUCK3OUT, PF9453_BUCK_RUN_MASK,
+ pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
+ PCA_DATA("BUCK4", PF9453_BUCK4CTRL, PF9453_EN_MODE_MASK,
+ PF9453_BUCK4OUT, PF9453_BUCK_RUN_MASK,
+ pf9453_buck134_vranges, ARRAY_SIZE(pf9453_buck134_vranges)),
+ /* LDOs */
+ PCA_DATA("LDO1", PF9453_LDO1CFG, PF9453_EN_MODE_MASK,
+ PF9453_LDO1OUT_H, PF9453_LDO1_MASK,
+ pf9453_ldo1_vranges, ARRAY_SIZE(pf9453_ldo1_vranges)),
+ PCA_DATA("LDO2", PF9453_LDO2CFG, PF9453_EN_MODE_MASK,
+ PF9453_LDO2OUT, PF9453_LDO2_MASK,
+ pf9453_ldo2_vranges, ARRAY_SIZE(pf9453_ldo2_vranges)),
+ PCA_DATA("LDO-SNVS", PF9453_LDOSNVS_CFG2, PF9453_EN_MODE_MASK,
+ PF9453_LDOSNVS_CFG1, PF9453_LDOSNVS_MASK,
+ pf9453_ldosnvs_vranges, ARRAY_SIZE(pf9453_ldosnvs_vranges)),
+};
+
+static int vrange_find_value(struct pf9453_vrange *r, unsigned int sel,
+ unsigned int *val)
+{
+ if (!val || sel < r->min_sel || sel > r->max_sel)
+ return -EINVAL;
+
+ *val = r->min_volt + r->step * (sel - r->min_sel);
+ return 0;
+}
+
+static int vrange_find_selector(struct pf9453_vrange *r, int val,
+ unsigned int *sel)
+{
+ int ret = -EINVAL;
+ int num_vals = r->max_sel - r->min_sel + 1;
+
+ if (val >= r->min_volt &&
+ val <= r->min_volt + r->step * (num_vals - 1)) {
+ if (r->step) {
+ *sel = r->min_sel + ((val - r->min_volt) / r->step);
+ ret = 0;
+ } else {
+ *sel = r->min_sel;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int pf9453_get_enable(struct udevice *dev)
+{
+ struct pf9453_plat *plat = dev_get_plat(dev);
+ int val;
+
+ val = pmic_reg_read(dev->parent, plat->enable_reg);
+ if (val < 0)
+ return val;
+
+ return (val & plat->enablemask);
+}
+
+static int pf9453_set_enable(struct udevice *dev, bool enable)
+{
+ int val = 0;
+ struct pf9453_plat *plat = dev_get_plat(dev);
+
+ if (enable)
+ val = plat->enablemask;
+
+ return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
+ val);
+}
+
+static int pf9453_get_value(struct udevice *dev)
+{
+ struct pf9453_plat *plat = dev_get_plat(dev);
+ unsigned int reg, tmp;
+ int i, ret;
+
+ ret = pmic_reg_read(dev->parent, plat->volt_reg);
+ if (ret < 0)
+ return ret;
+
+ reg = ret;
+ reg &= plat->volt_mask;
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct pf9453_vrange *r = &plat->ranges[i];
+
+ if (!vrange_find_value(r, reg, &tmp))
+ return tmp;
+ }
+
+ pr_err("Unknown voltage value read from pmic\n");
+
+ return -EINVAL;
+}
+
+static int pf9453_set_value(struct udevice *dev, int uvolt)
+{
+ struct pf9453_plat *plat = dev_get_plat(dev);
+ unsigned int sel;
+ int i, found = 0;
+
+ for (i = 0; i < plat->numranges; i++) {
+ struct pf9453_vrange *r = &plat->ranges[i];
+
+ found = !vrange_find_selector(r, uvolt, &sel);
+ if (found) {
+ unsigned int tmp;
+
+ /*
+ * We require exactly the requested value to be
+ * supported - this can be changed later if needed
+ */
+ found = !vrange_find_value(r, sel, &tmp);
+ if (found && tmp == uvolt)
+ break;
+ found = 0;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ return pmic_clrsetbits(dev->parent, plat->volt_reg,
+ plat->volt_mask, sel);
+}
+
+static int pf9453_regulator_probe(struct udevice *dev)
+{
+ struct pf9453_plat *plat = dev_get_plat(dev);
+ int i, type;
+
+ type = dev_get_driver_data(dev_get_parent(dev));
+
+ if (type != NXP_CHIP_TYPE_PF9453) {
+ debug("Unknown PMIC type\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pf9453_reg_data); i++) {
+ if (strcmp(dev->name, pf9453_reg_data[i].name))
+ continue;
+ *plat = pf9453_reg_data[i];
+ return 0;
+ }
+
+ pr_err("Unknown regulator '%s'\n", dev->name);
+
+ return -ENOENT;
+}
+
+static const struct dm_regulator_ops pf9453_regulator_ops = {
+ .get_value = pf9453_get_value,
+ .set_value = pf9453_set_value,
+ .get_enable = pf9453_get_enable,
+ .set_enable = pf9453_set_enable,
+};
+
+U_BOOT_DRIVER(pf9453_regulator) = {
+ .name = PF9453_REGULATOR_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &pf9453_regulator_ops,
+ .probe = pf9453_regulator_probe,
+ .plat_auto = sizeof(struct pf9453_plat),
+};
diff --git a/drivers/power/regulator/spacemit_p1_regulator.c b/drivers/power/regulator/spacemit_p1_regulator.c
new file mode 100644
index 00000000000..7b5eb710edf
--- /dev/null
+++ b/drivers/power/regulator/spacemit_p1_regulator.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025-2026 RISCstar Ltd.
+ */
+
+#include <dm.h>
+#include <dm/lists.h>
+#include <errno.h>
+#include <log.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/spacemit_p1.h>
+
+struct p1_reg_info {
+ uint min_uv;
+ uint step_uv;
+ u8 vsel_reg;
+ u8 vsel_sleep_reg;
+ u8 config_reg;
+ u8 vsel_mask;
+ u8 min_sel;
+ u8 max_sel;
+};
+
+static const struct p1_reg_info p1_bucks[] = {
+ /* BUCK 1 */
+ { 500000, 5000, P1_BUCK_VSEL(1), P1_BUCK_SVSEL(1), P1_BUCK_CTRL(1),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(1), P1_BUCK_SVSEL(1), P1_BUCK_CTRL(1),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+ /* BUCK 2 */
+ { 500000, 5000, P1_BUCK_VSEL(2), P1_BUCK_SVSEL(2), P1_BUCK_CTRL(2),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(2), P1_BUCK_SVSEL(2), P1_BUCK_CTRL(2),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+ /* BUCK 3 */
+ { 500000, 5000, P1_BUCK_VSEL(3), P1_BUCK_SVSEL(3), P1_BUCK_CTRL(3),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(3), P1_BUCK_SVSEL(3), P1_BUCK_CTRL(3),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+ /* BUCK 4 */
+ { 500000, 5000, P1_BUCK_VSEL(4), P1_BUCK_SVSEL(4), P1_BUCK_CTRL(4),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(4), P1_BUCK_SVSEL(4), P1_BUCK_CTRL(4),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+ /* BUCK 5 */
+ { 500000, 5000, P1_BUCK_VSEL(5), P1_BUCK_SVSEL(5), P1_BUCK_CTRL(5),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(5), P1_BUCK_SVSEL(5), P1_BUCK_CTRL(5),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+ /* BUCK 6 */
+ { 500000, 5000, P1_BUCK_VSEL(6), P1_BUCK_SVSEL(6), P1_BUCK_CTRL(6),
+ BUCK_VSEL_MASK, 0x00, 0xaa },
+ { 1375000, 25000, P1_BUCK_VSEL(6), P1_BUCK_SVSEL(6), P1_BUCK_CTRL(6),
+ BUCK_VSEL_MASK, 0xab, 0xfe },
+};
+
+static const struct p1_reg_info p1_aldos[] = {
+ /* ALDO 1 */
+ { 500000, 25000, P1_ALDO_VOLT(1), P1_ALDO_SVOLT(1), P1_ALDO_CTRL(1),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* ALDO 2 */
+ { 500000, 25000, P1_ALDO_VOLT(2), P1_ALDO_SVOLT(2), P1_ALDO_CTRL(2),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* ALDO 3 */
+ { 500000, 25000, P1_ALDO_VOLT(3), P1_ALDO_SVOLT(3), P1_ALDO_CTRL(3),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* ALDO 4 */
+ { 500000, 25000, P1_ALDO_VOLT(4), P1_ALDO_SVOLT(4), P1_ALDO_CTRL(4),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+};
+
+static const struct p1_reg_info p1_dldos[] = {
+ /* DLDO 1 */
+ { 500000, 25000, P1_DLDO_VOLT(1), P1_DLDO_SVOLT(1), P1_DLDO_CTRL(1),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 2 */
+ { 500000, 25000, P1_DLDO_VOLT(2), P1_DLDO_SVOLT(2), P1_DLDO_CTRL(2),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 3 */
+ { 500000, 25000, P1_DLDO_VOLT(3), P1_DLDO_SVOLT(3), P1_DLDO_CTRL(3),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 4 */
+ { 500000, 25000, P1_DLDO_VOLT(4), P1_DLDO_SVOLT(4), P1_DLDO_CTRL(4),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 5 */
+ { 500000, 25000, P1_DLDO_VOLT(5), P1_DLDO_SVOLT(5), P1_DLDO_CTRL(5),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 6 */
+ { 500000, 25000, P1_DLDO_VOLT(6), P1_DLDO_SVOLT(6), P1_DLDO_CTRL(6),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+ /* DLDO 7 */
+ { 500000, 25000, P1_DLDO_VOLT(7), P1_DLDO_SVOLT(7), P1_DLDO_CTRL(7),
+ ALDO_VSEL_MASK, 0x0b, 0x7f },
+};
+
+static const struct p1_reg_info *get_buck_reg(struct udevice *pmic,
+ int idx, int uvolt)
+{
+ if (idx < 0)
+ return NULL;
+ if (uvolt < 1375000)
+ return &p1_bucks[(idx - 1) * 2 + 0];
+ return &p1_bucks[(idx - 1) * 2 + 1];
+}
+
+static const struct p1_reg_info *get_aldo_reg(struct udevice *pmic,
+ int idx, int uvolt)
+{
+ if (idx < 1 || idx > ARRAY_SIZE(p1_aldos))
+ return NULL;
+ return &p1_aldos[idx - 1];
+}
+
+static const struct p1_reg_info *get_dldo_reg(struct udevice *pmic,
+ int idx, int uvolt)
+{
+ if (idx < 1 || idx > ARRAY_SIZE(p1_dldos))
+ return NULL;
+ return &p1_dldos[idx - 1];
+}
+
+static int buck_get_value(struct udevice *dev)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->read)
+ return -ENOSYS;
+
+ info = get_buck_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+ val = ret & info->vsel_mask;
+ while (val > info->max_sel)
+ info++;
+
+ return info->min_uv + (val - info->min_sel) * info->step_uv;
+}
+
+static int buck_set_value(struct udevice *dev, int uvolt)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->write)
+ return -ENOSYS;
+
+ info = get_buck_reg(dev->parent, dev->driver_data, uvolt);
+ if (!info)
+ return -ENOENT;
+ val = (uvolt - info->min_uv);
+ val = val / info->step_uv;
+ val += info->min_sel;
+ ret = pmic_reg_write(dev->parent, info->vsel_reg, val);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int buck_get_enable(struct udevice *dev)
+{
+ const struct p1_reg_info *info;
+ int ret;
+
+ info = get_buck_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ return ret & BUCK_EN_MASK;
+}
+
+static int buck_set_enable(struct udevice *dev, bool enable)
+{
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ info = get_buck_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ val = (unsigned int)ret;
+ val &= BUCK_EN_MASK;
+
+ if (enable == val)
+ return 0;
+
+ val = enable;
+ ret = pmic_clrsetbits(dev->parent, info->config_reg, BUCK_EN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops p1_buck_ops = {
+ .get_value = buck_get_value,
+ .set_value = buck_set_value,
+ .get_enable = buck_get_enable,
+ .set_enable = buck_set_enable,
+};
+
+static int p1_buck_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_BUCK;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(p1_buck) = {
+ .name = P1_BUCK_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &p1_buck_ops,
+ .probe = p1_buck_probe,
+};
+
+static int aldo_get_value(struct udevice *dev)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->read)
+ return -ENOSYS;
+
+ info = get_aldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & info->vsel_mask;
+ while (val > info->max_sel)
+ info++;
+
+ return info->min_uv + (val - info->min_sel) * info->step_uv;
+}
+
+static int aldo_set_value(struct udevice *dev, int uvolt)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->write)
+ return -ENOSYS;
+
+ info = get_aldo_reg(dev->parent, dev->driver_data, uvolt);
+ if (!info)
+ return -ENOENT;
+ val = (uvolt - info->min_uv);
+ val = val / info->step_uv;
+ val += info->min_sel;
+ ret = pmic_reg_write(dev->parent, info->vsel_reg, val);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int aldo_get_enable(struct udevice *dev)
+{
+ const struct p1_reg_info *info;
+ int ret;
+
+ info = get_aldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ return ret & ALDO_EN_MASK;
+}
+
+static int aldo_set_enable(struct udevice *dev, bool enable)
+{
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ info = get_aldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ val = (unsigned int)ret;
+ val &= ALDO_EN_MASK;
+
+ if (enable == val)
+ return 0;
+
+ val = enable;
+ ret = pmic_clrsetbits(dev->parent, info->config_reg, ALDO_EN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops p1_aldo_ops = {
+ .get_value = aldo_get_value,
+ .set_value = aldo_set_value,
+ .get_enable = aldo_get_enable,
+ .set_enable = aldo_set_enable,
+};
+
+static int p1_aldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(p1_aldo) = {
+ .name = P1_ALDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &p1_aldo_ops,
+ .probe = p1_aldo_probe,
+};
+
+static int dldo_get_value(struct udevice *dev)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->read)
+ return -ENOSYS;
+
+ info = get_dldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->vsel_reg);
+ if (ret < 0)
+ return ret;
+
+ val = ret & info->vsel_mask;
+ while (val > info->max_sel)
+ info++;
+
+ return info->min_uv + (val - info->min_sel) * info->step_uv;
+}
+
+static int dldo_set_value(struct udevice *dev, int uvolt)
+{
+ const struct dm_pmic_ops *ops = device_get_ops(dev->parent);
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ if (!ops || !ops->write)
+ return -ENOSYS;
+
+ info = get_dldo_reg(dev->parent, dev->driver_data, uvolt);
+ if (!info)
+ return -ENOENT;
+ val = (uvolt - info->min_uv);
+ val = val / info->step_uv;
+ val += info->min_sel;
+ ret = pmic_reg_write(dev->parent, info->vsel_reg, val);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int dldo_get_enable(struct udevice *dev)
+{
+ const struct p1_reg_info *info;
+ int ret;
+
+ info = get_dldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ return ret & DLDO_EN_MASK;
+}
+
+static int dldo_set_enable(struct udevice *dev, bool enable)
+{
+ const struct p1_reg_info *info;
+ uint val;
+ int ret;
+
+ info = get_dldo_reg(dev->parent, dev->driver_data, 0);
+ if (!info)
+ return -ENOENT;
+
+ ret = pmic_reg_read(dev->parent, info->config_reg);
+ if (ret < 0)
+ return ret;
+ val = (unsigned int)ret;
+ val &= DLDO_EN_MASK;
+
+ if (enable == val)
+ return 0;
+
+ val = enable;
+ ret = pmic_clrsetbits(dev->parent, info->config_reg, DLDO_EN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct dm_regulator_ops p1_dldo_ops = {
+ .get_value = dldo_get_value,
+ .set_value = dldo_set_value,
+ .get_enable = dldo_get_enable,
+ .set_enable = dldo_set_enable,
+};
+
+static int p1_dldo_probe(struct udevice *dev)
+{
+ struct dm_regulator_uclass_plat *uc_pdata;
+
+ uc_pdata = dev_get_uclass_plat(dev);
+
+ uc_pdata->type = REGULATOR_TYPE_LDO;
+ uc_pdata->mode_count = 0;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(p1_dldo) = {
+ .name = P1_DLDO_DRIVER,
+ .id = UCLASS_REGULATOR,
+ .ops = &p1_dldo_ops,
+ .probe = p1_dldo_probe,
+};