diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c')
-rw-r--r-- | plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c new file mode 100644 index 0000000..2d67fdf --- /dev/null +++ b/plat/mediatek/mt8192/drivers/spm/mt_spm_cond.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2020, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdbool.h> + +#include <common/debug.h> +#include <lib/mmio.h> + +#include <mt_spm_cond.h> +#include <mt_spm_conservation.h> +#include <mt_spm_constraint.h> +#include <plat_mtk_lpm.h> +#include <plat_pm.h> +#include <platform_def.h> + +#define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs) +#define MT_LP_TZ_MM_REG(ofs) (MMSYS_BASE + ofs) +#define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs) +#define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs) +#define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs) + +#define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C) +#define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170) +#define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0094) +#define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0090) +#define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC) +#define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8) +#define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00D8) +#define INFRA_SW_CG5 MT_LP_TZ_INFRA_REG(0x00E8) +#define MMSYS_CG_CON0 MT_LP_TZ_MM_REG(0x100) +#define MMSYS_CG_CON1 MT_LP_TZ_MM_REG(0x110) +#define MMSYS_CG_CON2 MT_LP_TZ_MM_REG(0x1A0) + +/*********************************************************** + * Check clkmux registers + ***********************************************************/ +#define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0x20 + id * 0x10) +#define PDN_CHECK BIT(7) +#define CLK_CHECK BIT(31) + +enum { + CLKMUX_DISP = 0, + CLKMUX_MDP = 1, + CLKMUX_IMG1 = 2, + CLKMUX_IMG2 = 3, + NF_CLKMUX, +}; + +static bool is_clkmux_pdn(unsigned int clkmux_id) +{ + unsigned int reg, val, idx; + + if ((clkmux_id & CLK_CHECK) != 0U) { + clkmux_id = (clkmux_id & ~CLK_CHECK); + reg = clkmux_id / 4U; + val = mmio_read_32(CLK_CFG(reg)); + idx = clkmux_id % 4U; + val = (val >> (idx * 8U)) & PDN_CHECK; + return (val != 0U); + } + + return false; +} + +static struct mt_spm_cond_tables spm_cond_t; + +struct idle_cond_info { + unsigned int subsys_mask; + uintptr_t addr; + bool bBitflip; + unsigned int clkmux_id; +}; + +#define IDLE_CG(mask, addr, bitflip, clkmux) \ + {mask, (uintptr_t)addr, bitflip, clkmux} + +static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = { + IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U), + IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U), + IDLE_CG(0x00100000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)), + IDLE_CG(0x00100000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)), + IDLE_CG(0x00100000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)), +}; + +/*********************************************************** + * Check pll idle condition + ***********************************************************/ +#define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x268) +#define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x360) +#define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x308) +#define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x350) +#define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x380) + +unsigned int mt_spm_cond_check(int state_id, + const struct mt_spm_cond_tables *src, + const struct mt_spm_cond_tables *dest, + struct mt_spm_cond_tables *res) +{ + unsigned int blocked = 0U, i; + bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id); + + if ((src == NULL) || (dest == NULL)) { + return SPM_COND_CHECK_FAIL; + } + + for (i = 0U; i < PLAT_SPM_COND_MAX; i++) { + if (res != NULL) { + res->table_cg[i] = + (src->table_cg[i] & dest->table_cg[i]); + + if (is_system_suspend && (res->table_cg[i] != 0U)) { + INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n", + dest->name, i, idle_cg_info[i].addr, + res->table_cg[i]); + } + + if (res->table_cg[i] != 0U) { + blocked |= (1U << i); + } + } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) { + blocked |= (1U << i); + break; + } + } + + if (res != NULL) { + res->table_pll = (src->table_pll & dest->table_pll); + + if (res->table_pll != 0U) { + blocked |= + (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) | + SPM_COND_CHECK_BLOCKED_PLL; + } + } else if ((src->table_pll & dest->table_pll) != 0U) { + blocked |= SPM_COND_CHECK_BLOCKED_PLL; + } + + if (is_system_suspend && (blocked != 0U)) { + INFO("suspend: %s total blocked = 0x%08x\n", + dest->name, blocked); + } + + return blocked; +} + +#define IS_MT_SPM_PWR_OFF(mask) \ + (((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \ + ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U)) + +int mt_spm_cond_update(struct mt_resource_constraint **con, + int stateid, void *priv) +{ + int res; + uint32_t i; + struct mt_resource_constraint *const *rc; + + /* read all cg state */ + for (i = 0U; i < PLAT_SPM_COND_MAX; i++) { + spm_cond_t.table_cg[i] = 0U; + + /* check mtcmos, if off set idle_value and clk to 0 disable */ + if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) { + continue; + } + + /* check clkmux */ + if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) { + continue; + } + + spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ? + ~mmio_read_32(idle_cg_info[i].addr) : + mmio_read_32(idle_cg_info[i].addr); + } + + spm_cond_t.table_pll = 0U; + if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) { + spm_cond_t.table_pll |= PLL_BIT_MFGPLL; + } + + if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) { + spm_cond_t.table_pll |= PLL_BIT_MMPLL; + } + + if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) { + spm_cond_t.table_pll |= PLL_BIT_UNIVPLL; + } + + if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) { + spm_cond_t.table_pll |= PLL_BIT_MSDCPLL; + } + + if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) { + spm_cond_t.table_pll |= PLL_BIT_TVDPLL; + } + + spm_cond_t.priv = priv; + for (rc = con; *rc != NULL; rc++) { + if (((*rc)->update) == NULL) { + continue; + } + + res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION, + (void const *)&spm_cond_t); + if (res != MT_RM_STATUS_OK) { + break; + } + } + + return 0; +} |