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