xref: /aosp_15_r20/external/arm-trusted-firmware/plat/hisilicon/hikey/hisi_dvfs.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <string.h>
9*54fd6939SJiyong Park 
10*54fd6939SJiyong Park #include <platform_def.h>
11*54fd6939SJiyong Park 
12*54fd6939SJiyong Park #include <arch_helpers.h>
13*54fd6939SJiyong Park #include <common/bl_common.h>
14*54fd6939SJiyong Park #include <common/debug.h>
15*54fd6939SJiyong Park #include <drivers/console.h>
16*54fd6939SJiyong Park #include <lib/mmio.h>
17*54fd6939SJiyong Park #include <plat/common/platform.h>
18*54fd6939SJiyong Park 
19*54fd6939SJiyong Park #include <hi6220.h>
20*54fd6939SJiyong Park #include <hi6553.h>
21*54fd6939SJiyong Park #include <hisi_sram_map.h>
22*54fd6939SJiyong Park 
23*54fd6939SJiyong Park #define ACPU_FREQ_MAX_NUM		5
24*54fd6939SJiyong Park #define	ACPU_OPP_NUM			7
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park #define ACPU_VALID_VOLTAGE_MAGIC	(0x5A5AC5C5)
27*54fd6939SJiyong Park 
28*54fd6939SJiyong Park #define ACPU_WAIT_TIMEOUT		(200)
29*54fd6939SJiyong Park #define ACPU_WAIT_FOR_WFI_TIMOUT	(2000)
30*54fd6939SJiyong Park #define ACPU_DFS_STATE_CNT		(0x10000)
31*54fd6939SJiyong Park 
32*54fd6939SJiyong Park struct acpu_dvfs_sram_stru {
33*54fd6939SJiyong Park 	unsigned int magic;
34*54fd6939SJiyong Park 	unsigned int support_freq_num;
35*54fd6939SJiyong Park 	unsigned int support_freq_max;
36*54fd6939SJiyong Park 	unsigned int start_prof;
37*54fd6939SJiyong Park 	unsigned int vol[ACPU_OPP_NUM];
38*54fd6939SJiyong Park };
39*54fd6939SJiyong Park 
40*54fd6939SJiyong Park struct acpu_volt_cal_para {
41*54fd6939SJiyong Park 	unsigned int freq;
42*54fd6939SJiyong Park 	unsigned int ul_vol;
43*54fd6939SJiyong Park 	unsigned int dl_vol;
44*54fd6939SJiyong Park 	unsigned int core_ref_hpm;
45*54fd6939SJiyong Park };
46*54fd6939SJiyong Park 
47*54fd6939SJiyong Park struct ddr_volt_cal_para {
48*54fd6939SJiyong Park 	unsigned int freq;
49*54fd6939SJiyong Park 	unsigned int ul_vol;
50*54fd6939SJiyong Park 	unsigned int dl_vol;
51*54fd6939SJiyong Park 	unsigned int ddr_ref_hpm;
52*54fd6939SJiyong Park };
53*54fd6939SJiyong Park 
54*54fd6939SJiyong Park struct acpu_dvfs_opp_para {
55*54fd6939SJiyong Park 	unsigned int freq;
56*54fd6939SJiyong Park 	unsigned int acpu_clk_profile0;
57*54fd6939SJiyong Park 	unsigned int acpu_clk_profile1;
58*54fd6939SJiyong Park 	unsigned int acpu_vol_profile;
59*54fd6939SJiyong Park 	unsigned int acpu_pll_freq;
60*54fd6939SJiyong Park 	unsigned int acpu_pll_frac;
61*54fd6939SJiyong Park };
62*54fd6939SJiyong Park 
63*54fd6939SJiyong Park unsigned int efuse_acpu_freq[] = {
64*54fd6939SJiyong Park 	1200000, 1250000, 1300000, 1350000,
65*54fd6939SJiyong Park 	1400000, 1450000, 1500000, 1550000,
66*54fd6939SJiyong Park 	1600000, 1650000, 1700000, 1750000,
67*54fd6939SJiyong Park 	1800000, 1850000, 1900000, 1950000,
68*54fd6939SJiyong Park };
69*54fd6939SJiyong Park 
70*54fd6939SJiyong Park struct acpu_dvfs_opp_para hi6220_acpu_profile[] = {
71*54fd6939SJiyong Park 	{ 208000,  0x61E5, 0x022, 0x3A, 0x5220102B, 0x05555555 },
72*54fd6939SJiyong Park 	{ 432000,  0x10A6, 0x121, 0x3A, 0x5120102D, 0x10000005 },
73*54fd6939SJiyong Park 	{ 729000,  0x2283, 0x100, 0x4A, 0x51101026, 0x10000005 },
74*54fd6939SJiyong Park 	{ 960000,  0x1211, 0x100, 0x5B, 0x51101032, 0x10000005 },
75*54fd6939SJiyong Park 	{ 1200000, 0x1211, 0x100, 0x6B, 0x5110207D, 0x10000005 },
76*54fd6939SJiyong Park 	{ 1400000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
77*54fd6939SJiyong Park 	{ 1500000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
78*54fd6939SJiyong Park };
79*54fd6939SJiyong Park 
80*54fd6939SJiyong Park struct acpu_dvfs_opp_para *acpu_dvfs_profile = hi6220_acpu_profile;
81*54fd6939SJiyong Park struct acpu_dvfs_sram_stru *acpu_dvfs_sram_buf =
82*54fd6939SJiyong Park 	(struct acpu_dvfs_sram_stru *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
83*54fd6939SJiyong Park 
write_reg_mask(uintptr_t addr,uint32_t val,uint32_t mask)84*54fd6939SJiyong Park static inline void write_reg_mask(uintptr_t addr,
85*54fd6939SJiyong Park 				  uint32_t val, uint32_t mask)
86*54fd6939SJiyong Park {
87*54fd6939SJiyong Park 	uint32_t reg;
88*54fd6939SJiyong Park 
89*54fd6939SJiyong Park 	reg = mmio_read_32(addr);
90*54fd6939SJiyong Park 	reg = (reg & ~(mask)) | val;
91*54fd6939SJiyong Park 	mmio_write_32(addr, reg);
92*54fd6939SJiyong Park }
93*54fd6939SJiyong Park 
read_reg_mask(uintptr_t addr,uint32_t mask,uint32_t offset)94*54fd6939SJiyong Park static inline uint32_t read_reg_mask(uintptr_t addr,
95*54fd6939SJiyong Park 				     uint32_t mask, uint32_t offset)
96*54fd6939SJiyong Park {
97*54fd6939SJiyong Park 	uint32_t reg;
98*54fd6939SJiyong Park 
99*54fd6939SJiyong Park 	reg = mmio_read_32(addr);
100*54fd6939SJiyong Park 	reg &= (mask << offset);
101*54fd6939SJiyong Park 	return (reg >> offset);
102*54fd6939SJiyong Park }
103*54fd6939SJiyong Park 
acpu_dvfs_syspll_cfg(unsigned int prof_id)104*54fd6939SJiyong Park static int acpu_dvfs_syspll_cfg(unsigned int prof_id)
105*54fd6939SJiyong Park {
106*54fd6939SJiyong Park 	uint32_t reg0 = 0;
107*54fd6939SJiyong Park 	uint32_t count = 0;
108*54fd6939SJiyong Park 	uint32_t clk_div_status = 0;
109*54fd6939SJiyong Park 
110*54fd6939SJiyong Park 	/*
111*54fd6939SJiyong Park 	 * step 1:
112*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
113*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
114*54fd6939SJiyong Park 	 */
115*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x3 << 12, 0x3 << 12);
116*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 4,  0x1 << 4);
117*54fd6939SJiyong Park 
118*54fd6939SJiyong Park 	/*
119*54fd6939SJiyong Park 	 * step 2:
120*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_div_cfg:
121*54fd6939SJiyong Park 	 *     208MHz, set to 0x5;
122*54fd6939SJiyong Park 	 *     500MHz, set to 0x2;
123*54fd6939SJiyong Park 	 *     other opps set to 0x1
124*54fd6939SJiyong Park 	 */
125*54fd6939SJiyong Park 	if (prof_id == 0)
126*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x5 << 0, 0x7 << 0);
127*54fd6939SJiyong Park 	else if (prof_id == 1)
128*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x2 << 0, 0x7 << 0);
129*54fd6939SJiyong Park 	else
130*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 0, 0x7 << 0);
131*54fd6939SJiyong Park 
132*54fd6939SJiyong Park 	/*
133*54fd6939SJiyong Park 	 * step 3:
134*54fd6939SJiyong Park 	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x3;
135*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0
136*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0
137*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1
138*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
139*54fd6939SJiyong Park 	 */
140*54fd6939SJiyong Park 	clk_div_status = 0x3;
141*54fd6939SJiyong Park 	do {
142*54fd6939SJiyong Park 		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, 20);
143*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
144*54fd6939SJiyong Park 			ERROR("%s: clk div status timeout!\n", __func__);
145*54fd6939SJiyong Park 			return -1;
146*54fd6939SJiyong Park 		}
147*54fd6939SJiyong Park 	} while (clk_div_status != reg0);
148*54fd6939SJiyong Park 
149*54fd6939SJiyong Park 	write_reg_mask(ACPU_SC_VD_CTRL, 0x0, (0x1 << 0) | (0x1 << 11));
150*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUCLKDIV, 0x1 << 8, 0x3 << 8);
151*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x1 << 0, 0x1 << 0);
152*54fd6939SJiyong Park 
153*54fd6939SJiyong Park 	return 0;
154*54fd6939SJiyong Park }
155*54fd6939SJiyong Park 
acpu_dvfs_clk_div_cfg(unsigned int prof_id,unsigned int * cpuext_cfg,unsigned int * acpu_ddr_cfg)156*54fd6939SJiyong Park static void acpu_dvfs_clk_div_cfg(unsigned int prof_id,
157*54fd6939SJiyong Park 				  unsigned int *cpuext_cfg,
158*54fd6939SJiyong Park 				  unsigned int *acpu_ddr_cfg)
159*54fd6939SJiyong Park {
160*54fd6939SJiyong Park 	if (prof_id == 0) {
161*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUCLKDIV,
162*54fd6939SJiyong Park 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
163*54fd6939SJiyong Park 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
164*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
165*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
166*54fd6939SJiyong Park 		*cpuext_cfg = 0x1;
167*54fd6939SJiyong Park 		*acpu_ddr_cfg = 0x1;
168*54fd6939SJiyong Park 	} else if (prof_id == 1) {
169*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUCLKDIV,
170*54fd6939SJiyong Park 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
171*54fd6939SJiyong Park 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
172*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
173*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
174*54fd6939SJiyong Park 		*cpuext_cfg = 0x1;
175*54fd6939SJiyong Park 		*acpu_ddr_cfg = 0x1;
176*54fd6939SJiyong Park 	} else {
177*54fd6939SJiyong Park 		/* ddr has not been inited */
178*54fd6939SJiyong Park 		write_reg_mask(PMCTRL_ACPUCLKDIV,
179*54fd6939SJiyong Park 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
180*54fd6939SJiyong Park 			(0x0 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
181*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
182*54fd6939SJiyong Park 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
183*54fd6939SJiyong Park 		*cpuext_cfg = 0x1;
184*54fd6939SJiyong Park 		*acpu_ddr_cfg = 0x0;
185*54fd6939SJiyong Park 	}
186*54fd6939SJiyong Park }
187*54fd6939SJiyong Park 
acpu_dvfs_freq_ascend(unsigned int cur_prof,unsigned int tar_prof)188*54fd6939SJiyong Park static int acpu_dvfs_freq_ascend(unsigned int cur_prof, unsigned int tar_prof)
189*54fd6939SJiyong Park {
190*54fd6939SJiyong Park 	unsigned int reg0 = 0;
191*54fd6939SJiyong Park 	unsigned int reg1 = 0;
192*54fd6939SJiyong Park 	unsigned int reg2 = 0;
193*54fd6939SJiyong Park 	unsigned int count = 0;
194*54fd6939SJiyong Park 	unsigned int cpuext_cfg_val = 0;
195*54fd6939SJiyong Park 	unsigned int acpu_ddr_cfg_val = 0;
196*54fd6939SJiyong Park 	int ret = 0;
197*54fd6939SJiyong Park 
198*54fd6939SJiyong Park 	/*
199*54fd6939SJiyong Park 	 * step 1:
200*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
201*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
202*54fd6939SJiyong Park 	 *
203*54fd6939SJiyong Park 	 * step 2:
204*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x5 (208MHz)
205*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x2 (500MHz)
206*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x1 (Other OPPs)
207*54fd6939SJiyong Park 	 *
208*54fd6939SJiyong Park 	 * step 3:
209*54fd6939SJiyong Park 	 *  - ACPU_SC_CPU_STAT.clk_div_status_vd = 0x3;
210*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x0;
211*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x0;
212*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1;
213*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
214*54fd6939SJiyong Park 	 */
215*54fd6939SJiyong Park 	ret = acpu_dvfs_syspll_cfg(cur_prof);
216*54fd6939SJiyong Park 	if (ret)
217*54fd6939SJiyong Park 		return -1;
218*54fd6939SJiyong Park 
219*54fd6939SJiyong Park 	/*
220*54fd6939SJiyong Park 	 * step 4:
221*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
222*54fd6939SJiyong Park 	 */
223*54fd6939SJiyong Park 	count = 0;
224*54fd6939SJiyong Park 	do {
225*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
226*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START);
227*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
228*54fd6939SJiyong Park 			ERROR("%s: syspll sw status timeout\n", __func__);
229*54fd6939SJiyong Park 			return -1;
230*54fd6939SJiyong Park 		}
231*54fd6939SJiyong Park 	} while (reg0 != 0x1);
232*54fd6939SJiyong Park 
233*54fd6939SJiyong Park 	/* Enable VD functionality if > 800MHz */
234*54fd6939SJiyong Park 	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
235*54fd6939SJiyong Park 
236*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
237*54fd6939SJiyong Park 			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
238*54fd6939SJiyong Park 
239*54fd6939SJiyong Park 		/*
240*54fd6939SJiyong Park 		 * step 5:
241*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
242*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
243*54fd6939SJiyong Park 		 */
244*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
245*54fd6939SJiyong Park 			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
246*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
247*54fd6939SJiyong Park 			ACPU_SC_VD_MASK_PATTERN_VAL,
248*54fd6939SJiyong Park 			ACPU_SC_VD_MASK_PATTERN_MASK);
249*54fd6939SJiyong Park 
250*54fd6939SJiyong Park 		/*
251*54fd6939SJiyong Park 		 * step 6:
252*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
253*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
254*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
255*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
256*54fd6939SJiyong Park 		 */
257*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
258*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
259*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
260*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
261*54fd6939SJiyong Park 
262*54fd6939SJiyong Park 		/*
263*54fd6939SJiyong Park 		 * step 7:
264*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
265*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
266*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
267*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
268*54fd6939SJiyong Park 		 *
269*54fd6939SJiyong Park 		 * step 8:
270*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
271*54fd6939SJiyong Park 		 */
272*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_CTRL,
273*54fd6939SJiyong Park 			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
274*54fd6939SJiyong Park 			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
275*54fd6939SJiyong Park 	}
276*54fd6939SJiyong Park 
277*54fd6939SJiyong Park 	/* step 9: ACPUPLLCTRL.acpupll_en_cfg = 0x0 */
278*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0,
279*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
280*54fd6939SJiyong Park 
281*54fd6939SJiyong Park 	/* step 10: set PMCTRL_ACPUPLLFREQ and PMCTRL_ACPUPLLFRAC */
282*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPLLFREQ,
283*54fd6939SJiyong Park 		acpu_dvfs_profile[tar_prof].acpu_pll_freq);
284*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPLLFRAC,
285*54fd6939SJiyong Park 		acpu_dvfs_profile[tar_prof].acpu_pll_frac);
286*54fd6939SJiyong Park 
287*54fd6939SJiyong Park 	/*
288*54fd6939SJiyong Park 	 * step 11:
289*54fd6939SJiyong Park 	 *  - wait for 1us;
290*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
291*54fd6939SJiyong Park 	 */
292*54fd6939SJiyong Park 	count = 0;
293*54fd6939SJiyong Park 	while (count < ACPU_WAIT_TIMEOUT)
294*54fd6939SJiyong Park 		count++;
295*54fd6939SJiyong Park 
296*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLCTRL,
297*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
298*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
299*54fd6939SJiyong Park 
300*54fd6939SJiyong Park 	/* step 12: PMCTRL_ACPUVOLPMUADDR = 0x100da */
301*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
302*54fd6939SJiyong Park 
303*54fd6939SJiyong Park 	/*
304*54fd6939SJiyong Park 	 * step 13:
305*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (208MHz);
306*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (500MHz);
307*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x20 (798MHz);
308*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1300MHz);
309*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1500MHz);
310*54fd6939SJiyong Park 	 */
311*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUDESTVOL,
312*54fd6939SJiyong Park 		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
313*54fd6939SJiyong Park 		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
314*54fd6939SJiyong Park 
315*54fd6939SJiyong Park 	/*
316*54fd6939SJiyong Park 	 * step 14:
317*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
318*54fd6939SJiyong Park 	 *  - Polling ACPUVOLTIMEOUT.acpu_vol_timeout == 0x1
319*54fd6939SJiyong Park 	 *  - Config PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg
320*54fd6939SJiyong Park 	 *  - Config ACPUCLKDIV.cpuext_clk_div_cfg;
321*54fd6939SJiyong Park 	 */
322*54fd6939SJiyong Park 	count = 0;
323*54fd6939SJiyong Park 	do {
324*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
325*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
326*54fd6939SJiyong Park 		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
327*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
328*54fd6939SJiyong Park 		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
329*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
330*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
331*54fd6939SJiyong Park 			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
332*54fd6939SJiyong Park 			return -1;
333*54fd6939SJiyong Park 		}
334*54fd6939SJiyong Park 	} while ((reg0 != reg1) || (reg2 != 0x1));
335*54fd6939SJiyong Park 
336*54fd6939SJiyong Park 	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
337*54fd6939SJiyong Park 
338*54fd6939SJiyong Park 	/*
339*54fd6939SJiyong Park 	 * step 15:
340*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
341*54fd6939SJiyong Park 	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
342*54fd6939SJiyong Park 	 *  - ACPUPLLCTRL.acpupll_timeout = 0x1;
343*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
344*54fd6939SJiyong Park 	 */
345*54fd6939SJiyong Park 	count = 0;
346*54fd6939SJiyong Park 	do {
347*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
348*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
349*54fd6939SJiyong Park 		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
350*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
351*54fd6939SJiyong Park 		reg2 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
352*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
353*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
354*54fd6939SJiyong Park 			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
355*54fd6939SJiyong Park 			return -1;
356*54fd6939SJiyong Park 		}
357*54fd6939SJiyong Park 	} while ((reg1 != cpuext_cfg_val) ||
358*54fd6939SJiyong Park 		(reg0 != acpu_ddr_cfg_val) ||
359*54fd6939SJiyong Park 		(reg2 != 0x1));
360*54fd6939SJiyong Park 
361*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
362*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
363*54fd6939SJiyong Park 
364*54fd6939SJiyong Park 	/*
365*54fd6939SJiyong Park 	 * step 16:
366*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
367*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
368*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
369*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
370*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
371*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
372*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
373*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
374*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
375*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
376*54fd6939SJiyong Park 	 */
377*54fd6939SJiyong Park 	count = 0;
378*54fd6939SJiyong Park 	do {
379*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
380*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
381*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
382*54fd6939SJiyong Park 			ERROR("%s: acpu pll sw status timeout.\n", __func__);
383*54fd6939SJiyong Park 			return -1;
384*54fd6939SJiyong Park 		}
385*54fd6939SJiyong Park 	} while (reg0 != 0x1);
386*54fd6939SJiyong Park 
387*54fd6939SJiyong Park 	if (acpu_dvfs_profile[tar_prof].freq > 800000)
388*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_CTRL,
389*54fd6939SJiyong Park 			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
390*54fd6939SJiyong Park 
391*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
392*54fd6939SJiyong Park 		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
393*54fd6939SJiyong Park 		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
394*54fd6939SJiyong Park 
395*54fd6939SJiyong Park 	return 0;
396*54fd6939SJiyong Park }
397*54fd6939SJiyong Park 
acpu_dvfs_freq_descend(unsigned int cur_prof,unsigned int tar_prof)398*54fd6939SJiyong Park static int acpu_dvfs_freq_descend(unsigned int cur_prof, unsigned int tar_prof)
399*54fd6939SJiyong Park {
400*54fd6939SJiyong Park 	unsigned int reg0 = 0;
401*54fd6939SJiyong Park 	unsigned int reg1 = 0;
402*54fd6939SJiyong Park 	unsigned int reg2 = 0;
403*54fd6939SJiyong Park 	unsigned int count = 0;
404*54fd6939SJiyong Park 	unsigned int cpuext_cfg_val = 0;
405*54fd6939SJiyong Park 	unsigned int acpu_ddr_cfg_val = 0;
406*54fd6939SJiyong Park 	int ret = 0;
407*54fd6939SJiyong Park 
408*54fd6939SJiyong Park 	ret = acpu_dvfs_syspll_cfg(tar_prof);
409*54fd6939SJiyong Park 	if (ret)
410*54fd6939SJiyong Park 		return -1;
411*54fd6939SJiyong Park 
412*54fd6939SJiyong Park 	/*
413*54fd6939SJiyong Park 	 * step 4:
414*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
415*54fd6939SJiyong Park 	 */
416*54fd6939SJiyong Park 	count = 0;
417*54fd6939SJiyong Park 	do {
418*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, 2);
419*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
420*54fd6939SJiyong Park 			ERROR("%s: syspll sw status timeout.\n", __func__);
421*54fd6939SJiyong Park 			return -1;
422*54fd6939SJiyong Park 		}
423*54fd6939SJiyong Park 	} while (reg0 != 0x1);
424*54fd6939SJiyong Park 
425*54fd6939SJiyong Park 	/*
426*54fd6939SJiyong Park 	 * Step 5:
427*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x0
428*54fd6939SJiyong Park 	 */
429*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << 0);
430*54fd6939SJiyong Park 
431*54fd6939SJiyong Park 	/*
432*54fd6939SJiyong Park 	 * step 6
433*54fd6939SJiyong Park 	 *  - Config PMCTRL_ACPUPLLFREQ and ACPUPLLFRAC
434*54fd6939SJiyong Park 	 */
435*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq);
436*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac);
437*54fd6939SJiyong Park 
438*54fd6939SJiyong Park 	/*
439*54fd6939SJiyong Park 	 * step 7:
440*54fd6939SJiyong Park 	 *  - Wait 1us;
441*54fd6939SJiyong Park 	 *  - Config PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
442*54fd6939SJiyong Park 	 */
443*54fd6939SJiyong Park 	count = 0;
444*54fd6939SJiyong Park 	while (count < ACPU_WAIT_TIMEOUT)
445*54fd6939SJiyong Park 		count++;
446*54fd6939SJiyong Park 
447*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLCTRL,
448*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
449*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
450*54fd6939SJiyong Park 
451*54fd6939SJiyong Park 	/* Enable VD functionality if > 800MHz */
452*54fd6939SJiyong Park 	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
453*54fd6939SJiyong Park 
454*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
455*54fd6939SJiyong Park 			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
456*54fd6939SJiyong Park 
457*54fd6939SJiyong Park 		/*
458*54fd6939SJiyong Park 		 * step 9:
459*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
460*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
461*54fd6939SJiyong Park 		 */
462*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
463*54fd6939SJiyong Park 			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
464*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
465*54fd6939SJiyong Park 			ACPU_SC_VD_MASK_PATTERN_VAL,
466*54fd6939SJiyong Park 			ACPU_SC_VD_MASK_PATTERN_MASK);
467*54fd6939SJiyong Park 
468*54fd6939SJiyong Park 		/*
469*54fd6939SJiyong Park 		 * step 10:
470*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
471*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
472*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
473*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
474*54fd6939SJiyong Park 		 */
475*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
476*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
477*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
478*54fd6939SJiyong Park 		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
479*54fd6939SJiyong Park 
480*54fd6939SJiyong Park 		/*
481*54fd6939SJiyong Park 		 * step 11:
482*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
483*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
484*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
485*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
486*54fd6939SJiyong Park 		 *
487*54fd6939SJiyong Park 		 * step 12:
488*54fd6939SJiyong Park 		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
489*54fd6939SJiyong Park 		 */
490*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_CTRL,
491*54fd6939SJiyong Park 			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
492*54fd6939SJiyong Park 			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
493*54fd6939SJiyong Park 	}
494*54fd6939SJiyong Park 
495*54fd6939SJiyong Park 	/*
496*54fd6939SJiyong Park 	 * step 13:
497*54fd6939SJiyong Park 	 *  - Pollig PMCTRL_ACPUPLLCTRL.acpupll_timeout == 0x1;
498*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
499*54fd6939SJiyong Park 	 */
500*54fd6939SJiyong Park 	count = 0;
501*54fd6939SJiyong Park 	do {
502*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
503*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
504*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
505*54fd6939SJiyong Park 			ERROR("%s: acpupll timeout.\n", __func__);
506*54fd6939SJiyong Park 			return -1;
507*54fd6939SJiyong Park 		}
508*54fd6939SJiyong Park 	} while (reg0 != 0x1);
509*54fd6939SJiyong Park 
510*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
511*54fd6939SJiyong Park 		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
512*54fd6939SJiyong Park 
513*54fd6939SJiyong Park 	/*
514*54fd6939SJiyong Park 	 * step 14:
515*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
516*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
517*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
518*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
519*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
520*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
521*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
522*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
523*54fd6939SJiyong Park 	 */
524*54fd6939SJiyong Park 	count = 0;
525*54fd6939SJiyong Park 	do {
526*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
527*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
528*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
529*54fd6939SJiyong Park 			ERROR("%s: acpupll sw status timeout.\n", __func__);
530*54fd6939SJiyong Park 			return -1;
531*54fd6939SJiyong Park 		}
532*54fd6939SJiyong Park 	} while (reg0 != 0x1);
533*54fd6939SJiyong Park 
534*54fd6939SJiyong Park 	if (acpu_dvfs_profile[tar_prof].freq > 800000)
535*54fd6939SJiyong Park 		write_reg_mask(ACPU_SC_VD_CTRL,
536*54fd6939SJiyong Park 			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
537*54fd6939SJiyong Park 
538*54fd6939SJiyong Park 	/*
539*54fd6939SJiyong Park 	 * step 15:
540*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
541*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
542*54fd6939SJiyong Park 	 */
543*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
544*54fd6939SJiyong Park 		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
545*54fd6939SJiyong Park 		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
546*54fd6939SJiyong Park 
547*54fd6939SJiyong Park 	/*
548*54fd6939SJiyong Park 	 * step 16:
549*54fd6939SJiyong Park 	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x0;
550*54fd6939SJiyong Park 	 */
551*54fd6939SJiyong Park 	count = 0;
552*54fd6939SJiyong Park 	do {
553*54fd6939SJiyong Park 		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3,
554*54fd6939SJiyong Park 			ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT);
555*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
556*54fd6939SJiyong Park 			ERROR("%s: clk div status timeout.\n", __func__);
557*54fd6939SJiyong Park 			return -1;
558*54fd6939SJiyong Park 		}
559*54fd6939SJiyong Park 	} while (reg0 != 0x0);
560*54fd6939SJiyong Park 
561*54fd6939SJiyong Park 	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
562*54fd6939SJiyong Park 
563*54fd6939SJiyong Park 	/*
564*54fd6939SJiyong Park 	 * step 17:
565*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
566*54fd6939SJiyong Park 	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
567*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUVOLPMUADDR = 0x1006C;
568*54fd6939SJiyong Park 	 */
569*54fd6939SJiyong Park 	count = 0;
570*54fd6939SJiyong Park 	do {
571*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
572*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
573*54fd6939SJiyong Park 		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
574*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
575*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
576*54fd6939SJiyong Park 			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
577*54fd6939SJiyong Park 			return -1;
578*54fd6939SJiyong Park 		}
579*54fd6939SJiyong Park 	} while ((reg0 != cpuext_cfg_val) || (reg1 != acpu_ddr_cfg_val));
580*54fd6939SJiyong Park 
581*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
582*54fd6939SJiyong Park 
583*54fd6939SJiyong Park 	/*
584*54fd6939SJiyong Park 	 * step 16:
585*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
586*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
587*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
588*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
589*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
590*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
591*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
592*54fd6939SJiyong Park 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
593*54fd6939SJiyong Park 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
594*54fd6939SJiyong Park 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
595*54fd6939SJiyong Park 	 */
596*54fd6939SJiyong Park 	write_reg_mask(PMCTRL_ACPUDESTVOL,
597*54fd6939SJiyong Park 		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
598*54fd6939SJiyong Park 		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
599*54fd6939SJiyong Park 
600*54fd6939SJiyong Park 	/*
601*54fd6939SJiyong Park 	 * step 19:
602*54fd6939SJiyong Park 	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
603*54fd6939SJiyong Park 	 *  - ACPUVOLTIMEOUT.acpu_vol_timeout = 0x1;
604*54fd6939SJiyong Park 	 */
605*54fd6939SJiyong Park 	count = 0;
606*54fd6939SJiyong Park 	do {
607*54fd6939SJiyong Park 		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
608*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
609*54fd6939SJiyong Park 		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
610*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
611*54fd6939SJiyong Park 		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
612*54fd6939SJiyong Park 			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
613*54fd6939SJiyong Park 		if ((count++) > ACPU_DFS_STATE_CNT) {
614*54fd6939SJiyong Park 			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
615*54fd6939SJiyong Park 			return -1;
616*54fd6939SJiyong Park 		}
617*54fd6939SJiyong Park 	} while ((reg0 != reg1) || (reg2 != 0x1));
618*54fd6939SJiyong Park 
619*54fd6939SJiyong Park 	return 0;
620*54fd6939SJiyong Park }
621*54fd6939SJiyong Park 
acpu_dvfs_target(unsigned int curr_prof,unsigned int target_prof)622*54fd6939SJiyong Park int acpu_dvfs_target(unsigned int curr_prof, unsigned int target_prof)
623*54fd6939SJiyong Park {
624*54fd6939SJiyong Park 	int ret = 0;
625*54fd6939SJiyong Park 
626*54fd6939SJiyong Park 	if (curr_prof == target_prof) {
627*54fd6939SJiyong Park 		INFO("%s: target_prof is equal curr_prof: is %d!\n",
628*54fd6939SJiyong Park 			__func__, curr_prof);
629*54fd6939SJiyong Park 		return 0;
630*54fd6939SJiyong Park 	}
631*54fd6939SJiyong Park 
632*54fd6939SJiyong Park 	if ((curr_prof >= ACPU_FREQ_MAX_NUM) ||
633*54fd6939SJiyong Park 	    (target_prof >= ACPU_FREQ_MAX_NUM)) {
634*54fd6939SJiyong Park 		INFO("%s: invalid parameter %d %d\n",
635*54fd6939SJiyong Park 			__func__, curr_prof, target_prof);
636*54fd6939SJiyong Park 		return -1;
637*54fd6939SJiyong Park 	}
638*54fd6939SJiyong Park 
639*54fd6939SJiyong Park 	if (target_prof > acpu_dvfs_sram_buf->support_freq_num)
640*54fd6939SJiyong Park 		target_prof = acpu_dvfs_sram_buf->support_freq_num;
641*54fd6939SJiyong Park 
642*54fd6939SJiyong Park 	if (target_prof < curr_prof)
643*54fd6939SJiyong Park 		ret = acpu_dvfs_freq_descend(curr_prof, target_prof);
644*54fd6939SJiyong Park 	else if (target_prof > curr_prof)
645*54fd6939SJiyong Park 		ret = acpu_dvfs_freq_ascend(curr_prof, target_prof);
646*54fd6939SJiyong Park 
647*54fd6939SJiyong Park 	if (ret) {
648*54fd6939SJiyong Park 		ERROR("%s: acpu_dvfs_target failed!\n", __func__);
649*54fd6939SJiyong Park 		return -1;
650*54fd6939SJiyong Park 	}
651*54fd6939SJiyong Park 
652*54fd6939SJiyong Park 	/* Complete acpu dvfs setting and set magic number */
653*54fd6939SJiyong Park 	acpu_dvfs_sram_buf->start_prof = target_prof;
654*54fd6939SJiyong Park 	acpu_dvfs_sram_buf->magic = ACPU_VALID_VOLTAGE_MAGIC;
655*54fd6939SJiyong Park 
656*54fd6939SJiyong Park 	mmio_write_32(DDR_DFS_FREQ_ADDR, 800000);
657*54fd6939SJiyong Park 	return 0;
658*54fd6939SJiyong Park }
659*54fd6939SJiyong Park 
acpu_dvfs_set_freq(void)660*54fd6939SJiyong Park static int acpu_dvfs_set_freq(void)
661*54fd6939SJiyong Park {
662*54fd6939SJiyong Park 	unsigned int i;
663*54fd6939SJiyong Park 	unsigned int curr_prof;
664*54fd6939SJiyong Park 	unsigned int target_prof;
665*54fd6939SJiyong Park 	unsigned int max_freq = 0;
666*54fd6939SJiyong Park 
667*54fd6939SJiyong Park 	max_freq = acpu_dvfs_sram_buf->support_freq_max;
668*54fd6939SJiyong Park 
669*54fd6939SJiyong Park 	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) {
670*54fd6939SJiyong Park 
671*54fd6939SJiyong Park 		if (max_freq == hi6220_acpu_profile[i].freq) {
672*54fd6939SJiyong Park 			target_prof = i;
673*54fd6939SJiyong Park 			break;
674*54fd6939SJiyong Park 		}
675*54fd6939SJiyong Park 	}
676*54fd6939SJiyong Park 
677*54fd6939SJiyong Park 	if (i == acpu_dvfs_sram_buf->support_freq_num) {
678*54fd6939SJiyong Park 		ERROR("%s: cannot found max freq profile\n", __func__);
679*54fd6939SJiyong Park 		return -1;
680*54fd6939SJiyong Park 	}
681*54fd6939SJiyong Park 
682*54fd6939SJiyong Park 	curr_prof = 0;
683*54fd6939SJiyong Park 	target_prof = i;
684*54fd6939SJiyong Park 
685*54fd6939SJiyong Park 	/* if max freq is 208MHz, do nothing */
686*54fd6939SJiyong Park 	if (curr_prof == target_prof)
687*54fd6939SJiyong Park 		return 0;
688*54fd6939SJiyong Park 
689*54fd6939SJiyong Park 	if (acpu_dvfs_target(curr_prof, target_prof)) {
690*54fd6939SJiyong Park 		ERROR("%s: set acpu freq failed!", __func__);
691*54fd6939SJiyong Park 		return -1;
692*54fd6939SJiyong Park 	}
693*54fd6939SJiyong Park 
694*54fd6939SJiyong Park 	INFO("%s: support freq num is %d\n",
695*54fd6939SJiyong Park 		__func__, acpu_dvfs_sram_buf->support_freq_num);
696*54fd6939SJiyong Park 	INFO("%s: start prof is 0x%x\n",
697*54fd6939SJiyong Park 		__func__,  acpu_dvfs_sram_buf->start_prof);
698*54fd6939SJiyong Park 	INFO("%s: magic is 0x%x\n",
699*54fd6939SJiyong Park 		__func__, acpu_dvfs_sram_buf->magic);
700*54fd6939SJiyong Park 	INFO("%s: voltage:\n", __func__);
701*54fd6939SJiyong Park 	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++)
702*54fd6939SJiyong Park 		INFO("  - %d: 0x%x\n", i, acpu_dvfs_sram_buf->vol[i]);
703*54fd6939SJiyong Park 
704*54fd6939SJiyong Park 	NOTICE("%s: set acpu freq success!", __func__);
705*54fd6939SJiyong Park 	return 0;
706*54fd6939SJiyong Park }
707*54fd6939SJiyong Park 
708*54fd6939SJiyong Park struct acpu_dvfs_volt_setting {
709*54fd6939SJiyong Park 	unsigned int magic;
710*54fd6939SJiyong Park 	unsigned int support_freq_num;
711*54fd6939SJiyong Park 	unsigned int support_freq_max;
712*54fd6939SJiyong Park 	unsigned int start_prof;
713*54fd6939SJiyong Park 	unsigned int vol[7];
714*54fd6939SJiyong Park 	unsigned int hmp_dly_threshold[7];
715*54fd6939SJiyong Park };
716*54fd6939SJiyong Park 
acpu_dvfs_volt_init(void)717*54fd6939SJiyong Park static void acpu_dvfs_volt_init(void)
718*54fd6939SJiyong Park {
719*54fd6939SJiyong Park 	struct acpu_dvfs_volt_setting *volt;
720*54fd6939SJiyong Park 
721*54fd6939SJiyong Park 	/*
722*54fd6939SJiyong Park 	 * - set default voltage;
723*54fd6939SJiyong Park 	 * - set pmu address;
724*54fd6939SJiyong Park 	 * - set voltage up and down step;
725*54fd6939SJiyong Park 	 * - set voltage stable time;
726*54fd6939SJiyong Park 	 */
727*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUDFTVOL, 0x4a);
728*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0xda);
729*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUVOLUPSTEP, 0x1);
730*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUVOLDNSTEP, 0x1);
731*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPMUVOLUPTIME, 0x60);
732*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUPMUVOLDNTIME, 0x60);
733*54fd6939SJiyong Park 	mmio_write_32(PMCTRL_ACPUCLKOFFCFG, 0x1000);
734*54fd6939SJiyong Park 
735*54fd6939SJiyong Park 	volt = (void *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
736*54fd6939SJiyong Park 	volt->magic = 0x5a5ac5c5;
737*54fd6939SJiyong Park 	volt->support_freq_num = 5;
738*54fd6939SJiyong Park 	volt->support_freq_max = 1200000;
739*54fd6939SJiyong Park 	volt->start_prof = 4;
740*54fd6939SJiyong Park 	volt->vol[0] = 0x49;
741*54fd6939SJiyong Park 	volt->vol[1] = 0x49;
742*54fd6939SJiyong Park 	volt->vol[2] = 0x50;
743*54fd6939SJiyong Park 	volt->vol[3] = 0x60;
744*54fd6939SJiyong Park 	volt->vol[4] = 0x78;
745*54fd6939SJiyong Park 	volt->vol[5] = 0x78;
746*54fd6939SJiyong Park 	volt->vol[6] = 0x78;
747*54fd6939SJiyong Park 
748*54fd6939SJiyong Park 	volt->hmp_dly_threshold[0] = 0x0;
749*54fd6939SJiyong Park 	volt->hmp_dly_threshold[1] = 0x0;
750*54fd6939SJiyong Park 	volt->hmp_dly_threshold[2] = 0x0;
751*54fd6939SJiyong Park 	volt->hmp_dly_threshold[3] = 0x0e8b0e45;
752*54fd6939SJiyong Park 	volt->hmp_dly_threshold[4] = 0x10691023;
753*54fd6939SJiyong Park 	volt->hmp_dly_threshold[5] = 0x10691023;
754*54fd6939SJiyong Park 	volt->hmp_dly_threshold[6] = 0x10691023;
755*54fd6939SJiyong Park 
756*54fd6939SJiyong Park 	INFO("%s: success!\n", __func__);
757*54fd6939SJiyong Park }
758*54fd6939SJiyong Park 
init_acpu_dvfs(void)759*54fd6939SJiyong Park void init_acpu_dvfs(void)
760*54fd6939SJiyong Park {
761*54fd6939SJiyong Park 	unsigned int i = 0;
762*54fd6939SJiyong Park 
763*54fd6939SJiyong Park 	INFO("%s: pmic version %d\n", __func__,
764*54fd6939SJiyong Park 	     mmio_read_8(HI6553_VERSION_REG));
765*54fd6939SJiyong Park 
766*54fd6939SJiyong Park 	/* init parameters */
767*54fd6939SJiyong Park 	mmio_write_32(ACPU_CHIP_MAX_FREQ, efuse_acpu_freq[8]);
768*54fd6939SJiyong Park 	INFO("%s: ACPU_CHIP_MAX_FREQ=0x%x.\n",
769*54fd6939SJiyong Park 		__func__, mmio_read_32(ACPU_CHIP_MAX_FREQ));
770*54fd6939SJiyong Park 
771*54fd6939SJiyong Park 	/* set maximum support frequency to 1.2GHz */
772*54fd6939SJiyong Park 	for (i = 0; i < ACPU_FREQ_MAX_NUM; i++)
773*54fd6939SJiyong Park 		acpu_dvfs_sram_buf->vol[i] = hi6220_acpu_profile[i].acpu_vol_profile;
774*54fd6939SJiyong Park 
775*54fd6939SJiyong Park 	acpu_dvfs_sram_buf->support_freq_num = ACPU_FREQ_MAX_NUM;
776*54fd6939SJiyong Park 	acpu_dvfs_sram_buf->support_freq_max = 1200000;
777*54fd6939SJiyong Park 
778*54fd6939SJiyong Park 	/* init acpu dvfs */
779*54fd6939SJiyong Park 	acpu_dvfs_volt_init();
780*54fd6939SJiyong Park 	acpu_dvfs_set_freq();
781*54fd6939SJiyong Park }
782