soc/mediatek/mt8189: Implement UFS power-off API for non-UFS SKUs

On MT8189, UFS power is enabled by default. For SKUs that do not use UFS
as storage, keeping UFS power enabled can cause suspend failures and
unnecessary power consumption. This change implements a UFS power-off
API to ensure UFS can be properly powered down on non-UFS SKUs.

BUG=b:430421429
BRANCH=skywalker
TEST=Suspend flow works correctly, and SoC power consumption is 34 mW,
     meeting expectations on Anakin.

Signed-off-by: Vince Liu <vince-wl.liu@mediatek.corp-partner.google.com>
Signed-off-by: Irving-ch Lin <irving-ch.lin@mediatek.corp-partner.google.com>
Change-Id: Ib5ccbeaf951c3a095905e472bc096eeb2dee47a8
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88976
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
Vince Liu 2025-08-27 14:34:44 +08:00 committed by Yu-Ping Wu
commit 22fe08c04b
4 changed files with 127 additions and 12 deletions

View file

@ -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);

View file

@ -1,8 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <console/console.h>
#include <delay.h>
#include <device/mmio.h>
#include <soc/spm.h>
#include <timer.h>
#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;

View file

@ -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);

View file

@ -11,24 +11,55 @@
#include <soc/spm_mtcmos.h>
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));