blob: fe6e598287b9308d53ef7e388bcb76518cdf1411 [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
129unsigned int mt_spm_cond_check(const struct mt_spm_cond_tables *src,
130 const struct mt_spm_cond_tables *dest,
131 struct mt_spm_cond_tables *res)
132{
133 unsigned int b_res = 0U;
134 unsigned int i;
135
136 if ((src == NULL) || (dest == NULL)) {
137 return SPM_COND_CHECK_FAIL;
138 }
139
140 for (i = 0; i < PLAT_SPM_COND_MAX; i++) {
141 if (res != NULL) {
142 res->table_cg[i] = (src->table_cg[i] & dest->table_cg[i]);
143
144 if ((res->table_cg[i]) != 0U) {
145 b_res |= BIT(i);
146 }
147 } else if ((src->table_cg[i] & dest->table_cg[i]) != 0U) {
148 b_res |= BIT(i);
149 break;
150 }
151 }
152
153 if (res != NULL) {
154 res->table_pll = (src->table_pll & dest->table_pll);
155
156 if ((res->table_pll) != 0U) {
157 b_res |= (res->table_pll << SPM_COND_BLOCKED_PLL_IDX) |
158 SPM_COND_CHECK_BLOCKED_PLL;
159 }
160 } else if ((src->table_pll & dest->table_pll) != 0U) {
161 b_res |= SPM_COND_CHECK_BLOCKED_PLL;
162 }
163
164 return b_res;
165}
166
167unsigned int mt_spm_dump_all_pll(const struct mt_spm_cond_tables *src,
168 const struct mt_spm_cond_tables *dest,
169 struct mt_spm_cond_tables *res)
170{
171 unsigned int b_res = 0U;
172
173 if (res != NULL) {
174 res->table_all_pll = src->table_all_pll;
175 if ((res->table_all_pll) != 0U) {
176 b_res |= (res->table_all_pll << SPM_COND_BLOCKED_PLL_IDX) |
177 SPM_COND_CHECK_BLOCKED_PLL;
178 }
179 } else if ((src->table_pll & dest->table_pll) != 0U) {
180 b_res |= SPM_COND_CHECK_BLOCKED_PLL;
181 }
182
183 return b_res;
184}
185
186#define IS_MT_SPM_PWR_OFF(mask) \
187 (!(mmio_read_32(SPM_PWR_STATUS) & mask) && \
188 !(mmio_read_32(SPM_PWR_STATUS_2ND) & mask))
189
developerfbc1ea92023-01-06 15:50:33 +0800190int mt_spm_cond_update(struct mt_resource_constraint **con, unsigned int num,
191 int stateid, void *priv)
developer451d49d2022-11-16 21:52:21 +0800192{
193 static const struct {
194 uintptr_t en_reg;
195 uint32_t pll_b;
196 } plls[] = {
197 { PLL_MFGPLL, PLL_BIT_MFGPLL },
198 { PLL_MMPLL, PLL_BIT_MMPLL },
199 { PLL_UNIVPLL, PLL_BIT_UNIVPLL },
200 { PLL_MSDCPLL, PLL_BIT_MSDCPLL },
201 { PLL_TVDPLL1, PLL_BIT_TVDPLL1 },
202 { PLL_TVDPLL2, PLL_BIT_TVDPLL2 },
203 { PLL_ETHPLL, PLL_BIT_ETHPLL },
204 { PLL_IMGPLL, PLL_BIT_IMGPLL },
205 { PLL_APLL1, PLL_BIT_APLL1 },
206 { PLL_APLL2, PLL_BIT_APLL2 },
207 { PLL_APLL3, PLL_BIT_APLL3 },
208 { PLL_APLL4, PLL_BIT_APLL4 },
209 { PLL_APLL5, PLL_BIT_APLL5 },
210 };
211
developerfbc1ea92023-01-06 15:50:33 +0800212 int res;
213 unsigned int i;
developer451d49d2022-11-16 21:52:21 +0800214 struct mt_resource_constraint *const *_con;
215
216 /* read all cg state */
developerfbc1ea92023-01-06 15:50:33 +0800217 for (i = 0U; i < PLAT_SPM_COND_MAX; i++) {
developer451d49d2022-11-16 21:52:21 +0800218 spm_cond_t.table_cg[i] = 0U;
219
220 /* check mtcmos, if off set idle_value and clk to 0 disable */
221 if (IS_MT_SPM_PWR_OFF(idle_cg_info[i].subsys_mask)) {
222 continue;
223 }
224 /* check clkmux */
225 if (check_clkmux_pdn(idle_cg_info[i].clkmux_id)) {
226 continue;
227 }
228 spm_cond_t.table_cg[i] = idle_cg_info[i].bBitflip ?
229 ~mmio_read_32(idle_cg_info[i].addr) :
230 mmio_read_32(idle_cg_info[i].addr);
231 }
232
233 spm_cond_t.table_pll = 0U;
developerfbc1ea92023-01-06 15:50:33 +0800234 for (i = 0U; i < ARRAY_SIZE(plls); i++) {
developer451d49d2022-11-16 21:52:21 +0800235 if ((mmio_read_32(plls[i].en_reg) & BIT(9)) != 0U) {
236 spm_cond_t.table_pll |= plls[i].pll_b;
237 }
238 }
239
240 spm_cond_t.priv = priv;
developerfbc1ea92023-01-06 15:50:33 +0800241 for (i = 0U, _con = con; (*_con != NULL) && (i < num); _con++, i++) {
developer451d49d2022-11-16 21:52:21 +0800242 if ((*_con)->update == NULL) {
243 continue;
244 }
245 res = (*_con)->update(stateid, PLAT_RC_UPDATE_CONDITION,
246 (void const *)&spm_cond_t);
247 if (res != MT_RM_STATUS_OK) {
248 break;
249 }
250 }
251
252 return 0;
253}