mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-08-15 00:47:02 +02:00
Enforce full include path for includes. Deprecate old paths. The following folders inside include/lib have been left unchanged: - include/lib/cpus/${ARCH} - include/lib/el3_runtime/${ARCH} The reason for this change is that having a global namespace for includes isn't a good idea. It defeats one of the advantages of having folders and it introduces problems that are sometimes subtle (because you may not know the header you are actually including if there are two of them). For example, this patch had to be created because two headers were called the same way:e0ea0928d5
("Fix gpio includes of mt8173 platform to avoid collision."). More recently, this patch has had similar problems:46f9b2c3a2
("drivers: add tzc380 support"). This problem was introduced in commit4ecca33988
("Move include and source files to logical locations"). At that time, there weren't too many headers so it wasn't a real issue. However, time has shown that this creates problems. Platforms that want to preserve the way they include headers may add the removed paths to PLAT_INCLUDES, but this is discouraged. Change-Id: I39dc53ed98f9e297a5966e723d1936d6ccf2fc8f Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
782 lines
22 KiB
C
782 lines
22 KiB
C
/*
|
|
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include <platform_def.h>
|
|
|
|
#include <arch_helpers.h>
|
|
#include <common/bl_common.h>
|
|
#include <common/debug.h>
|
|
#include <drivers/console.h>
|
|
#include <lib/mmio.h>
|
|
#include <plat/common/platform.h>
|
|
|
|
#include <hi6220.h>
|
|
#include <hi6553.h>
|
|
#include <hisi_sram_map.h>
|
|
|
|
#define ACPU_FREQ_MAX_NUM 5
|
|
#define ACPU_OPP_NUM 7
|
|
|
|
#define ACPU_VALID_VOLTAGE_MAGIC (0x5A5AC5C5)
|
|
|
|
#define ACPU_WAIT_TIMEOUT (200)
|
|
#define ACPU_WAIT_FOR_WFI_TIMOUT (2000)
|
|
#define ACPU_DFS_STATE_CNT (0x10000)
|
|
|
|
struct acpu_dvfs_sram_stru {
|
|
unsigned int magic;
|
|
unsigned int support_freq_num;
|
|
unsigned int support_freq_max;
|
|
unsigned int start_prof;
|
|
unsigned int vol[ACPU_OPP_NUM];
|
|
};
|
|
|
|
struct acpu_volt_cal_para {
|
|
unsigned int freq;
|
|
unsigned int ul_vol;
|
|
unsigned int dl_vol;
|
|
unsigned int core_ref_hpm;
|
|
};
|
|
|
|
struct ddr_volt_cal_para {
|
|
unsigned int freq;
|
|
unsigned int ul_vol;
|
|
unsigned int dl_vol;
|
|
unsigned int ddr_ref_hpm;
|
|
};
|
|
|
|
struct acpu_dvfs_opp_para {
|
|
unsigned int freq;
|
|
unsigned int acpu_clk_profile0;
|
|
unsigned int acpu_clk_profile1;
|
|
unsigned int acpu_vol_profile;
|
|
unsigned int acpu_pll_freq;
|
|
unsigned int acpu_pll_frac;
|
|
};
|
|
|
|
unsigned int efuse_acpu_freq[] = {
|
|
1200000, 1250000, 1300000, 1350000,
|
|
1400000, 1450000, 1500000, 1550000,
|
|
1600000, 1650000, 1700000, 1750000,
|
|
1800000, 1850000, 1900000, 1950000,
|
|
};
|
|
|
|
struct acpu_dvfs_opp_para hi6220_acpu_profile[] = {
|
|
{ 208000, 0x61E5, 0x022, 0x3A, 0x5220102B, 0x05555555 },
|
|
{ 432000, 0x10A6, 0x121, 0x3A, 0x5120102D, 0x10000005 },
|
|
{ 729000, 0x2283, 0x100, 0x4A, 0x51101026, 0x10000005 },
|
|
{ 960000, 0x1211, 0x100, 0x5B, 0x51101032, 0x10000005 },
|
|
{ 1200000, 0x1211, 0x100, 0x6B, 0x5110207D, 0x10000005 },
|
|
{ 1400000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
|
|
{ 1500000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
|
|
};
|
|
|
|
struct acpu_dvfs_opp_para *acpu_dvfs_profile = hi6220_acpu_profile;
|
|
struct acpu_dvfs_sram_stru *acpu_dvfs_sram_buf =
|
|
(struct acpu_dvfs_sram_stru *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
|
|
|
|
static inline void write_reg_mask(uintptr_t addr,
|
|
uint32_t val, uint32_t mask)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = mmio_read_32(addr);
|
|
reg = (reg & ~(mask)) | val;
|
|
mmio_write_32(addr, reg);
|
|
}
|
|
|
|
static inline uint32_t read_reg_mask(uintptr_t addr,
|
|
uint32_t mask, uint32_t offset)
|
|
{
|
|
uint32_t reg;
|
|
|
|
reg = mmio_read_32(addr);
|
|
reg &= (mask << offset);
|
|
return (reg >> offset);
|
|
}
|
|
|
|
static int acpu_dvfs_syspll_cfg(unsigned int prof_id)
|
|
{
|
|
uint32_t reg0 = 0;
|
|
uint32_t count = 0;
|
|
uint32_t clk_div_status = 0;
|
|
|
|
/*
|
|
* step 1:
|
|
* - ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
|
|
* - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
|
|
*/
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x3 << 12, 0x3 << 12);
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 4, 0x1 << 4);
|
|
|
|
/*
|
|
* step 2:
|
|
* - ACPUSYSPLLCFG.acpu_syspll_div_cfg:
|
|
* 208MHz, set to 0x5;
|
|
* 500MHz, set to 0x2;
|
|
* other opps set to 0x1
|
|
*/
|
|
if (prof_id == 0)
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x5 << 0, 0x7 << 0);
|
|
else if (prof_id == 1)
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x2 << 0, 0x7 << 0);
|
|
else
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 0, 0x7 << 0);
|
|
|
|
/*
|
|
* step 3:
|
|
* - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x3;
|
|
* - ACPU_SC_VD_CTRL.tune_en_dif = 0
|
|
* - ACPU_SC_VD_CTRL.tune_en_int = 0
|
|
* - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1
|
|
* - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
|
|
*/
|
|
clk_div_status = 0x3;
|
|
do {
|
|
reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, 20);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: clk div status timeout!\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (clk_div_status != reg0);
|
|
|
|
write_reg_mask(ACPU_SC_VD_CTRL, 0x0, (0x1 << 0) | (0x1 << 11));
|
|
write_reg_mask(PMCTRL_ACPUCLKDIV, 0x1 << 8, 0x3 << 8);
|
|
write_reg_mask(PMCTRL_ACPUPLLSEL, 0x1 << 0, 0x1 << 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void acpu_dvfs_clk_div_cfg(unsigned int prof_id,
|
|
unsigned int *cpuext_cfg,
|
|
unsigned int *acpu_ddr_cfg)
|
|
{
|
|
if (prof_id == 0) {
|
|
write_reg_mask(PMCTRL_ACPUCLKDIV,
|
|
(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
|
|
*cpuext_cfg = 0x1;
|
|
*acpu_ddr_cfg = 0x1;
|
|
} else if (prof_id == 1) {
|
|
write_reg_mask(PMCTRL_ACPUCLKDIV,
|
|
(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
|
|
*cpuext_cfg = 0x1;
|
|
*acpu_ddr_cfg = 0x1;
|
|
} else {
|
|
/* ddr has not been inited */
|
|
write_reg_mask(PMCTRL_ACPUCLKDIV,
|
|
(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x0 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
|
|
(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
|
|
*cpuext_cfg = 0x1;
|
|
*acpu_ddr_cfg = 0x0;
|
|
}
|
|
}
|
|
|
|
static int acpu_dvfs_freq_ascend(unsigned int cur_prof, unsigned int tar_prof)
|
|
{
|
|
unsigned int reg0 = 0;
|
|
unsigned int reg1 = 0;
|
|
unsigned int reg2 = 0;
|
|
unsigned int count = 0;
|
|
unsigned int cpuext_cfg_val = 0;
|
|
unsigned int acpu_ddr_cfg_val = 0;
|
|
int ret = 0;
|
|
|
|
/*
|
|
* step 1:
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
|
|
* - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
|
|
*
|
|
* step 2:
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x5 (208MHz)
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x2 (500MHz)
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x1 (Other OPPs)
|
|
*
|
|
* step 3:
|
|
* - ACPU_SC_CPU_STAT.clk_div_status_vd = 0x3;
|
|
* - ACPU_SC_VD_CTRL.tune_en_dif = 0x0;
|
|
* - ACPU_SC_VD_CTRL.tune_en_int = 0x0;
|
|
* - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1;
|
|
* - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
|
|
*/
|
|
ret = acpu_dvfs_syspll_cfg(cur_prof);
|
|
if (ret)
|
|
return -1;
|
|
|
|
/*
|
|
* step 4:
|
|
* - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
|
|
SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: syspll sw status timeout\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x1);
|
|
|
|
/* Enable VD functionality if > 800MHz */
|
|
if (acpu_dvfs_profile[tar_prof].freq > 800000) {
|
|
|
|
write_reg_mask(ACPU_SC_VD_HPM_CTRL,
|
|
HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
|
|
|
|
/*
|
|
* step 5:
|
|
* - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
|
|
* - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
|
|
*/
|
|
write_reg_mask(ACPU_SC_VD_HPM_CTRL,
|
|
HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
|
|
write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
|
|
ACPU_SC_VD_MASK_PATTERN_VAL,
|
|
ACPU_SC_VD_MASK_PATTERN_MASK);
|
|
|
|
/*
|
|
* step 6:
|
|
* - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
|
|
* - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
|
|
* - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
|
|
* - ACPU_SC_VD_DLY_FIXED_CTRL = 0x1;
|
|
*/
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
|
|
|
|
/*
|
|
* step 7:
|
|
* - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
|
|
* - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
|
|
* - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
|
|
* - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
|
|
*
|
|
* step 8:
|
|
* - ACPU_SC_VD_CTRL.tune = 0x7;
|
|
*/
|
|
write_reg_mask(ACPU_SC_VD_CTRL,
|
|
ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
|
|
ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
|
|
}
|
|
|
|
/* step 9: ACPUPLLCTRL.acpupll_en_cfg = 0x0 */
|
|
write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0,
|
|
0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
|
|
|
|
/* step 10: set PMCTRL_ACPUPLLFREQ and PMCTRL_ACPUPLLFRAC */
|
|
mmio_write_32(PMCTRL_ACPUPLLFREQ,
|
|
acpu_dvfs_profile[tar_prof].acpu_pll_freq);
|
|
mmio_write_32(PMCTRL_ACPUPLLFRAC,
|
|
acpu_dvfs_profile[tar_prof].acpu_pll_frac);
|
|
|
|
/*
|
|
* step 11:
|
|
* - wait for 1us;
|
|
* - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
|
|
*/
|
|
count = 0;
|
|
while (count < ACPU_WAIT_TIMEOUT)
|
|
count++;
|
|
|
|
write_reg_mask(PMCTRL_ACPUPLLCTRL,
|
|
0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
|
|
0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
|
|
|
|
/* step 12: PMCTRL_ACPUVOLPMUADDR = 0x100da */
|
|
mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
|
|
|
|
/*
|
|
* step 13:
|
|
* - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (208MHz);
|
|
* - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (500MHz);
|
|
* - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x20 (798MHz);
|
|
* - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1300MHz);
|
|
* - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1500MHz);
|
|
*/
|
|
write_reg_mask(PMCTRL_ACPUDESTVOL,
|
|
acpu_dvfs_profile[tar_prof].acpu_vol_profile,
|
|
((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
|
|
|
|
/*
|
|
* step 14:
|
|
* - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
|
|
* - Polling ACPUVOLTIMEOUT.acpu_vol_timeout == 0x1
|
|
* - Config PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg
|
|
* - Config ACPUCLKDIV.cpuext_clk_div_cfg;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
|
|
SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
|
|
reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
|
|
SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
|
|
reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
|
|
SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpu destvol cfg timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while ((reg0 != reg1) || (reg2 != 0x1));
|
|
|
|
acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
|
|
|
|
/*
|
|
* step 15:
|
|
* - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
|
|
* - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
|
|
* - ACPUPLLCTRL.acpupll_timeout = 0x1;
|
|
* - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
|
|
SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
|
|
reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
|
|
SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
|
|
reg2 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
|
|
SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpu clk div cfg timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while ((reg1 != cpuext_cfg_val) ||
|
|
(reg0 != acpu_ddr_cfg_val) ||
|
|
(reg2 != 0x1));
|
|
|
|
write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
|
|
0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
|
|
|
|
/*
|
|
* step 16:
|
|
* - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
|
|
* - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
|
|
* - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
|
|
* - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
|
|
SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpu pll sw status timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x1);
|
|
|
|
if (acpu_dvfs_profile[tar_prof].freq > 800000)
|
|
write_reg_mask(ACPU_SC_VD_CTRL,
|
|
ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
|
|
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
|
|
(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
|
|
(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int acpu_dvfs_freq_descend(unsigned int cur_prof, unsigned int tar_prof)
|
|
{
|
|
unsigned int reg0 = 0;
|
|
unsigned int reg1 = 0;
|
|
unsigned int reg2 = 0;
|
|
unsigned int count = 0;
|
|
unsigned int cpuext_cfg_val = 0;
|
|
unsigned int acpu_ddr_cfg_val = 0;
|
|
int ret = 0;
|
|
|
|
ret = acpu_dvfs_syspll_cfg(tar_prof);
|
|
if (ret)
|
|
return -1;
|
|
|
|
/*
|
|
* step 4:
|
|
* - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, 2);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: syspll sw status timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x1);
|
|
|
|
/*
|
|
* Step 5:
|
|
* - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x0
|
|
*/
|
|
write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << 0);
|
|
|
|
/*
|
|
* step 6
|
|
* - Config PMCTRL_ACPUPLLFREQ and ACPUPLLFRAC
|
|
*/
|
|
mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq);
|
|
mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac);
|
|
|
|
/*
|
|
* step 7:
|
|
* - Wait 1us;
|
|
* - Config PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
|
|
*/
|
|
count = 0;
|
|
while (count < ACPU_WAIT_TIMEOUT)
|
|
count++;
|
|
|
|
write_reg_mask(PMCTRL_ACPUPLLCTRL,
|
|
0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
|
|
0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
|
|
|
|
/* Enable VD functionality if > 800MHz */
|
|
if (acpu_dvfs_profile[tar_prof].freq > 800000) {
|
|
|
|
write_reg_mask(ACPU_SC_VD_HPM_CTRL,
|
|
HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
|
|
|
|
/*
|
|
* step 9:
|
|
* - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
|
|
* - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
|
|
*/
|
|
write_reg_mask(ACPU_SC_VD_HPM_CTRL,
|
|
HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
|
|
write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
|
|
ACPU_SC_VD_MASK_PATTERN_VAL,
|
|
ACPU_SC_VD_MASK_PATTERN_MASK);
|
|
|
|
/*
|
|
* step 10:
|
|
* - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
|
|
* - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
|
|
* - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
|
|
* - ACPU_SC_VD_DLY_FIXED_CTRL = 0x1;
|
|
*/
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
|
|
mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
|
|
|
|
/*
|
|
* step 11:
|
|
* - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
|
|
* - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
|
|
* - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
|
|
* - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
|
|
*
|
|
* step 12:
|
|
* - ACPU_SC_VD_CTRL.tune = 0x7;
|
|
*/
|
|
write_reg_mask(ACPU_SC_VD_CTRL,
|
|
ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
|
|
ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
|
|
}
|
|
|
|
/*
|
|
* step 13:
|
|
* - Pollig PMCTRL_ACPUPLLCTRL.acpupll_timeout == 0x1;
|
|
* - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
|
|
SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpupll timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x1);
|
|
|
|
write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
|
|
0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
|
|
|
|
/*
|
|
* step 14:
|
|
* - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
|
|
* - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
|
|
* - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
|
|
SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpupll sw status timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x1);
|
|
|
|
if (acpu_dvfs_profile[tar_prof].freq > 800000)
|
|
write_reg_mask(ACPU_SC_VD_CTRL,
|
|
ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
|
|
|
|
/*
|
|
* step 15:
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
|
|
* - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
|
|
*/
|
|
write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
|
|
(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
|
|
(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
|
|
|
|
/*
|
|
* step 16:
|
|
* - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x0;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3,
|
|
ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: clk div status timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while (reg0 != 0x0);
|
|
|
|
acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
|
|
|
|
/*
|
|
* step 17:
|
|
* - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
|
|
* - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
|
|
* - PMCTRL_ACPUVOLPMUADDR = 0x1006C;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
|
|
SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
|
|
reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
|
|
SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpu clk div cfg timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while ((reg0 != cpuext_cfg_val) || (reg1 != acpu_ddr_cfg_val));
|
|
|
|
mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
|
|
|
|
/*
|
|
* step 16:
|
|
* - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
|
|
* - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
|
|
* - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
|
|
* - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
|
|
* - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
|
|
* - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
|
|
* - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
|
|
*/
|
|
write_reg_mask(PMCTRL_ACPUDESTVOL,
|
|
acpu_dvfs_profile[tar_prof].acpu_vol_profile,
|
|
((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
|
|
|
|
/*
|
|
* step 19:
|
|
* - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
|
|
* - ACPUVOLTIMEOUT.acpu_vol_timeout = 0x1;
|
|
*/
|
|
count = 0;
|
|
do {
|
|
reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
|
|
SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
|
|
reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
|
|
SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
|
|
reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
|
|
SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
|
|
if ((count++) > ACPU_DFS_STATE_CNT) {
|
|
ERROR("%s: acpu destvol cfg timeout.\n", __func__);
|
|
return -1;
|
|
}
|
|
} while ((reg0 != reg1) || (reg2 != 0x1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int acpu_dvfs_target(unsigned int curr_prof, unsigned int target_prof)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (curr_prof == target_prof) {
|
|
INFO("%s: target_prof is equal curr_prof: is %d!\n",
|
|
__func__, curr_prof);
|
|
return 0;
|
|
}
|
|
|
|
if ((curr_prof >= ACPU_FREQ_MAX_NUM) ||
|
|
(target_prof >= ACPU_FREQ_MAX_NUM)) {
|
|
INFO("%s: invalid parameter %d %d\n",
|
|
__func__, curr_prof, target_prof);
|
|
return -1;
|
|
}
|
|
|
|
if (target_prof > acpu_dvfs_sram_buf->support_freq_num)
|
|
target_prof = acpu_dvfs_sram_buf->support_freq_num;
|
|
|
|
if (target_prof < curr_prof)
|
|
ret = acpu_dvfs_freq_descend(curr_prof, target_prof);
|
|
else if (target_prof > curr_prof)
|
|
ret = acpu_dvfs_freq_ascend(curr_prof, target_prof);
|
|
|
|
if (ret) {
|
|
ERROR("%s: acpu_dvfs_target failed!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
/* Complete acpu dvfs setting and set magic number */
|
|
acpu_dvfs_sram_buf->start_prof = target_prof;
|
|
acpu_dvfs_sram_buf->magic = ACPU_VALID_VOLTAGE_MAGIC;
|
|
|
|
mmio_write_32(DDR_DFS_FREQ_ADDR, 800000);
|
|
return 0;
|
|
}
|
|
|
|
static int acpu_dvfs_set_freq(void)
|
|
{
|
|
unsigned int i;
|
|
unsigned int curr_prof;
|
|
unsigned int target_prof;
|
|
unsigned int max_freq = 0;
|
|
|
|
max_freq = acpu_dvfs_sram_buf->support_freq_max;
|
|
|
|
for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) {
|
|
|
|
if (max_freq == hi6220_acpu_profile[i].freq) {
|
|
target_prof = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == acpu_dvfs_sram_buf->support_freq_num) {
|
|
ERROR("%s: cannot found max freq profile\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
curr_prof = 0;
|
|
target_prof = i;
|
|
|
|
/* if max freq is 208MHz, do nothing */
|
|
if (curr_prof == target_prof)
|
|
return 0;
|
|
|
|
if (acpu_dvfs_target(curr_prof, target_prof)) {
|
|
ERROR("%s: set acpu freq failed!", __func__);
|
|
return -1;
|
|
}
|
|
|
|
INFO("%s: support freq num is %d\n",
|
|
__func__, acpu_dvfs_sram_buf->support_freq_num);
|
|
INFO("%s: start prof is 0x%x\n",
|
|
__func__, acpu_dvfs_sram_buf->start_prof);
|
|
INFO("%s: magic is 0x%x\n",
|
|
__func__, acpu_dvfs_sram_buf->magic);
|
|
INFO("%s: voltage:\n", __func__);
|
|
for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++)
|
|
INFO(" - %d: 0x%x\n", i, acpu_dvfs_sram_buf->vol[i]);
|
|
|
|
NOTICE("%s: set acpu freq success!", __func__);
|
|
return 0;
|
|
}
|
|
|
|
struct acpu_dvfs_volt_setting {
|
|
unsigned int magic;
|
|
unsigned int support_freq_num;
|
|
unsigned int support_freq_max;
|
|
unsigned int start_prof;
|
|
unsigned int vol[7];
|
|
unsigned int hmp_dly_threshold[7];
|
|
};
|
|
|
|
static void acpu_dvfs_volt_init(void)
|
|
{
|
|
struct acpu_dvfs_volt_setting *volt;
|
|
|
|
/*
|
|
* - set default voltage;
|
|
* - set pmu address;
|
|
* - set voltage up and down step;
|
|
* - set voltage stable time;
|
|
*/
|
|
mmio_write_32(PMCTRL_ACPUDFTVOL, 0x4a);
|
|
mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0xda);
|
|
mmio_write_32(PMCTRL_ACPUVOLUPSTEP, 0x1);
|
|
mmio_write_32(PMCTRL_ACPUVOLDNSTEP, 0x1);
|
|
mmio_write_32(PMCTRL_ACPUPMUVOLUPTIME, 0x60);
|
|
mmio_write_32(PMCTRL_ACPUPMUVOLDNTIME, 0x60);
|
|
mmio_write_32(PMCTRL_ACPUCLKOFFCFG, 0x1000);
|
|
|
|
volt = (void *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
|
|
volt->magic = 0x5a5ac5c5;
|
|
volt->support_freq_num = 5;
|
|
volt->support_freq_max = 1200000;
|
|
volt->start_prof = 4;
|
|
volt->vol[0] = 0x49;
|
|
volt->vol[1] = 0x49;
|
|
volt->vol[2] = 0x50;
|
|
volt->vol[3] = 0x60;
|
|
volt->vol[4] = 0x78;
|
|
volt->vol[5] = 0x78;
|
|
volt->vol[6] = 0x78;
|
|
|
|
volt->hmp_dly_threshold[0] = 0x0;
|
|
volt->hmp_dly_threshold[1] = 0x0;
|
|
volt->hmp_dly_threshold[2] = 0x0;
|
|
volt->hmp_dly_threshold[3] = 0x0e8b0e45;
|
|
volt->hmp_dly_threshold[4] = 0x10691023;
|
|
volt->hmp_dly_threshold[5] = 0x10691023;
|
|
volt->hmp_dly_threshold[6] = 0x10691023;
|
|
|
|
INFO("%s: success!\n", __func__);
|
|
}
|
|
|
|
void init_acpu_dvfs(void)
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
INFO("%s: pmic version %d\n", __func__,
|
|
mmio_read_8(HI6553_VERSION_REG));
|
|
|
|
/* init parameters */
|
|
mmio_write_32(ACPU_CHIP_MAX_FREQ, efuse_acpu_freq[8]);
|
|
INFO("%s: ACPU_CHIP_MAX_FREQ=0x%x.\n",
|
|
__func__, mmio_read_32(ACPU_CHIP_MAX_FREQ));
|
|
|
|
/* set maximum support frequency to 1.2GHz */
|
|
for (i = 0; i < ACPU_FREQ_MAX_NUM; i++)
|
|
acpu_dvfs_sram_buf->vol[i] = hi6220_acpu_profile[i].acpu_vol_profile;
|
|
|
|
acpu_dvfs_sram_buf->support_freq_num = ACPU_FREQ_MAX_NUM;
|
|
acpu_dvfs_sram_buf->support_freq_max = 1200000;
|
|
|
|
/* init acpu dvfs */
|
|
acpu_dvfs_volt_init();
|
|
acpu_dvfs_set_freq();
|
|
}
|