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