1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 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 <lib/mmio.h> 9*91f16700Schasinglulu #include <lib/pm/mtk_pm.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 <platform_def.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #define TOPCKGEB_BASE (IO_PHYS) 16*91f16700Schasinglulu 17*91f16700Schasinglulu #define MT_LP_TZ_INFRA_REG(ofs) (INFRACFG_AO_BASE + ofs) 18*91f16700Schasinglulu 19*91f16700Schasinglulu #define MT_LP_TZ_SPM_REG(ofs) (SPM_BASE + ofs) 20*91f16700Schasinglulu #define MT_LP_TZ_TOPCK_REG(ofs) (TOPCKGEB_BASE + ofs) 21*91f16700Schasinglulu #define MT_LP_TZ_APMIXEDSYS(ofs) (APMIXEDSYS + ofs) 22*91f16700Schasinglulu 23*91f16700Schasinglulu #define MT_LP_TZ_VPPSYS0_REG(ofs) (VPPSYS0_BASE + ofs) 24*91f16700Schasinglulu #define MT_LP_TZ_VPPSYS1_REG(ofs) (VPPSYS1_BASE + ofs) 25*91f16700Schasinglulu #define MT_LP_TZ_VDOSYS0_REG(ofs) (VDOSYS0_BASE + ofs) 26*91f16700Schasinglulu #define MT_LP_TZ_VDOSYS1_REG(ofs) (VDOSYS1_BASE + ofs) 27*91f16700Schasinglulu 28*91f16700Schasinglulu #define MT_LP_TZ_PERI_AO_REG(ofs) (PERICFG_AO_BASE + ofs) 29*91f16700Schasinglulu 30*91f16700Schasinglulu #undef SPM_PWR_STATUS 31*91f16700Schasinglulu #define SPM_PWR_STATUS MT_LP_TZ_SPM_REG(0x016C) 32*91f16700Schasinglulu #define SPM_PWR_STATUS_2ND MT_LP_TZ_SPM_REG(0x0170) 33*91f16700Schasinglulu #define SPM_CPU_PWR_STATUS MT_LP_TZ_SPM_REG(0x0174) 34*91f16700Schasinglulu #define INFRA_SW_CG0 MT_LP_TZ_INFRA_REG(0x0090) 35*91f16700Schasinglulu #define INFRA_SW_CG1 MT_LP_TZ_INFRA_REG(0x0094) 36*91f16700Schasinglulu #define INFRA_SW_CG2 MT_LP_TZ_INFRA_REG(0x00AC) 37*91f16700Schasinglulu #define INFRA_SW_CG3 MT_LP_TZ_INFRA_REG(0x00C8) 38*91f16700Schasinglulu #define INFRA_SW_CG4 MT_LP_TZ_INFRA_REG(0x00E8) 39*91f16700Schasinglulu #define TOP_SW_I2C_CG MT_LP_TZ_TOPCK_REG(0x00A4) 40*91f16700Schasinglulu #define PERI_SW_CG0 MT_LP_TZ_PERI_AO_REG(0x0018) 41*91f16700Schasinglulu #define VPPSYS0_SW_CG0 MT_LP_TZ_VPPSYS0_REG(0x0020) 42*91f16700Schasinglulu #define VPPSYS0_SW_CG1 MT_LP_TZ_VPPSYS0_REG(0x002C) 43*91f16700Schasinglulu #define VPPSYS0_SW_CG2 MT_LP_TZ_VPPSYS0_REG(0x0038) 44*91f16700Schasinglulu #define VPPSYS1_SW_CG0 MT_LP_TZ_VPPSYS1_REG(0x0100) 45*91f16700Schasinglulu #define VPPSYS1_SW_CG1 MT_LP_TZ_VPPSYS1_REG(0x0110) 46*91f16700Schasinglulu #define VDOSYS0_SW_CG0 MT_LP_TZ_VDOSYS0_REG(0x0100) 47*91f16700Schasinglulu #define VDOSYS0_SW_CG1 MT_LP_TZ_VDOSYS0_REG(0x0110) 48*91f16700Schasinglulu #define VDOSYS1_SW_CG0 MT_LP_TZ_VDOSYS1_REG(0x0100) 49*91f16700Schasinglulu #define VDOSYS1_SW_CG1 MT_LP_TZ_VDOSYS1_REG(0x0120) 50*91f16700Schasinglulu #define VDOSYS1_SW_CG2 MT_LP_TZ_VDOSYS1_REG(0x0130) 51*91f16700Schasinglulu 52*91f16700Schasinglulu #define CLK_CFG(id) MT_LP_TZ_TOPCK_REG(0x2c + id * 0xc) 53*91f16700Schasinglulu 54*91f16700Schasinglulu enum { 55*91f16700Schasinglulu /* CLK_CFG_0 1000_002c */ 56*91f16700Schasinglulu CLKMUX_VPP = 0, 57*91f16700Schasinglulu NF_CLKMUX, 58*91f16700Schasinglulu }; 59*91f16700Schasinglulu 60*91f16700Schasinglulu #define CLK_CHECK BIT(31) 61*91f16700Schasinglulu 62*91f16700Schasinglulu static bool check_clkmux_pdn(unsigned int clkmux_id) 63*91f16700Schasinglulu { 64*91f16700Schasinglulu unsigned int reg, val, idx; 65*91f16700Schasinglulu bool ret = false; 66*91f16700Schasinglulu 67*91f16700Schasinglulu if ((clkmux_id & CLK_CHECK) != 0U) { 68*91f16700Schasinglulu clkmux_id = (clkmux_id & ~CLK_CHECK); 69*91f16700Schasinglulu reg = clkmux_id / 4U; 70*91f16700Schasinglulu val = mmio_read_32(CLK_CFG(reg)); 71*91f16700Schasinglulu idx = clkmux_id % 4U; 72*91f16700Schasinglulu ret = (((val >> (idx * 8U)) & 0x80) != 0U); 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu return ret; 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu static struct mt_spm_cond_tables spm_cond_t; 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* local definitions */ 81*91f16700Schasinglulu struct idle_cond_info { 82*91f16700Schasinglulu /* check SPM_PWR_STATUS for bit definition */ 83*91f16700Schasinglulu unsigned int subsys_mask; 84*91f16700Schasinglulu /* cg address */ 85*91f16700Schasinglulu uintptr_t addr; 86*91f16700Schasinglulu /* bitflip value from *addr ? */ 87*91f16700Schasinglulu bool bBitflip; 88*91f16700Schasinglulu /* check clkmux if bit 31 = 1, id is bit[30:0] */ 89*91f16700Schasinglulu unsigned int clkmux_id; 90*91f16700Schasinglulu }; 91*91f16700Schasinglulu 92*91f16700Schasinglulu #define IDLE_CG(mask, addr, bitflip, clkmux) {mask, (uintptr_t)addr, bitflip, clkmux} 93*91f16700Schasinglulu 94*91f16700Schasinglulu static struct idle_cond_info idle_cg_info[PLAT_SPM_COND_MAX] = { 95*91f16700Schasinglulu IDLE_CG(0xffffffff, SPM_PWR_STATUS, false, 0), 96*91f16700Schasinglulu IDLE_CG(0xffffffff, SPM_CPU_PWR_STATUS, false, 0), 97*91f16700Schasinglulu IDLE_CG(0xffffffff, INFRA_SW_CG0, true, 0), 98*91f16700Schasinglulu IDLE_CG(0xffffffff, INFRA_SW_CG1, true, 0), 99*91f16700Schasinglulu IDLE_CG(0xffffffff, INFRA_SW_CG2, true, 0), 100*91f16700Schasinglulu IDLE_CG(0xffffffff, INFRA_SW_CG3, true, 0), 101*91f16700Schasinglulu IDLE_CG(0xffffffff, INFRA_SW_CG4, true, 0), 102*91f16700Schasinglulu IDLE_CG(0xffffffff, PERI_SW_CG0, true, 0), 103*91f16700Schasinglulu IDLE_CG(0x00000800, VPPSYS0_SW_CG0, true, (CLK_CHECK | CLKMUX_VPP)), 104*91f16700Schasinglulu IDLE_CG(0x00000800, VPPSYS0_SW_CG1, true, (CLK_CHECK | CLKMUX_VPP)), 105*91f16700Schasinglulu IDLE_CG(0x00001000, VPPSYS1_SW_CG0, true, (CLK_CHECK | CLKMUX_VPP)), 106*91f16700Schasinglulu IDLE_CG(0x00001000, VPPSYS1_SW_CG1, true, (CLK_CHECK | CLKMUX_VPP)), 107*91f16700Schasinglulu IDLE_CG(0x00002000, VDOSYS0_SW_CG0, true, (CLK_CHECK | CLKMUX_VPP)), 108*91f16700Schasinglulu IDLE_CG(0x00002000, VDOSYS0_SW_CG1, true, (CLK_CHECK | CLKMUX_VPP)), 109*91f16700Schasinglulu IDLE_CG(0x00004000, VDOSYS1_SW_CG0, true, (CLK_CHECK | CLKMUX_VPP)), 110*91f16700Schasinglulu IDLE_CG(0x00004000, VDOSYS1_SW_CG1, true, (CLK_CHECK | CLKMUX_VPP)), 111*91f16700Schasinglulu IDLE_CG(0x00004000, VDOSYS1_SW_CG2, true, (CLK_CHECK | CLKMUX_VPP)), 112*91f16700Schasinglulu }; 113*91f16700Schasinglulu 114*91f16700Schasinglulu /* check pll idle condition */ 115*91f16700Schasinglulu #define PLL_MFGPLL MT_LP_TZ_APMIXEDSYS(0x340) 116*91f16700Schasinglulu #define PLL_MMPLL MT_LP_TZ_APMIXEDSYS(0x544) 117*91f16700Schasinglulu #define PLL_UNIVPLL MT_LP_TZ_APMIXEDSYS(0x504) 118*91f16700Schasinglulu #define PLL_MSDCPLL MT_LP_TZ_APMIXEDSYS(0x514) 119*91f16700Schasinglulu #define PLL_TVDPLL1 MT_LP_TZ_APMIXEDSYS(0x524) 120*91f16700Schasinglulu #define PLL_TVDPLL2 MT_LP_TZ_APMIXEDSYS(0x534) 121*91f16700Schasinglulu #define PLL_ETHPLL MT_LP_TZ_APMIXEDSYS(0x44c) 122*91f16700Schasinglulu #define PLL_IMGPLL MT_LP_TZ_APMIXEDSYS(0x554) 123*91f16700Schasinglulu #define PLL_APLL1 MT_LP_TZ_APMIXEDSYS(0x304) 124*91f16700Schasinglulu #define PLL_APLL2 MT_LP_TZ_APMIXEDSYS(0x318) 125*91f16700Schasinglulu #define PLL_APLL3 MT_LP_TZ_APMIXEDSYS(0x32c) 126*91f16700Schasinglulu #define PLL_APLL4 MT_LP_TZ_APMIXEDSYS(0x404) 127*91f16700Schasinglulu #define PLL_APLL5 MT_LP_TZ_APMIXEDSYS(0x418) 128*91f16700Schasinglulu 129*91f16700Schasinglulu unsigned int mt_spm_cond_check(int state_id, 130*91f16700Schasinglulu const struct mt_spm_cond_tables *src, 131*91f16700Schasinglulu const struct mt_spm_cond_tables *dest, 132*91f16700Schasinglulu struct mt_spm_cond_tables *res) 133*91f16700Schasinglulu { 134*91f16700Schasinglulu unsigned int b_res = 0U; 135*91f16700Schasinglulu unsigned int i; 136*91f16700Schasinglulu bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id); 137*91f16700Schasinglulu 138*91f16700Schasinglulu if ((src == NULL) || (dest == NULL)) { 139*91f16700Schasinglulu return SPM_COND_CHECK_FAIL; 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu for (i = 0; i < PLAT_SPM_COND_MAX; i++) { 143*91f16700Schasinglulu if (res != NULL) { 144*91f16700Schasinglulu res->table_cg[i] = (src->table_cg[i] & dest->table_cg[i]); 145*91f16700Schasinglulu if (is_system_suspend && ((res->table_cg[i]) != 0U)) { 146*91f16700Schasinglulu INFO("suspend: %s block[%u](0x%lx) = 0x%08x\n", 147*91f16700Schasinglulu dest->name, i, idle_cg_info[i].addr, 148*91f16700Schasinglulu res->table_cg[i]); 149*91f16700Schasinglulu } 150*91f16700Schasinglulu 151*91f16700Schasinglulu if ((res->table_cg[i]) != 0U) { 152*91f16700Schasinglulu b_res |= BIT(i); 153*91f16700Schasinglulu } 154*91f16700Schasinglulu } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) { 155*91f16700Schasinglulu b_res |= BIT(i); 156*91f16700Schasinglulu break; 157*91f16700Schasinglulu } 158*91f16700Schasinglulu } 159*91f16700Schasinglulu 160*91f16700Schasinglulu if (res != NULL) { 161*91f16700Schasinglulu res->table_pll = (src->table_pll & dest->table_pll); 162*91f16700Schasinglulu 163*91f16700Schasinglulu if ((res->table_pll) != 0U) { 164*91f16700Schasinglulu b_res |= (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) | 165*91f16700Schasinglulu SPM_COND_CHECK_BLOCKED_PLL; 166*91f16700Schasinglulu } 167*91f16700Schasinglulu } else if ((src->table_pll & dest->table_pll) != 0U) { 168*91f16700Schasinglulu b_res |= SPM_COND_CHECK_BLOCKED_PLL; 169*91f16700Schasinglulu } 170*91f16700Schasinglulu 171*91f16700Schasinglulu if (is_system_suspend && ((b_res) != 0U)) { 172*91f16700Schasinglulu INFO("suspend: %s total blocked = 0x%08x\n", dest->name, b_res); 173*91f16700Schasinglulu } 174*91f16700Schasinglulu 175*91f16700Schasinglulu return b_res; 176*91f16700Schasinglulu } 177*91f16700Schasinglulu 178*91f16700Schasinglulu unsigned int mt_spm_dump_all_pll(const struct mt_spm_cond_tables *src, 179*91f16700Schasinglulu const struct mt_spm_cond_tables *dest, 180*91f16700Schasinglulu struct mt_spm_cond_tables *res) 181*91f16700Schasinglulu { 182*91f16700Schasinglulu unsigned int b_res = 0U; 183*91f16700Schasinglulu 184*91f16700Schasinglulu if (res != NULL) { 185*91f16700Schasinglulu res->table_all_pll = src->table_all_pll; 186*91f16700Schasinglulu if ((res->table_all_pll) != 0U) { 187*91f16700Schasinglulu b_res |= (res->table_all_pll << SPM_COND_BLOCKED_PLL_IDX) | 188*91f16700Schasinglulu SPM_COND_CHECK_BLOCKED_PLL; 189*91f16700Schasinglulu } 190*91f16700Schasinglulu } else if ((src->table_pll & dest->table_pll) != 0U) { 191*91f16700Schasinglulu b_res |= SPM_COND_CHECK_BLOCKED_PLL; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu 194*91f16700Schasinglulu return b_res; 195*91f16700Schasinglulu } 196*91f16700Schasinglulu 197*91f16700Schasinglulu #define IS_MT_SPM_PWR_OFF(mask) \ 198*91f16700Schasinglulu (!(mmio_read_32(SPM_PWR_STATUS) & mask) && \ 199*91f16700Schasinglulu !(mmio_read_32(SPM_PWR_STATUS_2ND) & mask)) 200*91f16700Schasinglulu 201*91f16700Schasinglulu int mt_spm_cond_update(struct mt_resource_constraint **con, unsigned int num, 202*91f16700Schasinglulu int stateid, void *priv) 203*91f16700Schasinglulu { 204*91f16700Schasinglulu static const struct { 205*91f16700Schasinglulu uintptr_t en_reg; 206*91f16700Schasinglulu uint32_t pll_b; 207*91f16700Schasinglulu } plls[] = { 208*91f16700Schasinglulu { PLL_MFGPLL, PLL_BIT_MFGPLL }, 209*91f16700Schasinglulu { PLL_MMPLL, PLL_BIT_MMPLL }, 210*91f16700Schasinglulu { PLL_UNIVPLL, PLL_BIT_UNIVPLL }, 211*91f16700Schasinglulu { PLL_MSDCPLL, PLL_BIT_MSDCPLL }, 212*91f16700Schasinglulu { PLL_TVDPLL1, PLL_BIT_TVDPLL1 }, 213*91f16700Schasinglulu { PLL_TVDPLL2, PLL_BIT_TVDPLL2 }, 214*91f16700Schasinglulu { PLL_ETHPLL, PLL_BIT_ETHPLL }, 215*91f16700Schasinglulu { PLL_IMGPLL, PLL_BIT_IMGPLL }, 216*91f16700Schasinglulu { PLL_APLL1, PLL_BIT_APLL1 }, 217*91f16700Schasinglulu { PLL_APLL2, PLL_BIT_APLL2 }, 218*91f16700Schasinglulu { PLL_APLL3, PLL_BIT_APLL3 }, 219*91f16700Schasinglulu { PLL_APLL4, PLL_BIT_APLL4 }, 220*91f16700Schasinglulu { PLL_APLL5, PLL_BIT_APLL5 }, 221*91f16700Schasinglulu }; 222*91f16700Schasinglulu 223*91f16700Schasinglulu int res; 224*91f16700Schasinglulu unsigned int i; 225*91f16700Schasinglulu struct mt_resource_constraint *const *_con; 226*91f16700Schasinglulu 227*91f16700Schasinglulu /* read all cg state */ 228*91f16700Schasinglulu for (i = 0U; i < PLAT_SPM_COND_MAX; i++) { 229*91f16700Schasinglulu spm_cond_t.table_cg[i] = 0U; 230*91f16700Schasinglulu 231*91f16700Schasinglulu /* check mtcmos, if off set idle_value and clk to 0 disable */ 232*91f16700Schasinglulu if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) { 233*91f16700Schasinglulu continue; 234*91f16700Schasinglulu } 235*91f16700Schasinglulu /* check clkmux */ 236*91f16700Schasinglulu if (check_clkmux_pdn(idle_cg_info[i].clkmux_id)) { 237*91f16700Schasinglulu continue; 238*91f16700Schasinglulu } 239*91f16700Schasinglulu spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ? 240*91f16700Schasinglulu ~mmio_read_32(idle_cg_info[i].addr) : 241*91f16700Schasinglulu mmio_read_32(idle_cg_info[i].addr); 242*91f16700Schasinglulu } 243*91f16700Schasinglulu 244*91f16700Schasinglulu spm_cond_t.table_pll = 0U; 245*91f16700Schasinglulu for (i = 0U; i < ARRAY_SIZE(plls); i++) { 246*91f16700Schasinglulu if ((mmio_read_32(plls[i].en_reg) & BIT(9)) != 0U) { 247*91f16700Schasinglulu spm_cond_t.table_pll |= plls[i].pll_b; 248*91f16700Schasinglulu } 249*91f16700Schasinglulu } 250*91f16700Schasinglulu 251*91f16700Schasinglulu spm_cond_t.priv = priv; 252*91f16700Schasinglulu for (i = 0U, _con = con; (*_con != NULL) && (i < num); _con++, i++) { 253*91f16700Schasinglulu if ((*_con)->update == NULL) { 254*91f16700Schasinglulu continue; 255*91f16700Schasinglulu } 256*91f16700Schasinglulu res = (*_con)->update(stateid, PLAT_RC_UPDATE_CONDITION, 257*91f16700Schasinglulu (void const *)&spm_cond_t); 258*91f16700Schasinglulu if (res != MT_RM_STATUS_OK) { 259*91f16700Schasinglulu break; 260*91f16700Schasinglulu } 261*91f16700Schasinglulu } 262*91f16700Schasinglulu 263*91f16700Schasinglulu return 0; 264*91f16700Schasinglulu } 265