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