342 lines
8.5 KiB
C
342 lines
8.5 KiB
C
/*
|
|
* Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include <arch_helpers.h>
|
|
#include <common/debug.h>
|
|
#include <drivers/delay_timer.h>
|
|
|
|
#include <apupwr_clkctl.h>
|
|
#include <apupwr_clkctl_def.h>
|
|
#include <mtk_plat_common.h>
|
|
#include <platform_def.h>
|
|
|
|
/* 8195 use PCW mode to change freq directly */
|
|
enum pll_set_rate_mode PLL_MODE = CON0_PCW;
|
|
|
|
char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = {
|
|
"V_VPU0",
|
|
"V_VPU1",
|
|
"V_MDLA0",
|
|
"V_MDLA1",
|
|
"V_APU_CONN",
|
|
"V_TOP_IOMMU",
|
|
"V_VCORE",
|
|
};
|
|
|
|
uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = {
|
|
APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2,
|
|
APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5,
|
|
APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7
|
|
};
|
|
|
|
uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = {
|
|
APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2,
|
|
APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5,
|
|
APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7
|
|
};
|
|
|
|
struct reg_seq {
|
|
uint32_t address;
|
|
uint32_t val;
|
|
};
|
|
|
|
static const struct reg_seq init_acc_cfg[] = {
|
|
{ APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) },
|
|
{ APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) },
|
|
{ APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) },
|
|
{ APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) },
|
|
{ APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) },
|
|
{ APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) },
|
|
{ APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) },
|
|
{ APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) },
|
|
{ APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) },
|
|
{ APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) },
|
|
};
|
|
|
|
int32_t apupwr_smc_acc_init_all(void)
|
|
{
|
|
int32_t i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) {
|
|
apupwr_writel(init_acc_cfg[i].val,
|
|
init_acc_cfg[i].address);
|
|
}
|
|
|
|
/* Deault ACC will raise APU_DIV_2 */
|
|
apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
|
|
true, V_APU_CONN);
|
|
|
|
apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
|
|
true, V_TOP_IOMMU);
|
|
|
|
apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ,
|
|
true, V_VPU0);
|
|
|
|
apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ,
|
|
true, V_MDLA0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void apupwr_smc_acc_top(bool enable)
|
|
{
|
|
if (enable) {
|
|
apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]);
|
|
apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]);
|
|
} else {
|
|
apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]);
|
|
apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* acc_clk_set_parent:ACC MUX select
|
|
* 0. freq parameters here, only ACC clksrc is valid
|
|
* 1. Switch between APUPLL <=> Parking (F26M, PARK)
|
|
* 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU
|
|
* 3. Clear APU Div2 while Parking
|
|
* 4. Only use clksrc of APUPLL while ACC CG_APU is on
|
|
*/
|
|
int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain)
|
|
{
|
|
uint32_t acc_set = 0;
|
|
uint32_t acc_clr = 0;
|
|
int32_t ret = 0;
|
|
|
|
if (freq > DVFS_FREQ_ACC_APUPLL) {
|
|
ERROR("%s wrong clksrc: %d\n", __func__, freq);
|
|
ret = -EIO;
|
|
goto err;
|
|
}
|
|
|
|
switch (domain) {
|
|
case V_VPU1:
|
|
case V_VPU0:
|
|
case V_MDLA1:
|
|
case V_MDLA0:
|
|
case V_APU_CONN:
|
|
case V_TOP_IOMMU:
|
|
acc_set = aacc_set[domain];
|
|
acc_clr = aacc_clr[domain];
|
|
break;
|
|
default:
|
|
ret = -EIO;
|
|
break;
|
|
}
|
|
|
|
/* Select park source */
|
|
switch (freq) {
|
|
case DVFS_FREQ_ACC_PARKING:
|
|
/* Select park source */
|
|
apupwr_writel(BIT(BIT_SEL_PARK), acc_set);
|
|
apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
|
|
/* Enable park cg */
|
|
apupwr_writel(BIT(BIT_CGEN_PARK), acc_set);
|
|
apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr);
|
|
/* Select park path */
|
|
apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
|
|
/* clear apu div 2 */
|
|
apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
|
|
break;
|
|
|
|
case DVFS_FREQ_ACC_APUPLL:
|
|
/* Select park path */
|
|
apupwr_writel(BIT(BIT_SEL_APU), acc_set);
|
|
/* Clear park cg */
|
|
apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) |
|
|
BIT(BIT_CGEN_SOC), acc_clr);
|
|
break;
|
|
|
|
case DVFS_FREQ_ACC_SOC:
|
|
/* Select park source */
|
|
apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
|
|
apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
|
|
/* Enable park cg */
|
|
apupwr_writel(BIT(BIT_CGEN_SOC), acc_set);
|
|
apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr);
|
|
/* Select park path */
|
|
apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
|
|
/* clear apu div 2 */
|
|
apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
|
|
break;
|
|
|
|
case DVFS_FREQ_ACC_26M:
|
|
case DVFS_FREQ_NOT_SUPPORT:
|
|
default:
|
|
/* Select park source */
|
|
apupwr_writel(BIT(BIT_SEL_F26M), acc_set);
|
|
apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
|
|
/* Enable park cg */
|
|
apupwr_writel(BIT(BIT_CGEN_F26M), acc_set);
|
|
apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr);
|
|
/* Select park path */
|
|
apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
|
|
/* clear apu div 2 */
|
|
apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
|
|
ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n",
|
|
__func__, freq);
|
|
break;
|
|
}
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain)
|
|
{
|
|
int32_t ret = 0;
|
|
uint32_t acc_set0 = 0, acc_set1 = 0;
|
|
|
|
if (freq > DVFS_FREQ_MAX) {
|
|
ERROR("%s wrong freq: %d\n", __func__, freq);
|
|
ret = -EIO;
|
|
goto err;
|
|
}
|
|
|
|
/*
|
|
* Switch to Parking src
|
|
* 1. Need to switch out all ACCs sharing the same apupll
|
|
*/
|
|
switch (domain) {
|
|
case V_MDLA0:
|
|
case V_MDLA1:
|
|
acc_set0 = APU_ACC_CONFG_SET4;
|
|
acc_set1 = APU_ACC_CONFG_SET5;
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_MDLA0);
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_MDLA1);
|
|
break;
|
|
case V_VPU0:
|
|
case V_VPU1:
|
|
acc_set0 = APU_ACC_CONFG_SET1;
|
|
acc_set1 = APU_ACC_CONFG_SET2;
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_VPU0);
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_VPU1);
|
|
break;
|
|
case V_APU_CONN:
|
|
acc_set0 = APU_ACC_CONFG_SET0;
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_APU_CONN);
|
|
break;
|
|
case V_TOP_IOMMU:
|
|
acc_set0 = APU_ACC_CONFG_SET7;
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
|
|
V_TOP_IOMMU);
|
|
break;
|
|
default:
|
|
ERROR("[APUPWR] %s %d invalid domain (%d)\n",
|
|
__func__, __LINE__, domain);
|
|
ret = -EIO;
|
|
goto err;
|
|
}
|
|
|
|
anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq);
|
|
|
|
if (div2) {
|
|
apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0);
|
|
if (acc_set1) {
|
|
apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Switch back to APUPLL
|
|
* Only switch back to APUPLL while CG_APU on
|
|
* And clksrc is not APUPLL
|
|
*/
|
|
switch (domain) {
|
|
case V_VPU0:
|
|
case V_VPU1:
|
|
if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
|
|
!(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
|
|
V_VPU0);
|
|
}
|
|
if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
|
|
!(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
|
|
V_VPU1);
|
|
}
|
|
break;
|
|
case V_MDLA0:
|
|
case V_MDLA1:
|
|
if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
|
|
!(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
|
|
V_MDLA0);
|
|
}
|
|
if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
|
|
!(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
|
|
V_MDLA1);
|
|
}
|
|
break;
|
|
case V_APU_CONN:
|
|
case V_TOP_IOMMU:
|
|
if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
|
|
!(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
|
|
ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
|
|
domain);
|
|
}
|
|
break;
|
|
default:
|
|
ERROR("[APUPWR] %s %d invalid domain (%d)\n",
|
|
__func__, __LINE__, domain);
|
|
ret = -EIO;
|
|
break;
|
|
}
|
|
INFO("[%s][%d] set domain %d to freq %d\n",
|
|
__func__, __LINE__, domain, (div2) ? (freq * 2) : freq);
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
int32_t apupwr_smc_bulk_pll(bool enable)
|
|
{
|
|
int32_t ret = 0;
|
|
int32_t pll_idx;
|
|
|
|
if (enable) {
|
|
for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) {
|
|
ret = apu_pll_enable(pll_idx, enable, false);
|
|
if (ret != 0) {
|
|
goto err;
|
|
}
|
|
}
|
|
} else {
|
|
for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) {
|
|
ret = apu_pll_enable(pll_idx, enable, false);
|
|
if (ret != 0) {
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
void apupwr_smc_bus_prot_cg_on(void)
|
|
{
|
|
apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0);
|
|
}
|