blob: bed55c906d3359401e4db78f5eee0da7db276c98 [file] [log] [blame]
developer451d49d2022-11-16 21:52:21 +08001/*
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
54enum {
55 /* CLK_CFG_0 1000_002c */
56 CLKMUX_VPP = 0,
57 NF_CLKMUX,
58};
59
60#define CLK_CHECK BIT(31)
61
62static 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
78static struct mt_spm_cond_tables spm_cond_t;
79
80/* local definitions */
81struct 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
94static 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
developer68ff2df2023-05-03 19:11:29 +0800129unsigned int mt_spm_cond_check(int state_id,
130 const struct mt_spm_cond_tables *src,
developer451d49d2022-11-16 21:52:21 +0800131 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;
developer68ff2df2023-05-03 19:11:29 +0800136 bool is_system_suspend = IS_PLAT_SUSPEND_ID(state_id);
developer451d49d2022-11-16 21:52:21 +0800137
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]);
developer68ff2df2023-05-03 19:11:29 +0800145 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 }
developer451d49d2022-11-16 21:52:21 +0800150
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
developer68ff2df2023-05-03 19:11:29 +0800171 if (is_system_suspend && ((b_res) != 0U)) {
172 INFO("suspend: %s total blocked = 0x%08x\n", dest->name, b_res);
173 }
174
developer451d49d2022-11-16 21:52:21 +0800175 return b_res;
176}
177
178unsigned 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
developerfbc1ea92023-01-06 15:50:33 +0800201int mt_spm_cond_update(struct mt_resource_constraint **con, unsigned int num,
202 int stateid, void *priv)
developer451d49d2022-11-16 21:52:21 +0800203{
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
developerfbc1ea92023-01-06 15:50:33 +0800223 int res;
224 unsigned int i;
developer451d49d2022-11-16 21:52:21 +0800225 struct mt_resource_constraint *const *_con;
226
227 /* read all cg state */
developerfbc1ea92023-01-06 15:50:33 +0800228 for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
developer451d49d2022-11-16 21:52:21 +0800229 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;
developerfbc1ea92023-01-06 15:50:33 +0800245 for (i = 0U; i < ARRAY_SIZE(plls); i++) {
developer451d49d2022-11-16 21:52:21 +0800246 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;
developerfbc1ea92023-01-06 15:50:33 +0800252 for (i = 0U, _con = con; (*_con != NULL) && (i < num); _con++, i++) {
developer451d49d2022-11-16 21:52:21 +0800253 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}