diff options
Diffstat (limited to 'drivers/power')
| -rw-r--r-- | drivers/power/domain/Kconfig | 89 | ||||
| -rw-r--r-- | drivers/power/domain/Makefile | 15 | ||||
| -rw-r--r-- | drivers/power/domain/mt2701-power-domain.c | 89 | ||||
| -rw-r--r-- | drivers/power/domain/mt7622-power-domain.c | 56 | ||||
| -rw-r--r-- | drivers/power/domain/mt8188-power-domain.c | 665 | ||||
| -rw-r--r-- | drivers/power/domain/mtk-power-domain.c | 576 | ||||
| -rw-r--r-- | drivers/power/domain/mtk-power-domain.h | 131 | ||||
| -rw-r--r-- | drivers/power/domain/renesas-r8a78000-power-domain.c | 4 | ||||
| -rw-r--r-- | drivers/power/pmic/Kconfig | 23 | ||||
| -rw-r--r-- | drivers/power/pmic/Makefile | 2 | ||||
| -rw-r--r-- | drivers/power/pmic/pf9453.c | 170 | ||||
| -rw-r--r-- | drivers/power/pmic/pmic_spacemit_p1.c | 94 | ||||
| -rw-r--r-- | drivers/power/pmic/tps65219.c | 1 | ||||
| -rw-r--r-- | drivers/power/regulator/Kconfig | 22 | ||||
| -rw-r--r-- | drivers/power/regulator/Makefile | 2 | ||||
| -rw-r--r-- | drivers/power/regulator/pf9453.c | 256 | ||||
| -rw-r--r-- | drivers/power/regulator/spacemit_p1_regulator.c | 464 |
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, +}; |
