xref: /rk3399_ARM-atf/plat/hisilicon/hikey/hisi_dvfs.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
132e9fc1aSHaojian Zhuang /*
232e9fc1aSHaojian Zhuang  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
332e9fc1aSHaojian Zhuang  *
432e9fc1aSHaojian Zhuang  * SPDX-License-Identifier: BSD-3-Clause
532e9fc1aSHaojian Zhuang  */
632e9fc1aSHaojian Zhuang 
732e9fc1aSHaojian Zhuang #include <assert.h>
8*09d40e0eSAntonio Nino Diaz #include <string.h>
9*09d40e0eSAntonio Nino Diaz 
10*09d40e0eSAntonio Nino Diaz #include <platform_def.h>
11*09d40e0eSAntonio Nino Diaz 
12*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
13*09d40e0eSAntonio Nino Diaz #include <common/bl_common.h>
14*09d40e0eSAntonio Nino Diaz #include <common/debug.h>
15*09d40e0eSAntonio Nino Diaz #include <drivers/console.h>
16*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h>
17*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
18*09d40e0eSAntonio Nino Diaz 
1932e9fc1aSHaojian Zhuang #include <hi6220.h>
2032e9fc1aSHaojian Zhuang #include <hi6553.h>
2132e9fc1aSHaojian Zhuang #include <hisi_sram_map.h>
2232e9fc1aSHaojian Zhuang 
2332e9fc1aSHaojian Zhuang #define ACPU_FREQ_MAX_NUM		5
2432e9fc1aSHaojian Zhuang #define	ACPU_OPP_NUM			7
2532e9fc1aSHaojian Zhuang 
2632e9fc1aSHaojian Zhuang #define ACPU_VALID_VOLTAGE_MAGIC	(0x5A5AC5C5)
2732e9fc1aSHaojian Zhuang 
2832e9fc1aSHaojian Zhuang #define ACPU_WAIT_TIMEOUT		(200)
2932e9fc1aSHaojian Zhuang #define ACPU_WAIT_FOR_WFI_TIMOUT	(2000)
3032e9fc1aSHaojian Zhuang #define ACPU_DFS_STATE_CNT		(0x10000)
3132e9fc1aSHaojian Zhuang 
3232e9fc1aSHaojian Zhuang struct acpu_dvfs_sram_stru {
3332e9fc1aSHaojian Zhuang 	unsigned int magic;
3432e9fc1aSHaojian Zhuang 	unsigned int support_freq_num;
3532e9fc1aSHaojian Zhuang 	unsigned int support_freq_max;
3632e9fc1aSHaojian Zhuang 	unsigned int start_prof;
3732e9fc1aSHaojian Zhuang 	unsigned int vol[ACPU_OPP_NUM];
3832e9fc1aSHaojian Zhuang };
3932e9fc1aSHaojian Zhuang 
4032e9fc1aSHaojian Zhuang struct acpu_volt_cal_para {
4132e9fc1aSHaojian Zhuang 	unsigned int freq;
4232e9fc1aSHaojian Zhuang 	unsigned int ul_vol;
4332e9fc1aSHaojian Zhuang 	unsigned int dl_vol;
4432e9fc1aSHaojian Zhuang 	unsigned int core_ref_hpm;
4532e9fc1aSHaojian Zhuang };
4632e9fc1aSHaojian Zhuang 
4732e9fc1aSHaojian Zhuang struct ddr_volt_cal_para {
4832e9fc1aSHaojian Zhuang 	unsigned int freq;
4932e9fc1aSHaojian Zhuang 	unsigned int ul_vol;
5032e9fc1aSHaojian Zhuang 	unsigned int dl_vol;
5132e9fc1aSHaojian Zhuang 	unsigned int ddr_ref_hpm;
5232e9fc1aSHaojian Zhuang };
5332e9fc1aSHaojian Zhuang 
5432e9fc1aSHaojian Zhuang struct acpu_dvfs_opp_para {
5532e9fc1aSHaojian Zhuang 	unsigned int freq;
5632e9fc1aSHaojian Zhuang 	unsigned int acpu_clk_profile0;
5732e9fc1aSHaojian Zhuang 	unsigned int acpu_clk_profile1;
5832e9fc1aSHaojian Zhuang 	unsigned int acpu_vol_profile;
5932e9fc1aSHaojian Zhuang 	unsigned int acpu_pll_freq;
6032e9fc1aSHaojian Zhuang 	unsigned int acpu_pll_frac;
6132e9fc1aSHaojian Zhuang };
6232e9fc1aSHaojian Zhuang 
6332e9fc1aSHaojian Zhuang unsigned int efuse_acpu_freq[] = {
6432e9fc1aSHaojian Zhuang 	1200000, 1250000, 1300000, 1350000,
6532e9fc1aSHaojian Zhuang 	1400000, 1450000, 1500000, 1550000,
6632e9fc1aSHaojian Zhuang 	1600000, 1650000, 1700000, 1750000,
6732e9fc1aSHaojian Zhuang 	1800000, 1850000, 1900000, 1950000,
6832e9fc1aSHaojian Zhuang };
6932e9fc1aSHaojian Zhuang 
7032e9fc1aSHaojian Zhuang struct acpu_dvfs_opp_para hi6220_acpu_profile[] = {
7132e9fc1aSHaojian Zhuang 	{ 208000,  0x61E5, 0x022, 0x3A, 0x5220102B, 0x05555555 },
7232e9fc1aSHaojian Zhuang 	{ 432000,  0x10A6, 0x121, 0x3A, 0x5120102D, 0x10000005 },
7332e9fc1aSHaojian Zhuang 	{ 729000,  0x2283, 0x100, 0x4A, 0x51101026, 0x10000005 },
7432e9fc1aSHaojian Zhuang 	{ 960000,  0x1211, 0x100, 0x5B, 0x51101032, 0x10000005 },
7532e9fc1aSHaojian Zhuang 	{ 1200000, 0x1211, 0x100, 0x6B, 0x5110207D, 0x10000005 },
7632e9fc1aSHaojian Zhuang 	{ 1400000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
7732e9fc1aSHaojian Zhuang 	{ 1500000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
7832e9fc1aSHaojian Zhuang };
7932e9fc1aSHaojian Zhuang 
8032e9fc1aSHaojian Zhuang struct acpu_dvfs_opp_para *acpu_dvfs_profile = hi6220_acpu_profile;
8132e9fc1aSHaojian Zhuang struct acpu_dvfs_sram_stru *acpu_dvfs_sram_buf =
8232e9fc1aSHaojian Zhuang 	(struct acpu_dvfs_sram_stru *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
8332e9fc1aSHaojian Zhuang 
8432e9fc1aSHaojian Zhuang static inline void write_reg_mask(uintptr_t addr,
8532e9fc1aSHaojian Zhuang 				  uint32_t val, uint32_t mask)
8632e9fc1aSHaojian Zhuang {
8732e9fc1aSHaojian Zhuang 	uint32_t reg;
8832e9fc1aSHaojian Zhuang 
8932e9fc1aSHaojian Zhuang 	reg = mmio_read_32(addr);
9032e9fc1aSHaojian Zhuang 	reg = (reg & ~(mask)) | val;
9132e9fc1aSHaojian Zhuang 	mmio_write_32(addr, reg);
9232e9fc1aSHaojian Zhuang }
9332e9fc1aSHaojian Zhuang 
9432e9fc1aSHaojian Zhuang static inline uint32_t read_reg_mask(uintptr_t addr,
9532e9fc1aSHaojian Zhuang 				     uint32_t mask, uint32_t offset)
9632e9fc1aSHaojian Zhuang {
9732e9fc1aSHaojian Zhuang 	uint32_t reg;
9832e9fc1aSHaojian Zhuang 
9932e9fc1aSHaojian Zhuang 	reg = mmio_read_32(addr);
10032e9fc1aSHaojian Zhuang 	reg &= (mask << offset);
10132e9fc1aSHaojian Zhuang 	return (reg >> offset);
10232e9fc1aSHaojian Zhuang }
10332e9fc1aSHaojian Zhuang 
10432e9fc1aSHaojian Zhuang static int acpu_dvfs_syspll_cfg(unsigned int prof_id)
10532e9fc1aSHaojian Zhuang {
10632e9fc1aSHaojian Zhuang 	uint32_t reg0 = 0;
10732e9fc1aSHaojian Zhuang 	uint32_t count = 0;
10832e9fc1aSHaojian Zhuang 	uint32_t clk_div_status = 0;
10932e9fc1aSHaojian Zhuang 
11032e9fc1aSHaojian Zhuang 	/*
11132e9fc1aSHaojian Zhuang 	 * step 1:
11232e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
11332e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
11432e9fc1aSHaojian Zhuang 	 */
11532e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x3 << 12, 0x3 << 12);
11632e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 4,  0x1 << 4);
11732e9fc1aSHaojian Zhuang 
11832e9fc1aSHaojian Zhuang 	/*
11932e9fc1aSHaojian Zhuang 	 * step 2:
12032e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_div_cfg:
12132e9fc1aSHaojian Zhuang 	 *     208MHz, set to 0x5;
12232e9fc1aSHaojian Zhuang 	 *     500MHz, set to 0x2;
12332e9fc1aSHaojian Zhuang 	 *     other opps set to 0x1
12432e9fc1aSHaojian Zhuang 	 */
12532e9fc1aSHaojian Zhuang 	if (prof_id == 0)
12632e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x5 << 0, 0x7 << 0);
12732e9fc1aSHaojian Zhuang 	else if (prof_id == 1)
12832e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x2 << 0, 0x7 << 0);
12932e9fc1aSHaojian Zhuang 	else
13032e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 0, 0x7 << 0);
13132e9fc1aSHaojian Zhuang 
13232e9fc1aSHaojian Zhuang 	/*
13332e9fc1aSHaojian Zhuang 	 * step 3:
13432e9fc1aSHaojian Zhuang 	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x3;
13532e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0
13632e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0
13732e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1
13832e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
13932e9fc1aSHaojian Zhuang 	 */
14032e9fc1aSHaojian Zhuang 	clk_div_status = 0x3;
14132e9fc1aSHaojian Zhuang 	do {
14232e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, 20);
14332e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
14432e9fc1aSHaojian Zhuang 			ERROR("%s: clk div status timeout!\n", __func__);
14532e9fc1aSHaojian Zhuang 			return -1;
14632e9fc1aSHaojian Zhuang 		}
14732e9fc1aSHaojian Zhuang 	} while (clk_div_status != reg0);
14832e9fc1aSHaojian Zhuang 
14932e9fc1aSHaojian Zhuang 	write_reg_mask(ACPU_SC_VD_CTRL, 0x0, (0x1 << 0) | (0x1 << 11));
15032e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUCLKDIV, 0x1 << 8, 0x3 << 8);
15132e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x1 << 0, 0x1 << 0);
15232e9fc1aSHaojian Zhuang 
15332e9fc1aSHaojian Zhuang 	return 0;
15432e9fc1aSHaojian Zhuang }
15532e9fc1aSHaojian Zhuang 
15632e9fc1aSHaojian Zhuang static void acpu_dvfs_clk_div_cfg(unsigned int prof_id,
15732e9fc1aSHaojian Zhuang 				  unsigned int *cpuext_cfg,
15832e9fc1aSHaojian Zhuang 				  unsigned int *acpu_ddr_cfg)
15932e9fc1aSHaojian Zhuang {
16032e9fc1aSHaojian Zhuang 	if (prof_id == 0) {
16132e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUCLKDIV,
16232e9fc1aSHaojian Zhuang 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
16332e9fc1aSHaojian Zhuang 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
16432e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
16532e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
16632e9fc1aSHaojian Zhuang 		*cpuext_cfg = 0x1;
16732e9fc1aSHaojian Zhuang 		*acpu_ddr_cfg = 0x1;
16832e9fc1aSHaojian Zhuang 	} else if (prof_id == 1) {
16932e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUCLKDIV,
17032e9fc1aSHaojian Zhuang 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
17132e9fc1aSHaojian Zhuang 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
17232e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
17332e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
17432e9fc1aSHaojian Zhuang 		*cpuext_cfg = 0x1;
17532e9fc1aSHaojian Zhuang 		*acpu_ddr_cfg = 0x1;
17632e9fc1aSHaojian Zhuang 	} else {
17732e9fc1aSHaojian Zhuang 		/* ddr has not been inited */
17832e9fc1aSHaojian Zhuang 		write_reg_mask(PMCTRL_ACPUCLKDIV,
17932e9fc1aSHaojian Zhuang 			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
18032e9fc1aSHaojian Zhuang 			(0x0 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
18132e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
18232e9fc1aSHaojian Zhuang 			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
18332e9fc1aSHaojian Zhuang 		*cpuext_cfg = 0x1;
18432e9fc1aSHaojian Zhuang 		*acpu_ddr_cfg = 0x0;
18532e9fc1aSHaojian Zhuang 	}
18632e9fc1aSHaojian Zhuang }
18732e9fc1aSHaojian Zhuang 
18832e9fc1aSHaojian Zhuang static int acpu_dvfs_freq_ascend(unsigned int cur_prof, unsigned int tar_prof)
18932e9fc1aSHaojian Zhuang {
19032e9fc1aSHaojian Zhuang 	unsigned int reg0 = 0;
19132e9fc1aSHaojian Zhuang 	unsigned int reg1 = 0;
19232e9fc1aSHaojian Zhuang 	unsigned int reg2 = 0;
19332e9fc1aSHaojian Zhuang 	unsigned int count = 0;
19432e9fc1aSHaojian Zhuang 	unsigned int cpuext_cfg_val = 0;
19532e9fc1aSHaojian Zhuang 	unsigned int acpu_ddr_cfg_val = 0;
19632e9fc1aSHaojian Zhuang 	int ret = 0;
19732e9fc1aSHaojian Zhuang 
19832e9fc1aSHaojian Zhuang 	/*
19932e9fc1aSHaojian Zhuang 	 * step 1:
20032e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
20132e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
20232e9fc1aSHaojian Zhuang 	 *
20332e9fc1aSHaojian Zhuang 	 * step 2:
20432e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x5 (208MHz)
20532e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x2 (500MHz)
20632e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x1 (Other OPPs)
20732e9fc1aSHaojian Zhuang 	 *
20832e9fc1aSHaojian Zhuang 	 * step 3:
20932e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_CPU_STAT.clk_div_status_vd = 0x3;
21032e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x0;
21132e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x0;
21232e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1;
21332e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
21432e9fc1aSHaojian Zhuang 	 */
21532e9fc1aSHaojian Zhuang 	ret = acpu_dvfs_syspll_cfg(cur_prof);
21632e9fc1aSHaojian Zhuang 	if (ret)
21732e9fc1aSHaojian Zhuang 		return -1;
21832e9fc1aSHaojian Zhuang 
21932e9fc1aSHaojian Zhuang 	/*
22032e9fc1aSHaojian Zhuang 	 * step 4:
22132e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
22232e9fc1aSHaojian Zhuang 	 */
22332e9fc1aSHaojian Zhuang 	count = 0;
22432e9fc1aSHaojian Zhuang 	do {
22532e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
22632e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START);
22732e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
22832e9fc1aSHaojian Zhuang 			ERROR("%s: syspll sw status timeout\n", __func__);
22932e9fc1aSHaojian Zhuang 			return -1;
23032e9fc1aSHaojian Zhuang 		}
23132e9fc1aSHaojian Zhuang 	} while (reg0 != 0x1);
23232e9fc1aSHaojian Zhuang 
23332e9fc1aSHaojian Zhuang 	/* Enable VD functionality if > 800MHz */
23432e9fc1aSHaojian Zhuang 	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
23532e9fc1aSHaojian Zhuang 
23632e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
23732e9fc1aSHaojian Zhuang 			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
23832e9fc1aSHaojian Zhuang 
23932e9fc1aSHaojian Zhuang 		/*
24032e9fc1aSHaojian Zhuang 		 * step 5:
24132e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
24232e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
24332e9fc1aSHaojian Zhuang 		 */
24432e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
24532e9fc1aSHaojian Zhuang 			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
24632e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
24732e9fc1aSHaojian Zhuang 			ACPU_SC_VD_MASK_PATTERN_VAL,
24832e9fc1aSHaojian Zhuang 			ACPU_SC_VD_MASK_PATTERN_MASK);
24932e9fc1aSHaojian Zhuang 
25032e9fc1aSHaojian Zhuang 		/*
25132e9fc1aSHaojian Zhuang 		 * step 6:
25232e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
25332e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
25432e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
25532e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
25632e9fc1aSHaojian Zhuang 		 */
25732e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
25832e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
25932e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
26032e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
26132e9fc1aSHaojian Zhuang 
26232e9fc1aSHaojian Zhuang 		/*
26332e9fc1aSHaojian Zhuang 		 * step 7:
26432e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
26532e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
26632e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
26732e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
26832e9fc1aSHaojian Zhuang 		 *
26932e9fc1aSHaojian Zhuang 		 * step 8:
27032e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
27132e9fc1aSHaojian Zhuang 		 */
27232e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_CTRL,
27332e9fc1aSHaojian Zhuang 			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
27432e9fc1aSHaojian Zhuang 			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
27532e9fc1aSHaojian Zhuang 	}
27632e9fc1aSHaojian Zhuang 
27732e9fc1aSHaojian Zhuang 	/* step 9: ACPUPLLCTRL.acpupll_en_cfg = 0x0 */
27832e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0,
27932e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
28032e9fc1aSHaojian Zhuang 
28132e9fc1aSHaojian Zhuang 	/* step 10: set PMCTRL_ACPUPLLFREQ and PMCTRL_ACPUPLLFRAC */
28232e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPLLFREQ,
28332e9fc1aSHaojian Zhuang 		acpu_dvfs_profile[tar_prof].acpu_pll_freq);
28432e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPLLFRAC,
28532e9fc1aSHaojian Zhuang 		acpu_dvfs_profile[tar_prof].acpu_pll_frac);
28632e9fc1aSHaojian Zhuang 
28732e9fc1aSHaojian Zhuang 	/*
28832e9fc1aSHaojian Zhuang 	 * step 11:
28932e9fc1aSHaojian Zhuang 	 *  - wait for 1us;
29032e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
29132e9fc1aSHaojian Zhuang 	 */
29232e9fc1aSHaojian Zhuang 	count = 0;
29332e9fc1aSHaojian Zhuang 	while (count < ACPU_WAIT_TIMEOUT)
29432e9fc1aSHaojian Zhuang 		count++;
29532e9fc1aSHaojian Zhuang 
29632e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLCTRL,
29732e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
29832e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
29932e9fc1aSHaojian Zhuang 
30032e9fc1aSHaojian Zhuang 	/* step 12: PMCTRL_ACPUVOLPMUADDR = 0x100da */
30132e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
30232e9fc1aSHaojian Zhuang 
30332e9fc1aSHaojian Zhuang 	/*
30432e9fc1aSHaojian Zhuang 	 * step 13:
30532e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (208MHz);
30632e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (500MHz);
30732e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x20 (798MHz);
30832e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1300MHz);
30932e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1500MHz);
31032e9fc1aSHaojian Zhuang 	 */
31132e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUDESTVOL,
31232e9fc1aSHaojian Zhuang 		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
31332e9fc1aSHaojian Zhuang 		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
31432e9fc1aSHaojian Zhuang 
31532e9fc1aSHaojian Zhuang 	/*
31632e9fc1aSHaojian Zhuang 	 * step 14:
31732e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
31832e9fc1aSHaojian Zhuang 	 *  - Polling ACPUVOLTIMEOUT.acpu_vol_timeout == 0x1
31932e9fc1aSHaojian Zhuang 	 *  - Config PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg
32032e9fc1aSHaojian Zhuang 	 *  - Config ACPUCLKDIV.cpuext_clk_div_cfg;
32132e9fc1aSHaojian Zhuang 	 */
32232e9fc1aSHaojian Zhuang 	count = 0;
32332e9fc1aSHaojian Zhuang 	do {
32432e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
32532e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
32632e9fc1aSHaojian Zhuang 		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
32732e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
32832e9fc1aSHaojian Zhuang 		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
32932e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
33032e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
33132e9fc1aSHaojian Zhuang 			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
33232e9fc1aSHaojian Zhuang 			return -1;
33332e9fc1aSHaojian Zhuang 		}
33432e9fc1aSHaojian Zhuang 	} while ((reg0 != reg1) || (reg2 != 0x1));
33532e9fc1aSHaojian Zhuang 
33632e9fc1aSHaojian Zhuang 	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
33732e9fc1aSHaojian Zhuang 
33832e9fc1aSHaojian Zhuang 	/*
33932e9fc1aSHaojian Zhuang 	 * step 15:
34032e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
34132e9fc1aSHaojian Zhuang 	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
34232e9fc1aSHaojian Zhuang 	 *  - ACPUPLLCTRL.acpupll_timeout = 0x1;
34332e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
34432e9fc1aSHaojian Zhuang 	 */
34532e9fc1aSHaojian Zhuang 	count = 0;
34632e9fc1aSHaojian Zhuang 	do {
34732e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
34832e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
34932e9fc1aSHaojian Zhuang 		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
35032e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
35132e9fc1aSHaojian Zhuang 		reg2 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
35232e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
35332e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
35432e9fc1aSHaojian Zhuang 			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
35532e9fc1aSHaojian Zhuang 			return -1;
35632e9fc1aSHaojian Zhuang 		}
35732e9fc1aSHaojian Zhuang 	} while ((reg1 != cpuext_cfg_val) ||
35832e9fc1aSHaojian Zhuang 		(reg0 != acpu_ddr_cfg_val) ||
35932e9fc1aSHaojian Zhuang 		(reg2 != 0x1));
36032e9fc1aSHaojian Zhuang 
36132e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
36232e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
36332e9fc1aSHaojian Zhuang 
36432e9fc1aSHaojian Zhuang 	/*
36532e9fc1aSHaojian Zhuang 	 * step 16:
36632e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
36732e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
36832e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
36932e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
37032e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
37132e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
37232e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
37332e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
37432e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
37532e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
37632e9fc1aSHaojian Zhuang 	 */
37732e9fc1aSHaojian Zhuang 	count = 0;
37832e9fc1aSHaojian Zhuang 	do {
37932e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
38032e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
38132e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
38232e9fc1aSHaojian Zhuang 			ERROR("%s: acpu pll sw status timeout.\n", __func__);
38332e9fc1aSHaojian Zhuang 			return -1;
38432e9fc1aSHaojian Zhuang 		}
38532e9fc1aSHaojian Zhuang 	} while (reg0 != 0x1);
38632e9fc1aSHaojian Zhuang 
38732e9fc1aSHaojian Zhuang 	if (acpu_dvfs_profile[tar_prof].freq > 800000)
38832e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_CTRL,
38932e9fc1aSHaojian Zhuang 			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
39032e9fc1aSHaojian Zhuang 
39132e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
39232e9fc1aSHaojian Zhuang 		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
39332e9fc1aSHaojian Zhuang 		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
39432e9fc1aSHaojian Zhuang 
39532e9fc1aSHaojian Zhuang 	return 0;
39632e9fc1aSHaojian Zhuang }
39732e9fc1aSHaojian Zhuang 
39832e9fc1aSHaojian Zhuang static int acpu_dvfs_freq_descend(unsigned int cur_prof, unsigned int tar_prof)
39932e9fc1aSHaojian Zhuang {
40032e9fc1aSHaojian Zhuang 	unsigned int reg0 = 0;
40132e9fc1aSHaojian Zhuang 	unsigned int reg1 = 0;
40232e9fc1aSHaojian Zhuang 	unsigned int reg2 = 0;
40332e9fc1aSHaojian Zhuang 	unsigned int count = 0;
40432e9fc1aSHaojian Zhuang 	unsigned int cpuext_cfg_val = 0;
40532e9fc1aSHaojian Zhuang 	unsigned int acpu_ddr_cfg_val = 0;
40632e9fc1aSHaojian Zhuang 	int ret = 0;
40732e9fc1aSHaojian Zhuang 
40832e9fc1aSHaojian Zhuang 	ret = acpu_dvfs_syspll_cfg(tar_prof);
40932e9fc1aSHaojian Zhuang 	if (ret)
41032e9fc1aSHaojian Zhuang 		return -1;
41132e9fc1aSHaojian Zhuang 
41232e9fc1aSHaojian Zhuang 	/*
41332e9fc1aSHaojian Zhuang 	 * step 4:
41432e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
41532e9fc1aSHaojian Zhuang 	 */
41632e9fc1aSHaojian Zhuang 	count = 0;
41732e9fc1aSHaojian Zhuang 	do {
41832e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, 2);
41932e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
42032e9fc1aSHaojian Zhuang 			ERROR("%s: syspll sw status timeout.\n", __func__);
42132e9fc1aSHaojian Zhuang 			return -1;
42232e9fc1aSHaojian Zhuang 		}
42332e9fc1aSHaojian Zhuang 	} while (reg0 != 0x1);
42432e9fc1aSHaojian Zhuang 
42532e9fc1aSHaojian Zhuang 	/*
42632e9fc1aSHaojian Zhuang 	 * Step 5:
42732e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x0
42832e9fc1aSHaojian Zhuang 	 */
42932e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << 0);
43032e9fc1aSHaojian Zhuang 
43132e9fc1aSHaojian Zhuang 	/*
43232e9fc1aSHaojian Zhuang 	 * step 6
43332e9fc1aSHaojian Zhuang 	 *  - Config PMCTRL_ACPUPLLFREQ and ACPUPLLFRAC
43432e9fc1aSHaojian Zhuang 	 */
43532e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq);
43632e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac);
43732e9fc1aSHaojian Zhuang 
43832e9fc1aSHaojian Zhuang 	/*
43932e9fc1aSHaojian Zhuang 	 * step 7:
44032e9fc1aSHaojian Zhuang 	 *  - Wait 1us;
44132e9fc1aSHaojian Zhuang 	 *  - Config PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
44232e9fc1aSHaojian Zhuang 	 */
44332e9fc1aSHaojian Zhuang 	count = 0;
44432e9fc1aSHaojian Zhuang 	while (count < ACPU_WAIT_TIMEOUT)
44532e9fc1aSHaojian Zhuang 		count++;
44632e9fc1aSHaojian Zhuang 
44732e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLCTRL,
44832e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
44932e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
45032e9fc1aSHaojian Zhuang 
45132e9fc1aSHaojian Zhuang 	/* Enable VD functionality if > 800MHz */
45232e9fc1aSHaojian Zhuang 	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
45332e9fc1aSHaojian Zhuang 
45432e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
45532e9fc1aSHaojian Zhuang 			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
45632e9fc1aSHaojian Zhuang 
45732e9fc1aSHaojian Zhuang 		/*
45832e9fc1aSHaojian Zhuang 		 * step 9:
45932e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
46032e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
46132e9fc1aSHaojian Zhuang 		 */
46232e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
46332e9fc1aSHaojian Zhuang 			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
46432e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
46532e9fc1aSHaojian Zhuang 			ACPU_SC_VD_MASK_PATTERN_VAL,
46632e9fc1aSHaojian Zhuang 			ACPU_SC_VD_MASK_PATTERN_MASK);
46732e9fc1aSHaojian Zhuang 
46832e9fc1aSHaojian Zhuang 		/*
46932e9fc1aSHaojian Zhuang 		 * step 10:
47032e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
47132e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
47232e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
47332e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
47432e9fc1aSHaojian Zhuang 		 */
47532e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
47632e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
47732e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
47832e9fc1aSHaojian Zhuang 		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
47932e9fc1aSHaojian Zhuang 
48032e9fc1aSHaojian Zhuang 		/*
48132e9fc1aSHaojian Zhuang 		 * step 11:
48232e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
48332e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
48432e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
48532e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
48632e9fc1aSHaojian Zhuang 		 *
48732e9fc1aSHaojian Zhuang 		 * step 12:
48832e9fc1aSHaojian Zhuang 		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
48932e9fc1aSHaojian Zhuang 		 */
49032e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_CTRL,
49132e9fc1aSHaojian Zhuang 			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
49232e9fc1aSHaojian Zhuang 			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
49332e9fc1aSHaojian Zhuang 	}
49432e9fc1aSHaojian Zhuang 
49532e9fc1aSHaojian Zhuang 	/*
49632e9fc1aSHaojian Zhuang 	 * step 13:
49732e9fc1aSHaojian Zhuang 	 *  - Pollig PMCTRL_ACPUPLLCTRL.acpupll_timeout == 0x1;
49832e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
49932e9fc1aSHaojian Zhuang 	 */
50032e9fc1aSHaojian Zhuang 	count = 0;
50132e9fc1aSHaojian Zhuang 	do {
50232e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
50332e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
50432e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
50532e9fc1aSHaojian Zhuang 			ERROR("%s: acpupll timeout.\n", __func__);
50632e9fc1aSHaojian Zhuang 			return -1;
50732e9fc1aSHaojian Zhuang 		}
50832e9fc1aSHaojian Zhuang 	} while (reg0 != 0x1);
50932e9fc1aSHaojian Zhuang 
51032e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
51132e9fc1aSHaojian Zhuang 		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
51232e9fc1aSHaojian Zhuang 
51332e9fc1aSHaojian Zhuang 	/*
51432e9fc1aSHaojian Zhuang 	 * step 14:
51532e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
51632e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
51732e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
51832e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
51932e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
52032e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
52132e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
52232e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
52332e9fc1aSHaojian Zhuang 	 */
52432e9fc1aSHaojian Zhuang 	count = 0;
52532e9fc1aSHaojian Zhuang 	do {
52632e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
52732e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
52832e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
52932e9fc1aSHaojian Zhuang 			ERROR("%s: acpupll sw status timeout.\n", __func__);
53032e9fc1aSHaojian Zhuang 			return -1;
53132e9fc1aSHaojian Zhuang 		}
53232e9fc1aSHaojian Zhuang 	} while (reg0 != 0x1);
53332e9fc1aSHaojian Zhuang 
53432e9fc1aSHaojian Zhuang 	if (acpu_dvfs_profile[tar_prof].freq > 800000)
53532e9fc1aSHaojian Zhuang 		write_reg_mask(ACPU_SC_VD_CTRL,
53632e9fc1aSHaojian Zhuang 			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
53732e9fc1aSHaojian Zhuang 
53832e9fc1aSHaojian Zhuang 	/*
53932e9fc1aSHaojian Zhuang 	 * step 15:
54032e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
54132e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
54232e9fc1aSHaojian Zhuang 	 */
54332e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
54432e9fc1aSHaojian Zhuang 		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
54532e9fc1aSHaojian Zhuang 		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
54632e9fc1aSHaojian Zhuang 
54732e9fc1aSHaojian Zhuang 	/*
54832e9fc1aSHaojian Zhuang 	 * step 16:
54932e9fc1aSHaojian Zhuang 	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x0;
55032e9fc1aSHaojian Zhuang 	 */
55132e9fc1aSHaojian Zhuang 	count = 0;
55232e9fc1aSHaojian Zhuang 	do {
55332e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3,
55432e9fc1aSHaojian Zhuang 			ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT);
55532e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
55632e9fc1aSHaojian Zhuang 			ERROR("%s: clk div status timeout.\n", __func__);
55732e9fc1aSHaojian Zhuang 			return -1;
55832e9fc1aSHaojian Zhuang 		}
55932e9fc1aSHaojian Zhuang 	} while (reg0 != 0x0);
56032e9fc1aSHaojian Zhuang 
56132e9fc1aSHaojian Zhuang 	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
56232e9fc1aSHaojian Zhuang 
56332e9fc1aSHaojian Zhuang 	/*
56432e9fc1aSHaojian Zhuang 	 * step 17:
56532e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
56632e9fc1aSHaojian Zhuang 	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
56732e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUVOLPMUADDR = 0x1006C;
56832e9fc1aSHaojian Zhuang 	 */
56932e9fc1aSHaojian Zhuang 	count = 0;
57032e9fc1aSHaojian Zhuang 	do {
57132e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
57232e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
57332e9fc1aSHaojian Zhuang 		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
57432e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
57532e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
57632e9fc1aSHaojian Zhuang 			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
57732e9fc1aSHaojian Zhuang 			return -1;
57832e9fc1aSHaojian Zhuang 		}
57932e9fc1aSHaojian Zhuang 	} while ((reg0 != cpuext_cfg_val) || (reg1 != acpu_ddr_cfg_val));
58032e9fc1aSHaojian Zhuang 
58132e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
58232e9fc1aSHaojian Zhuang 
58332e9fc1aSHaojian Zhuang 	/*
58432e9fc1aSHaojian Zhuang 	 * step 16:
58532e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
58632e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
58732e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
58832e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
58932e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
59032e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
59132e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
59232e9fc1aSHaojian Zhuang 	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
59332e9fc1aSHaojian Zhuang 	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
59432e9fc1aSHaojian Zhuang 	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
59532e9fc1aSHaojian Zhuang 	 */
59632e9fc1aSHaojian Zhuang 	write_reg_mask(PMCTRL_ACPUDESTVOL,
59732e9fc1aSHaojian Zhuang 		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
59832e9fc1aSHaojian Zhuang 		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
59932e9fc1aSHaojian Zhuang 
60032e9fc1aSHaojian Zhuang 	/*
60132e9fc1aSHaojian Zhuang 	 * step 19:
60232e9fc1aSHaojian Zhuang 	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
60332e9fc1aSHaojian Zhuang 	 *  - ACPUVOLTIMEOUT.acpu_vol_timeout = 0x1;
60432e9fc1aSHaojian Zhuang 	 */
60532e9fc1aSHaojian Zhuang 	count = 0;
60632e9fc1aSHaojian Zhuang 	do {
60732e9fc1aSHaojian Zhuang 		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
60832e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
60932e9fc1aSHaojian Zhuang 		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
61032e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
61132e9fc1aSHaojian Zhuang 		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
61232e9fc1aSHaojian Zhuang 			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
61332e9fc1aSHaojian Zhuang 		if ((count++) > ACPU_DFS_STATE_CNT) {
61432e9fc1aSHaojian Zhuang 			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
61532e9fc1aSHaojian Zhuang 			return -1;
61632e9fc1aSHaojian Zhuang 		}
61732e9fc1aSHaojian Zhuang 	} while ((reg0 != reg1) || (reg2 != 0x1));
61832e9fc1aSHaojian Zhuang 
61932e9fc1aSHaojian Zhuang 	return 0;
62032e9fc1aSHaojian Zhuang }
62132e9fc1aSHaojian Zhuang 
62232e9fc1aSHaojian Zhuang int acpu_dvfs_target(unsigned int curr_prof, unsigned int target_prof)
62332e9fc1aSHaojian Zhuang {
62432e9fc1aSHaojian Zhuang 	int ret = 0;
62532e9fc1aSHaojian Zhuang 
62632e9fc1aSHaojian Zhuang 	if (curr_prof == target_prof) {
62732e9fc1aSHaojian Zhuang 		INFO("%s: target_prof is equal curr_prof: is %d!\n",
62832e9fc1aSHaojian Zhuang 			__func__, curr_prof);
62932e9fc1aSHaojian Zhuang 		return 0;
63032e9fc1aSHaojian Zhuang 	}
63132e9fc1aSHaojian Zhuang 
63232e9fc1aSHaojian Zhuang 	if ((curr_prof >= ACPU_FREQ_MAX_NUM) ||
63332e9fc1aSHaojian Zhuang 	    (target_prof >= ACPU_FREQ_MAX_NUM)) {
63432e9fc1aSHaojian Zhuang 		INFO("%s: invalid parameter %d %d\n",
63532e9fc1aSHaojian Zhuang 			__func__, curr_prof, target_prof);
63632e9fc1aSHaojian Zhuang 		return -1;
63732e9fc1aSHaojian Zhuang 	}
63832e9fc1aSHaojian Zhuang 
63932e9fc1aSHaojian Zhuang 	if (target_prof > acpu_dvfs_sram_buf->support_freq_num)
64032e9fc1aSHaojian Zhuang 		target_prof = acpu_dvfs_sram_buf->support_freq_num;
64132e9fc1aSHaojian Zhuang 
64232e9fc1aSHaojian Zhuang 	if (target_prof < curr_prof)
64332e9fc1aSHaojian Zhuang 		ret = acpu_dvfs_freq_descend(curr_prof, target_prof);
64432e9fc1aSHaojian Zhuang 	else if (target_prof > curr_prof)
64532e9fc1aSHaojian Zhuang 		ret = acpu_dvfs_freq_ascend(curr_prof, target_prof);
64632e9fc1aSHaojian Zhuang 
64732e9fc1aSHaojian Zhuang 	if (ret) {
64832e9fc1aSHaojian Zhuang 		ERROR("%s: acpu_dvfs_target failed!\n", __func__);
64932e9fc1aSHaojian Zhuang 		return -1;
65032e9fc1aSHaojian Zhuang 	}
65132e9fc1aSHaojian Zhuang 
65232e9fc1aSHaojian Zhuang 	/* Complete acpu dvfs setting and set magic number */
65332e9fc1aSHaojian Zhuang 	acpu_dvfs_sram_buf->start_prof = target_prof;
65432e9fc1aSHaojian Zhuang 	acpu_dvfs_sram_buf->magic = ACPU_VALID_VOLTAGE_MAGIC;
65532e9fc1aSHaojian Zhuang 
65632e9fc1aSHaojian Zhuang 	mmio_write_32(DDR_DFS_FREQ_ADDR, 800000);
65732e9fc1aSHaojian Zhuang 	return 0;
65832e9fc1aSHaojian Zhuang }
65932e9fc1aSHaojian Zhuang 
66032e9fc1aSHaojian Zhuang static int acpu_dvfs_set_freq(void)
66132e9fc1aSHaojian Zhuang {
66232e9fc1aSHaojian Zhuang 	unsigned int i;
66332e9fc1aSHaojian Zhuang 	unsigned int curr_prof;
66432e9fc1aSHaojian Zhuang 	unsigned int target_prof;
66532e9fc1aSHaojian Zhuang 	unsigned int max_freq = 0;
66632e9fc1aSHaojian Zhuang 
66732e9fc1aSHaojian Zhuang 	max_freq = acpu_dvfs_sram_buf->support_freq_max;
66832e9fc1aSHaojian Zhuang 
66932e9fc1aSHaojian Zhuang 	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) {
67032e9fc1aSHaojian Zhuang 
67132e9fc1aSHaojian Zhuang 		if (max_freq == hi6220_acpu_profile[i].freq) {
67232e9fc1aSHaojian Zhuang 			target_prof = i;
67332e9fc1aSHaojian Zhuang 			break;
67432e9fc1aSHaojian Zhuang 		}
67532e9fc1aSHaojian Zhuang 	}
67632e9fc1aSHaojian Zhuang 
67732e9fc1aSHaojian Zhuang 	if (i == acpu_dvfs_sram_buf->support_freq_num) {
67832e9fc1aSHaojian Zhuang 		ERROR("%s: cannot found max freq profile\n", __func__);
67932e9fc1aSHaojian Zhuang 		return -1;
68032e9fc1aSHaojian Zhuang 	}
68132e9fc1aSHaojian Zhuang 
68232e9fc1aSHaojian Zhuang 	curr_prof = 0;
68332e9fc1aSHaojian Zhuang 	target_prof = i;
68432e9fc1aSHaojian Zhuang 
68532e9fc1aSHaojian Zhuang 	/* if max freq is 208MHz, do nothing */
68632e9fc1aSHaojian Zhuang 	if (curr_prof == target_prof)
68732e9fc1aSHaojian Zhuang 		return 0;
68832e9fc1aSHaojian Zhuang 
68932e9fc1aSHaojian Zhuang 	if (acpu_dvfs_target(curr_prof, target_prof)) {
69032e9fc1aSHaojian Zhuang 		ERROR("%s: set acpu freq failed!", __func__);
69132e9fc1aSHaojian Zhuang 		return -1;
69232e9fc1aSHaojian Zhuang 	}
69332e9fc1aSHaojian Zhuang 
69432e9fc1aSHaojian Zhuang 	INFO("%s: support freq num is %d\n",
69532e9fc1aSHaojian Zhuang 		__func__, acpu_dvfs_sram_buf->support_freq_num);
69632e9fc1aSHaojian Zhuang 	INFO("%s: start prof is 0x%x\n",
69732e9fc1aSHaojian Zhuang 		__func__,  acpu_dvfs_sram_buf->start_prof);
69832e9fc1aSHaojian Zhuang 	INFO("%s: magic is 0x%x\n",
69932e9fc1aSHaojian Zhuang 		__func__, acpu_dvfs_sram_buf->magic);
70032e9fc1aSHaojian Zhuang 	INFO("%s: voltage:\n", __func__);
70132e9fc1aSHaojian Zhuang 	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++)
70232e9fc1aSHaojian Zhuang 		INFO("  - %d: 0x%x\n", i, acpu_dvfs_sram_buf->vol[i]);
70332e9fc1aSHaojian Zhuang 
70432e9fc1aSHaojian Zhuang 	NOTICE("%s: set acpu freq success!", __func__);
70532e9fc1aSHaojian Zhuang 	return 0;
70632e9fc1aSHaojian Zhuang }
70732e9fc1aSHaojian Zhuang 
70832e9fc1aSHaojian Zhuang struct acpu_dvfs_volt_setting {
70932e9fc1aSHaojian Zhuang 	unsigned int magic;
71032e9fc1aSHaojian Zhuang 	unsigned int support_freq_num;
71132e9fc1aSHaojian Zhuang 	unsigned int support_freq_max;
71232e9fc1aSHaojian Zhuang 	unsigned int start_prof;
71332e9fc1aSHaojian Zhuang 	unsigned int vol[7];
71432e9fc1aSHaojian Zhuang 	unsigned int hmp_dly_threshold[7];
71532e9fc1aSHaojian Zhuang };
71632e9fc1aSHaojian Zhuang 
71732e9fc1aSHaojian Zhuang static void acpu_dvfs_volt_init(void)
71832e9fc1aSHaojian Zhuang {
71932e9fc1aSHaojian Zhuang 	struct acpu_dvfs_volt_setting *volt;
72032e9fc1aSHaojian Zhuang 
72132e9fc1aSHaojian Zhuang 	/*
72232e9fc1aSHaojian Zhuang 	 * - set default voltage;
72332e9fc1aSHaojian Zhuang 	 * - set pmu address;
72432e9fc1aSHaojian Zhuang 	 * - set voltage up and down step;
72532e9fc1aSHaojian Zhuang 	 * - set voltage stable time;
72632e9fc1aSHaojian Zhuang 	 */
72732e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUDFTVOL, 0x4a);
72832e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0xda);
72932e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUVOLUPSTEP, 0x1);
73032e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUVOLDNSTEP, 0x1);
73132e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPMUVOLUPTIME, 0x60);
73232e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUPMUVOLDNTIME, 0x60);
73332e9fc1aSHaojian Zhuang 	mmio_write_32(PMCTRL_ACPUCLKOFFCFG, 0x1000);
73432e9fc1aSHaojian Zhuang 
73532e9fc1aSHaojian Zhuang 	volt = (void *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
73632e9fc1aSHaojian Zhuang 	volt->magic = 0x5a5ac5c5;
73732e9fc1aSHaojian Zhuang 	volt->support_freq_num = 5;
73832e9fc1aSHaojian Zhuang 	volt->support_freq_max = 1200000;
73932e9fc1aSHaojian Zhuang 	volt->start_prof = 4;
74032e9fc1aSHaojian Zhuang 	volt->vol[0] = 0x49;
74132e9fc1aSHaojian Zhuang 	volt->vol[1] = 0x49;
74232e9fc1aSHaojian Zhuang 	volt->vol[2] = 0x50;
74332e9fc1aSHaojian Zhuang 	volt->vol[3] = 0x60;
74432e9fc1aSHaojian Zhuang 	volt->vol[4] = 0x78;
74532e9fc1aSHaojian Zhuang 	volt->vol[5] = 0x78;
74632e9fc1aSHaojian Zhuang 	volt->vol[6] = 0x78;
74732e9fc1aSHaojian Zhuang 
74832e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[0] = 0x0;
74932e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[1] = 0x0;
75032e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[2] = 0x0;
75132e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[3] = 0x0e8b0e45;
75232e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[4] = 0x10691023;
75332e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[5] = 0x10691023;
75432e9fc1aSHaojian Zhuang 	volt->hmp_dly_threshold[6] = 0x10691023;
75532e9fc1aSHaojian Zhuang 
75632e9fc1aSHaojian Zhuang 	INFO("%s: success!\n", __func__);
75732e9fc1aSHaojian Zhuang }
75832e9fc1aSHaojian Zhuang 
75932e9fc1aSHaojian Zhuang void init_acpu_dvfs(void)
76032e9fc1aSHaojian Zhuang {
76132e9fc1aSHaojian Zhuang 	unsigned int i = 0;
76232e9fc1aSHaojian Zhuang 
76332e9fc1aSHaojian Zhuang 	INFO("%s: pmic version %d\n", __func__,
76432e9fc1aSHaojian Zhuang 	     mmio_read_8(HI6553_VERSION_REG));
76532e9fc1aSHaojian Zhuang 
76632e9fc1aSHaojian Zhuang 	/* init parameters */
76732e9fc1aSHaojian Zhuang 	mmio_write_32(ACPU_CHIP_MAX_FREQ, efuse_acpu_freq[8]);
76832e9fc1aSHaojian Zhuang 	INFO("%s: ACPU_CHIP_MAX_FREQ=0x%x.\n",
76932e9fc1aSHaojian Zhuang 		__func__, mmio_read_32(ACPU_CHIP_MAX_FREQ));
77032e9fc1aSHaojian Zhuang 
77132e9fc1aSHaojian Zhuang 	/* set maximum support frequency to 1.2GHz */
77232e9fc1aSHaojian Zhuang 	for (i = 0; i < ACPU_FREQ_MAX_NUM; i++)
77332e9fc1aSHaojian Zhuang 		acpu_dvfs_sram_buf->vol[i] = hi6220_acpu_profile[i].acpu_vol_profile;
77432e9fc1aSHaojian Zhuang 
77532e9fc1aSHaojian Zhuang 	acpu_dvfs_sram_buf->support_freq_num = ACPU_FREQ_MAX_NUM;
77632e9fc1aSHaojian Zhuang 	acpu_dvfs_sram_buf->support_freq_max = 1200000;
77732e9fc1aSHaojian Zhuang 
77832e9fc1aSHaojian Zhuang 	/* init acpu dvfs */
77932e9fc1aSHaojian Zhuang 	acpu_dvfs_volt_init();
78032e9fc1aSHaojian Zhuang 	acpu_dvfs_set_freq();
78132e9fc1aSHaojian Zhuang }
782