1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2022-2023, MediaTek Inc. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stdbool.h> 8*91f16700Schasinglulu #include <common/debug.h> 9*91f16700Schasinglulu #include <lib/mmio.h> 10*91f16700Schasinglulu #include <mt_spm_cond.h> 11*91f16700Schasinglulu #include <mt_spm_conservation.h> 12*91f16700Schasinglulu #include <mt_spm_constraint.h> 13*91f16700Schasinglulu #include <plat_mtk_lpm.h> 14*91f16700Schasinglulu #include <plat_pm.h> 15*91f16700Schasinglulu #include <platform_def.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu #define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs) 18*91f16700Schasinglulu #define MT_LP_TZ_MM_REG(ofs) (MMSYS_BASE + ofs) 19*91f16700Schasinglulu #define MT_LP_TZ_MDP_REG(ofs) (MDPSYS_BASE + ofs) 20*91f16700Schasinglulu #define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs) 21*91f16700Schasinglulu #define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEN_BASE + ofs) 22*91f16700Schasinglulu #define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs) 23*91f16700Schasinglulu 24*91f16700Schasinglulu #define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C) 25*91f16700Schasinglulu #define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170) 26*91f16700Schasinglulu #define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0090) 27*91f16700Schasinglulu #define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0094) 28*91f16700Schasinglulu #define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC) 29*91f16700Schasinglulu #define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8) 30*91f16700Schasinglulu #define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00E8) 31*91f16700Schasinglulu #define INFRA_SW_CG5 MT_LP_TZ_INFRA_REG(0x00D8) 32*91f16700Schasinglulu #define MMSYS_CG_CON0 MT_LP_TZ_MM_REG(0x100) 33*91f16700Schasinglulu #define MMSYS_CG_CON1 MT_LP_TZ_MM_REG(0x110) 34*91f16700Schasinglulu #define MMSYS_CG_CON2 MT_LP_TZ_MM_REG(0x1A0) 35*91f16700Schasinglulu #define MMSYS_CG_CON3 MT_LP_TZ_MDP_REG(0x100) 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* Check clkmux registers */ 38*91f16700Schasinglulu #define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0xe0 + id * 0x10) 39*91f16700Schasinglulu #define CLK_CHECK BIT(31) 40*91f16700Schasinglulu 41*91f16700Schasinglulu enum { 42*91f16700Schasinglulu CLKMUX_DISP = 0, 43*91f16700Schasinglulu CLKMUX_MDP = 1, 44*91f16700Schasinglulu CLKMUX_IMG1 = 2, 45*91f16700Schasinglulu CLKMUX_IMG2 = 3, 46*91f16700Schasinglulu NF_CLKMUX = 4, 47*91f16700Schasinglulu }; 48*91f16700Schasinglulu 49*91f16700Schasinglulu static bool is_clkmux_pdn(unsigned int clkmux_id) 50*91f16700Schasinglulu { 51*91f16700Schasinglulu unsigned int reg, val, idx; 52*91f16700Schasinglulu bool ret = false; 53*91f16700Schasinglulu 54*91f16700Schasinglulu if (clkmux_id & CLK_CHECK) { 55*91f16700Schasinglulu clkmux_id = (clkmux_id & ~CLK_CHECK); 56*91f16700Schasinglulu reg = clkmux_id / 4U; 57*91f16700Schasinglulu val = mmio_read_32(CLK_CFG(reg)); 58*91f16700Schasinglulu idx = clkmux_id % 4U; 59*91f16700Schasinglulu ret = (((val >> (idx * 8U)) & 0x80) != 0U); 60*91f16700Schasinglulu } 61*91f16700Schasinglulu 62*91f16700Schasinglulu return ret; 63*91f16700Schasinglulu } 64*91f16700Schasinglulu 65*91f16700Schasinglulu static struct mt_spm_cond_tables spm_cond_t; 66*91f16700Schasinglulu 67*91f16700Schasinglulu struct idle_cond_info { 68*91f16700Schasinglulu unsigned int subsys_mask; 69*91f16700Schasinglulu uintptr_t addr; 70*91f16700Schasinglulu bool bit_flip; 71*91f16700Schasinglulu unsigned int clkmux_id; 72*91f16700Schasinglulu }; 73*91f16700Schasinglulu 74*91f16700Schasinglulu #define IDLE_CG(mask, addr, bitflip, clkmux) \ 75*91f16700Schasinglulu {mask, (uintptr_t)addr, bitflip, clkmux} 76*91f16700Schasinglulu 77*91f16700Schasinglulu static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = { 78*91f16700Schasinglulu IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0U), 79*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG0, true, 0U), 80*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG1, true, 0U), 81*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG2, true, 0U), 82*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG3, true, 0U), 83*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG4, true, 0U), 84*91f16700Schasinglulu IDLE_CG(0x00000200, INFRA_SW_CG5, true, 0U), 85*91f16700Schasinglulu IDLE_CG(0x00200000, MMSYS_CG_CON0, true, (CLK_CHECK | CLKMUX_DISP)), 86*91f16700Schasinglulu IDLE_CG(0x00200000, MMSYS_CG_CON1, true, (CLK_CHECK | CLKMUX_DISP)), 87*91f16700Schasinglulu IDLE_CG(0x00200000, MMSYS_CG_CON2, true, (CLK_CHECK | CLKMUX_DISP)), 88*91f16700Schasinglulu IDLE_CG(0x00200000, MMSYS_CG_CON3, true, (CLK_CHECK | CLKMUX_MDP)), 89*91f16700Schasinglulu }; 90*91f16700Schasinglulu 91*91f16700Schasinglulu /* Check pll idle condition */ 92*91f16700Schasinglulu #define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x314) 93*91f16700Schasinglulu #define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x254) 94*91f16700Schasinglulu #define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x324) 95*91f16700Schasinglulu #define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x38c) 96*91f16700Schasinglulu #define PLL_TVDPLL MT_LP_TZ_APMIXEDSYS(0x264) 97*91f16700Schasinglulu 98*91f16700Schasinglulu unsigned int mt_spm_cond_check(int state_id, 99*91f16700Schasinglulu const struct mt_spm_cond_tables *src, 100*91f16700Schasinglulu const struct mt_spm_cond_tables *dest, 101*91f16700Schasinglulu struct mt_spm_cond_tables *res) 102*91f16700Schasinglulu { 103*91f16700Schasinglulu unsigned int blocked = 0U; 104*91f16700Schasinglulu unsigned int i; 105*91f16700Schasinglulu bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id); 106*91f16700Schasinglulu 107*91f16700Schasinglulu if ((src == NULL) || (dest == NULL)) { 108*91f16700Schasinglulu blocked = SPM_COND_CHECK_FAIL; 109*91f16700Schasinglulu } else { 110*91f16700Schasinglulu for (i = 0U; i < PLAT_SPM_COND_MAX; i++) { 111*91f16700Schasinglulu if (res != NULL) { 112*91f16700Schasinglulu res->table_cg[i] = (src->table_cg[i] & dest->table_cg[i]); 113*91f16700Schasinglulu if (is_system_suspend && ((res->table_cg[i]) != 0U)) { 114*91f16700Schasinglulu INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n", 115*91f16700Schasinglulu dest->name, i, idle_cg_info[i].addr, 116*91f16700Schasinglulu res->table_cg[i]); 117*91f16700Schasinglulu } 118*91f16700Schasinglulu 119*91f16700Schasinglulu if ((res->table_cg[i]) != 0U) { 120*91f16700Schasinglulu blocked |= BIT(i); 121*91f16700Schasinglulu } 122*91f16700Schasinglulu } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) { 123*91f16700Schasinglulu blocked |= BIT(i); 124*91f16700Schasinglulu break; 125*91f16700Schasinglulu } 126*91f16700Schasinglulu } 127*91f16700Schasinglulu 128*91f16700Schasinglulu if (res != NULL) { 129*91f16700Schasinglulu res->table_pll = (src->table_pll & dest->table_pll); 130*91f16700Schasinglulu 131*91f16700Schasinglulu if (res->table_pll != 0U) { 132*91f16700Schasinglulu blocked |= (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) | 133*91f16700Schasinglulu SPM_COND_CHECK_BLOCKED_PLL; 134*91f16700Schasinglulu } 135*91f16700Schasinglulu } else if ((src->table_pll & dest->table_pll) != 0U) { 136*91f16700Schasinglulu blocked |= SPM_COND_CHECK_BLOCKED_PLL; 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu if (is_system_suspend && ((blocked) != 0U)) { 140*91f16700Schasinglulu INFO("suspend: %s total blocked = 0x%08x\n", dest->name, blocked); 141*91f16700Schasinglulu } 142*91f16700Schasinglulu } 143*91f16700Schasinglulu 144*91f16700Schasinglulu return blocked; 145*91f16700Schasinglulu } 146*91f16700Schasinglulu 147*91f16700Schasinglulu #define IS_MT_SPM_PWR_OFF(mask) \ 148*91f16700Schasinglulu (((mmio_read_32(SPM_PWR_STATUS) & mask) == 0U) && \ 149*91f16700Schasinglulu ((mmio_read_32(SPM_PWR_STATUS_2ND) & mask) == 0U)) 150*91f16700Schasinglulu 151*91f16700Schasinglulu int mt_spm_cond_update(struct mt_resource_constraint **con, unsigned int num, 152*91f16700Schasinglulu int stateid, void *priv) 153*91f16700Schasinglulu { 154*91f16700Schasinglulu int res; 155*91f16700Schasinglulu uint32_t i; 156*91f16700Schasinglulu struct mt_resource_constraint *const *rc; 157*91f16700Schasinglulu 158*91f16700Schasinglulu /* read all cg state */ 159*91f16700Schasinglulu for (i = 0U; i < PLAT_SPM_COND_MAX; i++) { 160*91f16700Schasinglulu spm_cond_t.table_cg[i] = 0U; 161*91f16700Schasinglulu 162*91f16700Schasinglulu /* check mtcmos, if off set idle_value and clk to 0 disable */ 163*91f16700Schasinglulu if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) { 164*91f16700Schasinglulu continue; 165*91f16700Schasinglulu } 166*91f16700Schasinglulu 167*91f16700Schasinglulu /* check clkmux */ 168*91f16700Schasinglulu if (is_clkmux_pdn(idle_cg_info[i].clkmux_id)) { 169*91f16700Schasinglulu continue; 170*91f16700Schasinglulu } 171*91f16700Schasinglulu 172*91f16700Schasinglulu spm_cond_t.table_cg[i] = idle_cg_info[i].bit_flip ? 173*91f16700Schasinglulu ~mmio_read_32(idle_cg_info[i].addr) : 174*91f16700Schasinglulu mmio_read_32(idle_cg_info[i].addr); 175*91f16700Schasinglulu } 176*91f16700Schasinglulu 177*91f16700Schasinglulu spm_cond_t.table_pll = 0U; 178*91f16700Schasinglulu if ((mmio_read_32(PLL_MFGPLL) & 0x1) != 0U) { 179*91f16700Schasinglulu spm_cond_t.table_pll |= PLL_BIT_MFGPLL; 180*91f16700Schasinglulu } 181*91f16700Schasinglulu 182*91f16700Schasinglulu if ((mmio_read_32(PLL_MMPLL) & 0x1) != 0U) { 183*91f16700Schasinglulu spm_cond_t.table_pll |= PLL_BIT_MMPLL; 184*91f16700Schasinglulu } 185*91f16700Schasinglulu 186*91f16700Schasinglulu if ((mmio_read_32(PLL_UNIVPLL) & 0x1) != 0U) { 187*91f16700Schasinglulu spm_cond_t.table_pll |= PLL_BIT_UNIVPLL; 188*91f16700Schasinglulu } 189*91f16700Schasinglulu 190*91f16700Schasinglulu if ((mmio_read_32(PLL_MSDCPLL) & 0x1) != 0U) { 191*91f16700Schasinglulu spm_cond_t.table_pll |= PLL_BIT_MSDCPLL; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu 194*91f16700Schasinglulu if ((mmio_read_32(PLL_TVDPLL) & 0x1) != 0U) { 195*91f16700Schasinglulu spm_cond_t.table_pll |= PLL_BIT_TVDPLL; 196*91f16700Schasinglulu } 197*91f16700Schasinglulu 198*91f16700Schasinglulu spm_cond_t.priv = priv; 199*91f16700Schasinglulu 200*91f16700Schasinglulu for (rc = con; *rc != NULL; rc++) { 201*91f16700Schasinglulu if (((*rc)->update) == NULL) { 202*91f16700Schasinglulu continue; 203*91f16700Schasinglulu } 204*91f16700Schasinglulu 205*91f16700Schasinglulu res = (*rc)->update(stateid, PLAT_RC_UPDATE_CONDITION, 206*91f16700Schasinglulu (void const *)&spm_cond_t); 207*91f16700Schasinglulu if (res != MT_RM_STATUS_OK) { 208*91f16700Schasinglulu break; 209*91f16700Schasinglulu } 210*91f16700Schasinglulu } 211*91f16700Schasinglulu 212*91f16700Schasinglulu return 0; 213*91f16700Schasinglulu } 214