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