Yidi Lin has submitted this change. ( https://review.coreboot.org/c/coreboot/+/84497?usp=email )
Change subject: soc/mediatek/mt8196: Add mtcmos init support ......................................................................
soc/mediatek/mt8196: Add mtcmos init support
Add mtcmos init code and APIs for controlling power domain.
TEST=build pass and driver init ok BUG=b:317009620
Signed-off-by: Guangjie Song guangjie.song@mediatek.corp-partner.google.com Change-Id: I44f2bb10453377a8412e80ac0c100760ebfbaff9 Reviewed-on: https://review.coreboot.org/c/coreboot/+/84497 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Yu-Ping Wu yupingso@google.com Reviewed-by: Yidi Lin yidilin@google.com --- M src/soc/mediatek/mt8196/Makefile.mk M src/soc/mediatek/mt8196/bootblock.c M src/soc/mediatek/mt8196/include/soc/memlayout.ld A src/soc/mediatek/mt8196/include/soc/spm_mtcmos.h A src/soc/mediatek/mt8196/mtcmos.c 5 files changed, 839 insertions(+), 1 deletion(-)
Approvals: Yidi Lin: Looks good to me, approved build bot (Jenkins): Verified Yu-Ping Wu: Looks good to me, approved
diff --git a/src/soc/mediatek/mt8196/Makefile.mk b/src/soc/mediatek/mt8196/Makefile.mk index b3a0834..0410129 100644 --- a/src/soc/mediatek/mt8196/Makefile.mk +++ b/src/soc/mediatek/mt8196/Makefile.mk @@ -16,6 +16,7 @@ bootblock-y += ../common/early_init.c bootblock-y += ../common/lastbus_v2.c lastbus.c bootblock-y += ../common/mmu_operations.c +bootblock-y += mtcmos.c bootblock-$(CONFIG_PCI) += ../common/pcie.c pcie.c bootblock-y += ../common/wdt.c ../common/wdt_req.c wdt.c
diff --git a/src/soc/mediatek/mt8196/bootblock.c b/src/soc/mediatek/mt8196/bootblock.c index 365a4e0..a864bff 100644 --- a/src/soc/mediatek/mt8196/bootblock.c +++ b/src/soc/mediatek/mt8196/bootblock.c @@ -6,6 +6,7 @@ #include <soc/lastbus_v2.h> #include <soc/mmu_operations.h> #include <soc/pll.h> +#include <soc/spm_mtcmos.h> #include <soc/wdt.h>
void bootblock_soc_init(void) @@ -15,6 +16,8 @@ lastbus_init(); mtk_wdt_init(); mt_pll_init(); + mtcmos_init(); mt_pll_post_init(); + mtcmos_post_init(); early_init_clear(); } diff --git a/src/soc/mediatek/mt8196/include/soc/memlayout.ld b/src/soc/mediatek/mt8196/include/soc/memlayout.ld index 1529a69..83e80b6 100644 --- a/src/soc/mediatek/mt8196/include/soc/memlayout.ld +++ b/src/soc/mediatek/mt8196/include/soc/memlayout.ld @@ -46,7 +46,7 @@ DRAM_INIT_CODE(0x02000000, 600K) #else /* The beginning 4K of SRAM_L2C is reserved for BOOTROM until BOOTBLOCK is started. */ - BOOTBLOCK(0x02001000, 78K) + BOOTBLOCK(0x02001000, 85K) #endif OVERLAP_DECOMPRESSOR_VERSTAGE_ROMSTAGE(0x02096000, 272K) PRERAM_CBFS_CACHE(0x020DA000, 48K) diff --git a/src/soc/mediatek/mt8196/include/soc/spm_mtcmos.h b/src/soc/mediatek/mt8196/include/soc/spm_mtcmos.h new file mode 100644 index 0000000..5cad800c9 --- /dev/null +++ b/src/soc/mediatek/mt8196/include/soc/spm_mtcmos.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SOC_MEDIATEK_MT8196_SPM_MTCMOS_H +#define SOC_MEDIATEK_MT8196_SPM_MTCMOS_H + +#include <commonlib/list.h> + +enum mtcmos_state { + MTCMOS_POWER_DOWN, + MTCMOS_POWER_ON, +}; + +enum mtcmos_id { + MTCMOS_ID_SSUSB_DP_PHY_P0, + MTCMOS_ID_SSUSB_P0, + MTCMOS_ID_SSUSB_P1, + MTCMOS_ID_SSUSB_P23, + MTCMOS_ID_SSUSB_PHY_P2, + MTCMOS_ID_UFS0_SHUTDOWN, + MTCMOS_ID_UFS0_PHY, + MTCMOS_ID_PEXTP_MAC0, + MTCMOS_ID_PEXTP_MAC1, + MTCMOS_ID_PEXTP_MAC2, + MTCMOS_ID_PEXTP_PHY0, + MTCMOS_ID_PEXTP_PHY1, + MTCMOS_ID_PEXTP_PHY2, + MTCMOS_ID_AUDIO, + MTCMOS_ID_ADSP_TOP_SHUTDOWN, + MTCMOS_ID_ADSP_INFRA, + MTCMOS_ID_ADSP_AO, + MTCMOS_ID_MM_PROC_SHUTDOWN, + MTCMOS_ID_SSRSYS, + MTCMOS_ID_DISP_VCORE, + MTCMOS_ID_DIS0_SHUTDOWN, + MTCMOS_ID_DIS1_SHUTDOWN, + MTCMOS_ID_OVL0_SHUTDOWN, + MTCMOS_ID_OVL1_SHUTDOWN, + MTCMOS_ID_DISP_EDPTX_SHUTDOWN, + MTCMOS_ID_DISP_DPTX_SHUTDOWN, + MTCMOS_ID_MM_INFRA0, + MTCMOS_ID_MM_INFRA1, + MTCMOS_ID_MM_INFRA_AO, + MTCMOS_ID_DSI_PHY0, + MTCMOS_ID_DSI_PHY1, + MTCMOS_ID_DSI_PHY2, + MTCMOS_ID_NUM, +}; + +struct mtcmos_cb { + int (*pre_on)(void); + int (*pre_off)(void); + int (*post_on)(void); + int (*post_off)(void); +}; + +int mtcmos_cb_register(enum mtcmos_id id, const struct mtcmos_cb *cb); +void mtcmos_ctrl(enum mtcmos_id id, enum mtcmos_state state); +void mtcmos_init(void); +void mtcmos_post_init(void); + +#endif diff --git a/src/soc/mediatek/mt8196/mtcmos.c b/src/soc/mediatek/mt8196/mtcmos.c new file mode 100644 index 0000000..367e74b --- /dev/null +++ b/src/soc/mediatek/mt8196/mtcmos.c @@ -0,0 +1,773 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * This file is created based on MTCMOS_SW_NOTE.xlsx + */ + +#include <console/console.h> +#include <delay.h> +#include <soc/addressmap.h> +#include <soc/mtcmos.h> +#include <soc/pll.h> +#include <soc/spm_mtcmos.h> +#include <timer.h> + +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->caps & (_x)) + +#define POWERON_CONFIG_EN ((void *)(SPM_BASE + 0x0000)) + +#define SPM_PROJECT_CODE 0xB16 + +#define SET_BUS_PROTECT 1 +#define RELEASE_BUS_PROTECT 0 + +#define WAIT_VOTE_TIMEOUT 20000 + +#define SPM_PBUS_BUS_PROTECT_EN_SET ((void *)(SPM_PBUS_BASE + 0x00DC)) +#define SPM_PBUS_BUS_PROTECT_EN_CLR ((void *)(SPM_PBUS_BASE + 0x00E0)) +#define SPM_PBUS_BUS_PROTECT_RDY_STA ((void *)(SPM_PBUS_BASE + 0x0208)) +#define SPM_PBUS_BUS_MSB_PROTECT_EN_SET ((void *)(SPM_PBUS_BASE + 0x00E8)) +#define SPM_PBUS_BUS_MSB_PROTECT_EN_CLR ((void *)(SPM_PBUS_BASE + 0x00EC)) +#define SPM_PBUS_BUS_MSB_PROTECT_RDY_STA ((void *)(SPM_PBUS_BASE + 0x020C)) + +#define MM_BUCK_ISO_CON_CLR ((void *)(MMPC_BASE + 0x00C8)) +#define DISP_AO_PWR_CON ((void *)(MMPC_BASE + 0x00E8)) +#define MMPC_BUS_PROTECT_EN_1_CLR ((void *)(MMPC_BASE + 0x0188)) + +#define MMVOTE_MTCMOS_0_SET ((void *)(MMVOTE_BASE + 0x0218)) +#define MMVOTE_MTCMOS_0_CLR ((void *)(MMVOTE_BASE + 0x021C)) +#define MMVOTE_MTCMOS_0_DONE ((void *)(MMVOTE_BASE + 0x141C)) +#define MMVOTE_MTCMOS_0_PM_ACK ((void *)(MMVOTE_BASE + 0x5514)) +#define MMVOTE_MTCMOS_1_SET ((void *)(MMVOTE_BASE + 0x0220)) +#define MMVOTE_MTCMOS_1_CLR ((void *)(MMVOTE_BASE + 0x0224)) +#define MMVOTE_MTCMOS_1_DONE ((void *)(MMVOTE_BASE + 0x142C)) +#define MMVOTE_MTCMOS_1_PM_ACK ((void *)(MMVOTE_BASE + 0x5518)) +#define MMINFRA_MTCMOS_1_SET ((void *)(MMVOTE_BASE + 0x43220)) +#define MMINFRA_MTCMOS_1_CLR ((void *)(MMVOTE_BASE + 0x43224)) + +#define DISP_VDISP_AO_CONFIG_CG 0x3E800108 +#define DISP_DPC_DISP0_MTCMOS_CFG 0x3E8F0500 +#define DISP_DPC_DISP1_MTCMOS_CFG 0x3E8F0580 +#define DISP_DPC_OVL0_MTCMOS_CFG 0x3E8F0600 +#define DISP_DPC_OVL1_MTCMOS_CFG 0x3E8F0680 +#define DISP_DPC_MML0_MTCMOS_CFG 0x3E8F0B00 +#define DISP_DPC_MML1_MTCMOS_CFG 0x3E8F0700 +#define DISP_DPC_EDP_MTCMOS_CFG 0x3E8F0C00 +#define DISP_DPC_EPTX_MTCMOS_CFG 0x3E8F0D00 + +#define MMINFRA0_VOTE_BIT 1 +#define MMINFRA1_VOTE_BIT 2 +#define MMINFRA_AO_VOTE_BIT 3 +#define DSI_PHY0_VOTE_BIT 7 +#define DSI_PHY1_VOTE_BIT 8 +#define DSI_PHY2_VOTE_BIT 9 +#define DISP_VCORE_VOTE_BIT 24 +#define DISP0_VOTE_BIT 25 +#define DISP1_VOTE_BIT 26 +#define OVL0_VOTE_BIT 27 +#define OVL1_VOTE_BIT 28 +#define DISP_EDPTX_VOTE_BIT 29 +#define DISP_DPTX_VOTE_BIT 30 + +#define MTK_SCPD_SRAM_ISO BIT(0) +#define MTK_SCPD_SRAM_SLP BIT(2) +#define MTK_SCPD_RTFF_DELAY BIT(6) +#define MTK_SCPD_NO_SRAM BIT(8) + +#define PWR_RST_B BIT(0) +#define PWR_ISO BIT(1) +#define PWR_ON BIT(2) +#define PWR_ON_2ND BIT(3) +#define PWR_CLK_DIS BIT(4) +#define SRAM_CKISO BIT(5) +#define SRAM_ISOINT_B BIT(6) +#define SRAM_PDN BIT(8) +#define SRAM_SLP BIT(9) +#define SRAM_PDN_ACK BIT(12) +#define SRAM_SLP_ACK BIT(13) +#define PWR_RTFF_SAVE BIT(24) +#define PWR_RTFF_SAVE_FLAG BIT(27) +#define PWR_ACK BIT(30) +#define PWR_ACK_2ND BIT(31) + +#define ACK_DELAY_US 10 +#define ACK_DELAY_TIMES 10000 + +#define ADSP_AO_PROT_STEP1_SHIFT 23 +#define ADSP_INFRA_PROT_STEP1_SHIFT 22 +#define ADSP_TOP_PROT_STEP1_SHIFT 21 +#define AUDIO_PROT_STEP1_SHIFT 19 +#define MM_PROC_PROT_STEP1_SHIFT 24 +#define PEXTP_MAC0_PROT_STEP1_SHIFT 13 +#define PEXTP_MAC1_PROT_STEP1_SHIFT 14 +#define PEXTP_MAC2_PROT_STEP1_SHIFT 15 +#define PEXTP_PHY0_PROT_STEP1_SHIFT 16 +#define PEXTP_PHY1_PROT_STEP1_SHIFT 17 +#define PEXTP_PHY2_PROT_STEP1_SHIFT 18 +#define SSRSYS_PROT_STEP1_SHIFT 10 +#define SSUSB_DP_PHY_P0_PROT_STEP1_SHIFT 6 +#define SSUSB_P0_PROT_STEP1_SHIFT 7 +#define SSUSB_P1_PROT_STEP1_SHIFT 8 +#define SSUSB_P23_PROT_STEP1_SHIFT 9 +#define SSUSB_PHY_P2_PROT_STEP1_SHIFT 10 +#define UFS0_PHY_PROT_STEP1_SHIFT 12 +#define UFS0_PROT_STEP1_SHIFT 11 + +struct mtcmos_bus_prot { + u32 *bp_en_set; + u32 *bp_en_clr; + u32 *bp_rdy; + u8 bit; +}; + +struct mtcmos_data { + const struct mtcmos_bus_prot *bp_table; + u32 *ctl_addr; + u32 caps; + u32 bp_num; + const struct mtcmos_cb *cb; +}; + +struct mtcmos_vote_data { + u32 *set_addr; + u32 *clr_addr; + u32 *done_addr; + u32 *ack_addr; + u8 vote_bit; + const struct mtcmos_cb *cb; +}; + +static const struct mtcmos_bus_prot ssusb_dp_phy_p0_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, SSUSB_DP_PHY_P0_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ssusb_p0_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, SSUSB_P0_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ssusb_p1_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, SSUSB_P1_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ssusb_p23_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, SSUSB_P23_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ssusb_phy_p2_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, SSUSB_PHY_P2_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ufs0_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, UFS0_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ufs0_phy_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, UFS0_PHY_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_mac0_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_MAC0_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_mac1_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_MAC1_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_mac2_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_MAC2_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_phy0_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_PHY0_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_phy1_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_PHY1_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot pextp_phy2_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, PEXTP_PHY2_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot audio_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, AUDIO_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot adsp_top_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, ADSP_TOP_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot adsp_infra_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, ADSP_INFRA_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot adsp_ao_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, ADSP_AO_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot mm_proc_bp[] = { + { SPM_PBUS_BUS_PROTECT_EN_SET, SPM_PBUS_BUS_PROTECT_EN_CLR, + SPM_PBUS_BUS_PROTECT_RDY_STA, MM_PROC_PROT_STEP1_SHIFT }, +}; + +static const struct mtcmos_bus_prot ssrsys_bp[] = { + { SPM_PBUS_BUS_MSB_PROTECT_EN_SET, SPM_PBUS_BUS_MSB_PROTECT_EN_CLR, + SPM_PBUS_BUS_MSB_PROTECT_RDY_STA, SSRSYS_PROT_STEP1_SHIFT }, +}; + +static struct mtcmos_data mds[MTCMOS_ID_NUM] = { + [MTCMOS_ID_SSUSB_DP_PHY_P0] = { + ssusb_dp_phy_p0_bp, &mtk_spm_mtcmos->ssusb_dp_phy_p0_pwr_con, + MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_SSUSB_P0] = { + ssusb_p0_bp, &mtk_spm_mtcmos->ssusb_p0_pwr_con, 0, 1 + }, + [MTCMOS_ID_SSUSB_P1] = { + ssusb_p1_bp, &mtk_spm_mtcmos->ssusb_p1_pwr_con, 0, 1 + }, + [MTCMOS_ID_SSUSB_P23] = { + ssusb_p23_bp, &mtk_spm_mtcmos->ssusb_p23_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_SSUSB_PHY_P2] = { + ssusb_phy_p2_bp, &mtk_spm_mtcmos->ssusb_phy_p2_pwr_con, 0, 1 + }, + [MTCMOS_ID_UFS0_SHUTDOWN] = { + ufs0_bp, &mtk_spm_mtcmos->ufs0_pwr_con, 0, 1 + }, + [MTCMOS_ID_UFS0_PHY] = { + ufs0_phy_bp, &mtk_spm_mtcmos->ufs0_phy_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_PEXTP_MAC0] = { + pextp_mac0_bp, &mtk_spm_mtcmos->pextp_mac0_pwr_con, 0, 1 + }, + [MTCMOS_ID_PEXTP_MAC1] = { + pextp_mac1_bp, &mtk_spm_mtcmos->pextp_mac1_pwr_con, 0, 1 + }, + [MTCMOS_ID_PEXTP_MAC2] = { + pextp_mac2_bp, &mtk_spm_mtcmos->pextp_mac2_pwr_con, 0, 1 + }, + [MTCMOS_ID_PEXTP_PHY0] = { + pextp_phy0_bp, &mtk_spm_mtcmos->pextp_phy0_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_PEXTP_PHY1] = { + pextp_phy1_bp, &mtk_spm_mtcmos->pextp_phy1_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_PEXTP_PHY2] = { + pextp_phy2_bp, &mtk_spm_mtcmos->pextp_phy2_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_AUDIO] = { + audio_bp, &mtk_spm_mtcmos->audio_pwr_con, 0, 1 + }, + [MTCMOS_ID_ADSP_TOP_SHUTDOWN] = { + adsp_top_bp, &mtk_spm_mtcmos->adsp_top_pwr_con, 0, 1 + }, + [MTCMOS_ID_ADSP_INFRA] = { + adsp_infra_bp, &mtk_spm_mtcmos->adsp_infra_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_ADSP_AO] = { + adsp_ao_bp, &mtk_spm_mtcmos->adsp_ao_pwr_con, MTK_SCPD_NO_SRAM, 1 + }, + [MTCMOS_ID_MM_PROC_SHUTDOWN] = { + mm_proc_bp, &mtk_spm_mtcmos->mm_proc_pwr_con, 0, 1 + }, + [MTCMOS_ID_SSRSYS] = { + ssrsys_bp, &mtk_spm_mtcmos->ssrsys_pwr_con, 0, 1 + }, +}; + +static struct mtcmos_vote_data vote_mds[MTCMOS_ID_NUM] = { + [MTCMOS_ID_DISP_VCORE] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, DISP_VCORE_VOTE_BIT + }, + [MTCMOS_ID_DIS0_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, DISP0_VOTE_BIT + }, + [MTCMOS_ID_DIS1_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, DISP1_VOTE_BIT + }, + [MTCMOS_ID_OVL0_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, OVL0_VOTE_BIT + }, + [MTCMOS_ID_OVL1_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, OVL1_VOTE_BIT + }, + [MTCMOS_ID_DISP_EDPTX_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, DISP_EDPTX_VOTE_BIT + }, + [MTCMOS_ID_DISP_DPTX_SHUTDOWN] = { + MMVOTE_MTCMOS_0_SET, MMVOTE_MTCMOS_0_CLR, MMVOTE_MTCMOS_0_DONE, + MMVOTE_MTCMOS_0_PM_ACK, DISP_DPTX_VOTE_BIT + }, + [MTCMOS_ID_MM_INFRA0] = { + MMINFRA_MTCMOS_1_SET, MMINFRA_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, MMINFRA0_VOTE_BIT + }, + [MTCMOS_ID_MM_INFRA1] = { + MMINFRA_MTCMOS_1_SET, MMINFRA_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, MMINFRA1_VOTE_BIT + }, + [MTCMOS_ID_MM_INFRA_AO] = { + MMINFRA_MTCMOS_1_SET, MMINFRA_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, MMINFRA_AO_VOTE_BIT + }, + [MTCMOS_ID_DSI_PHY0] = { + MMVOTE_MTCMOS_1_SET, MMVOTE_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, DSI_PHY0_VOTE_BIT + }, + [MTCMOS_ID_DSI_PHY1] = { + MMVOTE_MTCMOS_1_SET, MMVOTE_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, DSI_PHY1_VOTE_BIT + }, + [MTCMOS_ID_DSI_PHY2] = { + MMVOTE_MTCMOS_1_SET, MMVOTE_MTCMOS_1_CLR, MMVOTE_MTCMOS_1_DONE, + MMVOTE_MTCMOS_1_PM_ACK, DSI_PHY2_VOTE_BIT + }, +}; + +int mtcmos_cb_register(enum mtcmos_id id, const struct mtcmos_cb *cb) +{ + if (id >= MTCMOS_ID_NUM) { + printk(BIOS_ERR, "id(%d) is invalid\n", id); + return -1; + } + + if (id <= MTCMOS_ID_SSRSYS) + mds[id].cb = cb; + else + vote_mds[id].cb = cb; + + return 0; +} + +static int mtcmos_wait_for_state(u32 *reg, u32 mask, bool onoff) +{ + u32 expect = onoff ? mask : 0; + + if (!retry(ACK_DELAY_TIMES, (read32(reg) & mask) == expect, udelay(ACK_DELAY_US))) { + printk(BIOS_ERR, "%s(%p, %#x, %d) reg_val=%#x timeout\n", + __func__, reg, mask, onoff, read32(reg)); + return -1; + } + + return 0; +} + +static int mtcmos_bus_prot_ctrl(const struct mtcmos_bus_prot *bp_table, bool set) +{ + u32 *ctrl_addr; + u32 mask = BIT(bp_table->bit); + + if (set) + ctrl_addr = bp_table->bp_en_set; + else + ctrl_addr = bp_table->bp_en_clr; + + write32(ctrl_addr, mask); + + if (set) + return mtcmos_wait_for_state(bp_table->bp_rdy, mask, set); + + return 0; +} + +static int mtcmos_setclr_bus_prot(const struct mtcmos_bus_prot *bp_table, u32 bp_num, bool set) +{ + int step_idx; + int ret; + int i; + + for (i = 0; i < bp_num; i++) { + step_idx = set ? i : bp_num - 1 - i; + ret = mtcmos_bus_prot_ctrl(&bp_table[step_idx], set); + if (ret) { + printk(BIOS_ERR, "mtcmos_bus_prot_ctrl set fail: %d\n", ret); + mtcmos_bus_prot_ctrl(&bp_table[step_idx], !set); + return ret; + } + } + + return 0; +} + +static int mtcmos_sram_on(enum mtcmos_id id, const struct mtcmos_data *md) +{ + u32 *ctl_addr = md->ctl_addr; + int ret = 0; + + if (MTK_SCPD_CAPS(md, MTK_SCPD_SRAM_SLP)) { + setbits32(ctl_addr, SRAM_SLP); + ret = mtcmos_wait_for_state(ctl_addr, SRAM_SLP_ACK, true); + } else { + clrbits32(ctl_addr, SRAM_PDN); + ret = mtcmos_wait_for_state(ctl_addr, SRAM_PDN_ACK, false); + } + if (ret) + return ret; + + if (MTK_SCPD_CAPS(md, MTK_SCPD_SRAM_ISO)) { + setbits32(ctl_addr, SRAM_ISOINT_B); + udelay(1); + clrbits32(ctl_addr, SRAM_CKISO); + } + + return 0; +} + +static int mtcmos_sram_off(enum mtcmos_id id, const struct mtcmos_data *md) +{ + u32 *ctl_addr = md->ctl_addr; + + if (MTK_SCPD_CAPS(md, MTK_SCPD_SRAM_ISO)) { + setbits32(ctl_addr, SRAM_CKISO); + clrbits32(ctl_addr, SRAM_ISOINT_B); + udelay(1); + } + + if (MTK_SCPD_CAPS(md, MTK_SCPD_SRAM_SLP)) { + clrbits32(ctl_addr, SRAM_SLP); + return mtcmos_wait_for_state(ctl_addr, SRAM_SLP_ACK, false); + } else { + setbits32(ctl_addr, SRAM_PDN); + return mtcmos_wait_for_state(ctl_addr, SRAM_PDN_ACK, true); + } +} + +static int mtcmos_onoff(enum mtcmos_id id, enum mtcmos_state state) +{ + const struct mtcmos_data *md = &mds[id]; + u32 *ctl_addr = md->ctl_addr; + int ret = 0; + + if (state == MTCMOS_POWER_DOWN) { + if (md->cb && md->cb->pre_off) { + ret = md->cb->pre_off(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call pre_off fail(%d)\n", id, ret); + return ret; + } + } + + ret = mtcmos_setclr_bus_prot(md->bp_table, md->bp_num, SET_BUS_PROTECT); + if (ret) + return ret; + + if (!MTK_SCPD_CAPS(md, MTK_SCPD_NO_SRAM)) { + ret = mtcmos_sram_off(id, md); + if (ret) + return ret; + } + + setbits32(ctl_addr, PWR_ISO); + setbits32(ctl_addr, PWR_CLK_DIS); + clrbits32(ctl_addr, PWR_RST_B); + clrbits32(ctl_addr, PWR_ON); + ret = mtcmos_wait_for_state(ctl_addr, PWR_ACK, state); + if (ret) + return ret; + + clrbits32(ctl_addr, PWR_ON_2ND); + ret = mtcmos_wait_for_state(ctl_addr, PWR_ACK_2ND, state); + if (ret) + return ret; + + if (md->cb && md->cb->post_off) { + ret = md->cb->post_off(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call post_off fail(%d)\n", id, ret); + return ret; + } + } + } else { + if (md->cb && md->cb->pre_on) { + ret = md->cb->pre_on(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call pre_on fail(%d)\n", id, ret); + return ret; + } + } + + setbits32(ctl_addr, PWR_ON); + ret = mtcmos_wait_for_state(ctl_addr, PWR_ACK, state); + if (ret) + return ret; + udelay(50); + + setbits32(ctl_addr, PWR_ON_2ND); + ret = mtcmos_wait_for_state(ctl_addr, PWR_ACK_2ND, state); + if (ret) + return ret; + + clrbits32(ctl_addr, PWR_CLK_DIS); + clrbits32(ctl_addr, PWR_ISO); + + if (MTK_SCPD_CAPS(md, MTK_SCPD_RTFF_DELAY)) + udelay(10); + + setbits32(ctl_addr, PWR_RST_B); + if (!MTK_SCPD_CAPS(md, MTK_SCPD_NO_SRAM)) { + ret = mtcmos_sram_on(id, md); + if (ret) + return ret; + } + + ret = mtcmos_setclr_bus_prot(md->bp_table, md->bp_num, RELEASE_BUS_PROTECT); + if (ret) + return ret; + + if (md->cb && md->cb->post_on) { + ret = md->cb->post_on(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call post_on fail(%d)\n", id, ret); + return ret; + } + } + } + + return 0; +} + +static int mtcmos_vote_onoff(enum mtcmos_id id, enum mtcmos_state state) +{ + const struct mtcmos_vote_data *md = &vote_mds[id]; + u32 vote_bit = BIT(md->vote_bit); + int ret = 0; + + if (state == MTCMOS_POWER_DOWN) { + if (md->cb && md->cb->pre_off) { + ret = md->cb->pre_off(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call pre_off fail(%d)\n", id, ret); + return ret; + } + } + + write32(md->clr_addr, vote_bit); + if (!wait_us(WAIT_VOTE_TIMEOUT, ((read32(md->done_addr) & vote_bit) != 0 && + (read32(md->ack_addr) & vote_bit) == vote_bit))) { + printk(BIOS_ERR, "mtcmos_vote disable %d timeout\n", id); + return -1; + } + + if (md->cb && md->cb->post_off) { + ret = md->cb->post_off(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call post_off fail(%d)\n", id, ret); + return ret; + } + } + } else { + if (md->cb && md->cb->pre_on) { + ret = md->cb->pre_on(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call pre_on fail(%d)\n", id, ret); + return ret; + } + } + + write32(md->set_addr, vote_bit); + if (!wait_us(WAIT_VOTE_TIMEOUT, ((read32(md->done_addr) & vote_bit) != 0 && + (read32(md->ack_addr) & vote_bit) == vote_bit))) { + printk(BIOS_ERR, "mtcmos_vote enable %d timeout\n", id); + return ret; + } + + if (md->cb && md->cb->post_on) { + ret = md->cb->post_on(); + if (ret) { + printk(BIOS_ERR, "mtcmos(%d) call post_on fail(%d)\n", id, ret); + return ret; + } + } + } + + return 0; +} + +static void mtcmos_spm_clr_rtff_flag(void) +{ + clrbits32(&mtk_spm_mtcmos->conn_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssusb_dp_phy_p0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssusb_p0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssusb_p1_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssusb_p23_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssusb_phy_p2_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ufs0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ufs0_phy_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_mac0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_mac1_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_mac2_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_phy0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_phy1_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->pextp_phy2_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->audio_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->adsp_infra_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->adsp_ao_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->mm_proc_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->ssrsys_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->spu_ise_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->spu_hwrot_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->hsgmii0_pwr_con, PWR_RTFF_SAVE_FLAG); + clrbits32(&mtk_spm_mtcmos->hsgmii1_pwr_con, PWR_RTFF_SAVE_FLAG); +} + +static int mtcmos_disp_vcore_pre_on(void) +{ + write32(MM_BUCK_ISO_CON_CLR, BIT(0)); + write32(MM_BUCK_ISO_CON_CLR, BIT(1)); + write32(MM_BUCK_ISO_CON_CLR, BIT(2)); + + write32(DISP_AO_PWR_CON, 0x1); + + return 0; +} + +static int mtcmos_disp_vcore_post_on(void) +{ + write32(MMPC_BUS_PROTECT_EN_1_CLR, BIT(6) | BIT(7)); + + write32p(DISP_VDISP_AO_CONFIG_CG, 0xFFFFFFFF); + + setbits32p(DISP_DPC_DISP0_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_DISP1_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_OVL0_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_OVL1_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_MML0_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_MML1_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_EDP_MTCMOS_CFG, BIT(4)); + setbits32p(DISP_DPC_EPTX_MTCMOS_CFG, BIT(4)); + + return 0; +} + +static struct mtcmos_cb disp_vcore_cb = { + .pre_on = mtcmos_disp_vcore_pre_on, + .post_on = mtcmos_disp_vcore_post_on, +}; + +void mtcmos_protect_display_bus(void) +{ + /* empty implementation for user common flow */ +} + +void mtcmos_display_power_on(void) +{ + mtcmos_ctrl(MTCMOS_ID_DIS0_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DIS1_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_OVL0_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_OVL1_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DISP_EDPTX_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DISP_DPTX_SHUTDOWN, MTCMOS_POWER_ON); +} + +void mtcmos_ctrl(enum mtcmos_id id, enum mtcmos_state state) +{ + int ret = 0; + + if (id >= MTCMOS_ID_NUM) { + printk(BIOS_ERR, "id(%d) is invalid\n", id); + return; + } + + if (id <= MTCMOS_ID_SSRSYS) + ret = mtcmos_onoff(id, state); + else + ret = mtcmos_vote_onoff(id, state); + + if (ret) + printk(BIOS_ERR, "%s(%u, %u) fail, ret=%d\n", __func__, id, state, ret); +} + +void mtcmos_init(void) +{ + write32(POWERON_CONFIG_EN, (SPM_PROJECT_CODE << 16) | BIT(0)); + + mtcmos_spm_clr_rtff_flag(); + + mtcmos_ctrl(MTCMOS_ID_SSUSB_P0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_SSUSB_DP_PHY_P0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_SSUSB_P1, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_SSUSB_P23, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_SSUSB_PHY_P2, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_UFS0_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_UFS0_PHY, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_MAC0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_MAC1, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_MAC2, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_PHY0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_PHY1, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_PEXTP_PHY2, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_ADSP_TOP_SHUTDOWN, MTCMOS_POWER_DOWN); + mtcmos_ctrl(MTCMOS_ID_AUDIO, MTCMOS_POWER_DOWN); + mtcmos_ctrl(MTCMOS_ID_ADSP_INFRA, MTCMOS_POWER_DOWN); + mtcmos_ctrl(MTCMOS_ID_ADSP_AO, MTCMOS_POWER_DOWN); + mtcmos_ctrl(MTCMOS_ID_ADSP_AO, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_ADSP_INFRA, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_AUDIO, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_ADSP_TOP_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_MM_PROC_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_SSRSYS, MTCMOS_POWER_ON); +} + +void mtcmos_post_init(void) +{ + if (mtcmos_cb_register(MTCMOS_ID_DISP_VCORE, &disp_vcore_cb)) + printk(BIOS_ERR, "register disp_vcore failed\n"); + + mtcmos_ctrl(MTCMOS_ID_MM_INFRA_AO, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_MM_INFRA0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_MM_INFRA1, MTCMOS_POWER_ON); + + mtcmos_ctrl(MTCMOS_ID_DISP_VCORE, MTCMOS_POWER_ON); + write32(&mtk_disp->clk_cfg[0].clr, 0x00000007); + + mtcmos_ctrl(MTCMOS_ID_DIS0_SHUTDOWN, MTCMOS_POWER_ON); + write32(&mtk_mmsys->clk_cfg[0].clr, 0xFFFFFFFF); + write32(&mtk_mmsys->clk_cfg[1].clr, 0x07FFFFFF); + + mtcmos_ctrl(MTCMOS_ID_DIS1_SHUTDOWN, MTCMOS_POWER_ON); + write32(&mtk_mmsys1->clk_cfg[0].clr, 0xFFFFFFFF); + write32(&mtk_mmsys1->clk_cfg[1].clr, 0x1FF3FFFF); + + mtcmos_ctrl(MTCMOS_ID_OVL0_SHUTDOWN, MTCMOS_POWER_ON); + write32(&mtk_ovlsys->clk_cfg[0].clr, 0xFFFFFFFF); + write32(&mtk_ovlsys->clk_cfg[1].clr, 0x7FFFFFFF); + + mtcmos_ctrl(MTCMOS_ID_OVL1_SHUTDOWN, MTCMOS_POWER_ON); + write32(&mtk_ovlsys1->clk_cfg[0].clr, 0xFFFFFFFF); + write32(&mtk_ovlsys1->clk_cfg[1].clr, 0x7FFFFFFF); + + mtcmos_ctrl(MTCMOS_ID_DISP_EDPTX_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DISP_DPTX_SHUTDOWN, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DSI_PHY0, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DSI_PHY1, MTCMOS_POWER_ON); + mtcmos_ctrl(MTCMOS_ID_DSI_PHY2, MTCMOS_POWER_ON); + + /* vmm buck isolation off */ + write32(MM_BUCK_ISO_CON_CLR, BIT(4)); + write32(MM_BUCK_ISO_CON_CLR, BIT(5)); + write32(MM_BUCK_ISO_CON_CLR, BIT(6)); +}