diff --git a/src/soc/mediatek/common/include/soc/mtcmos.h b/src/soc/mediatek/common/include/soc/mtcmos.h index 15b4367fc4..a38d3f7ac2 100644 --- a/src/soc/mediatek/common/include/soc/mtcmos.h +++ b/src/soc/mediatek/common/include/soc/mtcmos.h @@ -5,6 +5,8 @@ struct bus_protect { void *clr_addr; + void *set_addr; + void *rdy_addr; u32 mask; }; @@ -28,9 +30,11 @@ struct power_domain_data { void mtcmos_set_scpd_ext_buck_iso(const struct power_domain_data *pd); void mtcmos_power_on(const struct power_domain_data *pd); +void mtcmos_power_off(const struct power_domain_data *pd); void mtcmos_adsp_power_on(void); void mtcmos_audio_power_on(void); void mtcmos_display_power_on(void); +void mtcmos_ufs_power_off(void); void mtcmos_protect_adsp_bus(void); void mtcmos_protect_audio_bus(void); diff --git a/src/soc/mediatek/common/mtcmos.c b/src/soc/mediatek/common/mtcmos.c index f69e84fab7..0172e24981 100644 --- a/src/soc/mediatek/common/mtcmos.c +++ b/src/soc/mediatek/common/mtcmos.c @@ -1,8 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include +#include #include #include #include +#include + +#define MTCMOS_TIMEOUT_US 500 +#define MTCMOS_ETIMEDOUT 25 enum { SRAM_ISOINT_B = 1U << 6, @@ -19,6 +25,20 @@ __weak void mtcmos_set_scpd_ext_buck_iso(const struct power_domain_data *pd) /* do nothing */ } +static int mtcmos_wait_for_state(u32 *reg, u32 mask, bool is_set) +{ + u32 expect = is_set ? mask : 0; + + if (!wait_us(MTCMOS_TIMEOUT_US, ((read32(reg) & mask) == expect))) { + printk(BIOS_ERR, + "%s (0x%p, %#x, %d) timeout after %d us, reg_val=%#x\n", + __func__, reg, mask, is_set, MTCMOS_TIMEOUT_US, read32(reg)); + return -MTCMOS_ETIMEDOUT; + } + + return 0; +} + static void release_bus_protection(const struct power_domain_data *pd) { int i; @@ -27,6 +47,19 @@ static void release_bus_protection(const struct power_domain_data *pd) write32(pd->bp_table[i].clr_addr, pd->bp_table[i].mask); } +static void set_bus_protection(const struct power_domain_data *pd) +{ + int i; + + for (i = pd->bp_steps - 1; i >= 0; i--) { + const struct bus_protect *bp = &pd->bp_table[i]; + assert(bp->set_addr && bp->rdy_addr); + write32(bp->set_addr, bp->mask); + mtcmos_wait_for_state(bp->rdy_addr, bp->mask, true); + } +} + + void mtcmos_power_on(const struct power_domain_data *pd) { u32 *pwr_status; @@ -70,6 +103,44 @@ void mtcmos_power_on(const struct power_domain_data *pd) release_bus_protection(pd); } +void mtcmos_power_off(const struct power_domain_data *pd) +{ + u32 *pwr_status; + u32 *pwr_status_2nd; + + write32(&mtk_spm->poweron_config_set, + (SPM_PROJECT_CODE << 16) | (1U << 0)); + + set_bus_protection(pd); + + if (pd->sram_pdn_mask) { + if (pd->caps & SCPD_SRAM_ISO) { + setbits32(pd->pwr_con, SRAM_CKISO); + clrbits32(pd->pwr_con, SRAM_ISOINT_B); + udelay(1); + } + setbits32(pd->pwr_con, pd->sram_pdn_mask); + mtcmos_wait_for_state(pd->pwr_con, pd->sram_ack_mask, true); + } + + setbits32(pd->pwr_con, PWR_ISO); + setbits32(pd->pwr_con, PWR_CLK_DIS); + clrbits32(pd->pwr_con, PWR_RST_B); + + if (pd->pwr_status && pd->pwr_status_2nd) { + pwr_status = pd->pwr_status; + pwr_status_2nd = pd->pwr_status_2nd; + } else { + pwr_status = &mtk_spm->pwr_status; + pwr_status_2nd = &mtk_spm->pwr_status_2nd; + } + + clrbits32(pd->pwr_con, PWR_ON); + mtcmos_wait_for_state(pwr_status, pd->pwr_sta_mask, false); + clrbits32(pd->pwr_con, PWR_ON_2ND); + mtcmos_wait_for_state(pwr_status_2nd, pd->pwr_sta_mask, false); +} + void mtcmos_display_power_on(void) { int i; diff --git a/src/soc/mediatek/mt8189/include/soc/spm_mtcmos.h b/src/soc/mediatek/mt8189/include/soc/spm_mtcmos.h index e68b531bb9..9c9b6d8afc 100644 --- a/src/soc/mediatek/mt8189/include/soc/spm_mtcmos.h +++ b/src/soc/mediatek/mt8189/include/soc/spm_mtcmos.h @@ -24,6 +24,7 @@ struct mtk_vlpcfg_regs { u32 bus_vlp_topaxi_protecten; u32 bus_vlp_topaxi_protecten_set; u32 bus_vlp_topaxi_protecten_clr; + u32 bus_vlp_topaxi_protecten_sta0; u32 bus_vlp_topaxi_protecten_sta1; }; check_member(mtk_vlpcfg_regs, vlp_test_ck_ctrl, 0x0004); diff --git a/src/soc/mediatek/mt8189/mtcmos.c b/src/soc/mediatek/mt8189/mtcmos.c index 8b89e58ad2..b212b72a59 100644 --- a/src/soc/mediatek/mt8189/mtcmos.c +++ b/src/soc/mediatek/mt8189/mtcmos.c @@ -11,24 +11,55 @@ #include static const struct bus_protect bp_ufs[] = { - {&mtk_vlpcfg->bus_vlp_topaxi_protecten_clr, BIT(6)}, - {&mtk_infracfg_ao->perisys_protect.clr, BIT(4)}, - {&mtk_vlpcfg->bus_vlp_topaxi_protecten_clr, BIT(5)}, + { + .clr_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_clr, + .set_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_set, + .rdy_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_sta1, + .mask = BIT(6), + }, + { + .clr_addr = &mtk_infracfg_ao->perisys_protect.clr, + .set_addr = &mtk_infracfg_ao->perisys_protect.set, + .rdy_addr = &mtk_infracfg_ao->perisys_protect.ready, + .mask = BIT(4), + }, + { + .clr_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_clr, + .set_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_set, + .rdy_addr = &mtk_vlpcfg->bus_vlp_topaxi_protecten_sta1, + .mask = BIT(5), + }, }; static const struct bus_protect bp_mminfra[] = { - {&mtk_infracfg_ao->emisys_protect.clr, BIT(20) | BIT(21)}, - {&mtk_infracfg_ao->infrasys_protect[0].clr, BIT(16)}, - {&mtk_infracfg_ao->mmsys_protect[1].clr, - BIT(0) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | - BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15)}, - {&mtk_infracfg_ao->infrasys_protect[1].clr, BIT(11)}, - {&mtk_infracfg_ao->mmsys_protect[1].clr, - BIT(1) | BIT(2) | BIT(3)}, + { + .clr_addr = &mtk_infracfg_ao->emisys_protect.clr, + .mask = BIT(20) | BIT(21), + }, + { + .clr_addr = &mtk_infracfg_ao->infrasys_protect[0].clr, + .mask = BIT(16), + }, + { + .clr_addr = &mtk_infracfg_ao->mmsys_protect[1].clr, + .mask = BIT(0) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | + BIT(11) | BIT(12) | BIT(13) | BIT(14) | BIT(15), + }, + { + .clr_addr = &mtk_infracfg_ao->infrasys_protect[1].clr, + .mask = BIT(11), + }, + { + .clr_addr = &mtk_infracfg_ao->mmsys_protect[1].clr, + .mask = BIT(1) | BIT(2) | BIT(3), + }, }; static const struct bus_protect bp_ssusb[] = { - {&mtk_infracfg_ao->perisys_protect.clr, BIT(7)}, + { + .clr_addr = &mtk_infracfg_ao->perisys_protect.clr, + .mask = BIT(7), + }, }; static const struct power_domain_data pd_plat[] = { @@ -81,6 +112,14 @@ void mtcmos_init(void) mtcmos_power_on(&pd_plat[i]); } +void mtcmos_ufs_power_off(void) +{ + /* ufs0_phy */ + mtcmos_power_off(&pd_plat[1]); + /* ufs0 */ + mtcmos_power_off(&pd_plat[0]); +} + void mtcmos_protect_audio_bus(void) { write32(&mtk_infracfg_ao->perisys_protect.clr, BIT(6));