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