1 /*
2 * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <errno.h>
8
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12
13 #include <apupwr_clkctl.h>
14 #include <apupwr_clkctl_def.h>
15 #include <mtk_plat_common.h>
16 #include <platform_def.h>
17
18 /* 8195 use PCW mode to change freq directly */
19 enum pll_set_rate_mode PLL_MODE = CON0_PCW;
20
21 char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = {
22 "V_VPU0",
23 "V_VPU1",
24 "V_MDLA0",
25 "V_MDLA1",
26 "V_APU_CONN",
27 "V_TOP_IOMMU",
28 "V_VCORE",
29 };
30
31 uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = {
32 APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2,
33 APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5,
34 APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7
35 };
36
37 uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = {
38 APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2,
39 APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5,
40 APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7
41 };
42
43 struct reg_seq {
44 uint32_t address;
45 uint32_t val;
46 };
47
48 static const struct reg_seq init_acc_cfg[] = {
49 { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) },
50 { APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) },
51 { APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) },
52 { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) },
53 { APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) },
54 { APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) },
55 { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) },
56 { APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) },
57 { APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) },
58 { APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) },
59 { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) },
60 { APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) },
61 { APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) },
62 { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) },
63 { APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) },
64 { APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) },
65 { APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) },
66 { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) },
67 { APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) },
68 { APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) },
69 };
70
apupwr_smc_acc_init_all(void)71 int32_t apupwr_smc_acc_init_all(void)
72 {
73 int32_t i;
74
75 for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) {
76 apupwr_writel(init_acc_cfg[i].val,
77 init_acc_cfg[i].address);
78 }
79
80 /* Deault ACC will raise APU_DIV_2 */
81 apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
82 true, V_APU_CONN);
83
84 apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
85 true, V_TOP_IOMMU);
86
87 apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ,
88 true, V_VPU0);
89
90 apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ,
91 true, V_MDLA0);
92
93 return 0;
94 }
95
apupwr_smc_acc_top(bool enable)96 void apupwr_smc_acc_top(bool enable)
97 {
98 if (enable) {
99 apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]);
100 apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]);
101 } else {
102 apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]);
103 apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]);
104 }
105 }
106
107 /*
108 * acc_clk_set_parent:ACC MUX select
109 * 0. freq parameters here, only ACC clksrc is valid
110 * 1. Switch between APUPLL <=> Parking (F26M, PARK)
111 * 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU
112 * 3. Clear APU Div2 while Parking
113 * 4. Only use clksrc of APUPLL while ACC CG_APU is on
114 */
apupwr_smc_acc_set_parent(uint32_t freq,uint32_t domain)115 int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain)
116 {
117 uint32_t acc_set = 0;
118 uint32_t acc_clr = 0;
119 int32_t ret = 0;
120
121 if (freq > DVFS_FREQ_ACC_APUPLL) {
122 ERROR("%s wrong clksrc: %d\n", __func__, freq);
123 ret = -EIO;
124 goto err;
125 }
126
127 switch (domain) {
128 case V_VPU1:
129 case V_VPU0:
130 case V_MDLA1:
131 case V_MDLA0:
132 case V_APU_CONN:
133 case V_TOP_IOMMU:
134 acc_set = aacc_set[domain];
135 acc_clr = aacc_clr[domain];
136 break;
137 default:
138 ret = -EIO;
139 break;
140 }
141
142 /* Select park source */
143 switch (freq) {
144 case DVFS_FREQ_ACC_PARKING:
145 /* Select park source */
146 apupwr_writel(BIT(BIT_SEL_PARK), acc_set);
147 apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
148 /* Enable park cg */
149 apupwr_writel(BIT(BIT_CGEN_PARK), acc_set);
150 apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr);
151 /* Select park path */
152 apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
153 /* clear apu div 2 */
154 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
155 break;
156
157 case DVFS_FREQ_ACC_APUPLL:
158 /* Select park path */
159 apupwr_writel(BIT(BIT_SEL_APU), acc_set);
160 /* Clear park cg */
161 apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) |
162 BIT(BIT_CGEN_SOC), acc_clr);
163 break;
164
165 case DVFS_FREQ_ACC_SOC:
166 /* Select park source */
167 apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
168 apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
169 /* Enable park cg */
170 apupwr_writel(BIT(BIT_CGEN_SOC), acc_set);
171 apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr);
172 /* Select park path */
173 apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
174 /* clear apu div 2 */
175 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
176 break;
177
178 case DVFS_FREQ_ACC_26M:
179 case DVFS_FREQ_NOT_SUPPORT:
180 default:
181 /* Select park source */
182 apupwr_writel(BIT(BIT_SEL_F26M), acc_set);
183 apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
184 /* Enable park cg */
185 apupwr_writel(BIT(BIT_CGEN_F26M), acc_set);
186 apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr);
187 /* Select park path */
188 apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
189 /* clear apu div 2 */
190 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
191 ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n",
192 __func__, freq);
193 break;
194 }
195
196 err:
197 return ret;
198 }
199
apupwr_smc_pll_set_rate(uint32_t freq,bool div2,uint32_t domain)200 int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain)
201 {
202 int32_t ret = 0;
203 uint32_t acc_set0 = 0, acc_set1 = 0;
204
205 if (freq > DVFS_FREQ_MAX) {
206 ERROR("%s wrong freq: %d\n", __func__, freq);
207 ret = -EIO;
208 goto err;
209 }
210
211 /*
212 * Switch to Parking src
213 * 1. Need to switch out all ACCs sharing the same apupll
214 */
215 switch (domain) {
216 case V_MDLA0:
217 case V_MDLA1:
218 acc_set0 = APU_ACC_CONFG_SET4;
219 acc_set1 = APU_ACC_CONFG_SET5;
220 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
221 V_MDLA0);
222 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
223 V_MDLA1);
224 break;
225 case V_VPU0:
226 case V_VPU1:
227 acc_set0 = APU_ACC_CONFG_SET1;
228 acc_set1 = APU_ACC_CONFG_SET2;
229 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
230 V_VPU0);
231 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
232 V_VPU1);
233 break;
234 case V_APU_CONN:
235 acc_set0 = APU_ACC_CONFG_SET0;
236 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
237 V_APU_CONN);
238 break;
239 case V_TOP_IOMMU:
240 acc_set0 = APU_ACC_CONFG_SET7;
241 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
242 V_TOP_IOMMU);
243 break;
244 default:
245 ERROR("[APUPWR] %s %d invalid domain (%d)\n",
246 __func__, __LINE__, domain);
247 ret = -EIO;
248 goto err;
249 }
250
251 anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq);
252
253 if (div2) {
254 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0);
255 if (acc_set1) {
256 apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1);
257 }
258 }
259
260 /*
261 * Switch back to APUPLL
262 * Only switch back to APUPLL while CG_APU on
263 * And clksrc is not APUPLL
264 */
265 switch (domain) {
266 case V_VPU0:
267 case V_VPU1:
268 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
269 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
270 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
271 V_VPU0);
272 }
273 if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
274 !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
275 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
276 V_VPU1);
277 }
278 break;
279 case V_MDLA0:
280 case V_MDLA1:
281 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
282 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
283 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
284 V_MDLA0);
285 }
286 if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
287 !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
288 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
289 V_MDLA1);
290 }
291 break;
292 case V_APU_CONN:
293 case V_TOP_IOMMU:
294 if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
295 !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
296 ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
297 domain);
298 }
299 break;
300 default:
301 ERROR("[APUPWR] %s %d invalid domain (%d)\n",
302 __func__, __LINE__, domain);
303 ret = -EIO;
304 break;
305 }
306 INFO("[%s][%d] set domain %d to freq %d\n",
307 __func__, __LINE__, domain, (div2) ? (freq * 2) : freq);
308
309 err:
310 return ret;
311 }
312
apupwr_smc_bulk_pll(bool enable)313 int32_t apupwr_smc_bulk_pll(bool enable)
314 {
315 int32_t ret = 0;
316 int32_t pll_idx;
317
318 if (enable) {
319 for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) {
320 ret = apu_pll_enable(pll_idx, enable, false);
321 if (ret != 0) {
322 goto err;
323 }
324 }
325 } else {
326 for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) {
327 ret = apu_pll_enable(pll_idx, enable, false);
328 if (ret != 0) {
329 goto err;
330 }
331 }
332 }
333
334 err:
335 return ret;
336 }
337
apupwr_smc_bus_prot_cg_on(void)338 void apupwr_smc_bus_prot_cg_on(void)
339 {
340 apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0);
341 }
342