mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/device/s5js100_pwrcal.c

480 lines
17 KiB
C

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/
#include "cmsis.h"
unsigned int cal_clk_is_enabled(unsigned int id)
{
return 0;
}
int cal_clk_setrate(unsigned int id, unsigned long rate)
{
unsigned long parents;
unsigned int div;
unsigned int sel;
switch (id) {
case p1_upll:
if (rate == 0) {
modifyreg32(SCMU_PLL_CON0_UPLL, (1 << 4), 0 << 4);
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 31), 0);
} else if ((getreg32(SCMU_PLL_CON0_UPLL) & (1 << 31)) == 0) {
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 31), 1);
while (!(getreg32(SCMU_PLL_CON0_UPLL) & (1 << 29))) {
};
modifyreg32(SCMU_PLL_CON0_UPLL, (1 << 4), 1 << 4);
}
break;
case m1_timer1:
if ((rate >= OSCCLK) || (rate == 0)) {
sel = 0;
} else {
sel = 1;
}
modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER1_CLK, 1, sel);
break;
case m1_timer2:
if ((rate >= OSCCLK) || (rate == 0)) {
sel = 0;
} else {
sel = 1;
}
modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER2_CLK, 1, sel);
break;
case m1_timer3:
if ((rate >= OSCCLK) || (rate == 0)) {
sel = 0;
} else {
sel = 1;
}
modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER3_CLK, 1, sel);
break;
case m1_timer4:
if ((rate >= OSCCLK) || (rate == 0)) {
sel = 0;
} else {
sel = 1;
}
modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER4_CLK, 1, sel);
break;
case m1_timer5:
if ((rate >= OSCCLK) || (rate == 0)) {
sel = 0;
} else {
sel = 1;
}
modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER5_CLK, 1, sel);
break;
case d1_upll_clk_ap:
parents = cal_clk_getrate(p1_upll);
div = (parents + rate - 1) / rate;
if (div > 0xf) {
div = 0xf;
}
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_AP, 0xF, div - 1);
break;
case d1_upll_clk_cp:
parents = cal_clk_getrate(p1_upll);
div = (parents + rate - 1) / rate;
if (div > 0xf) {
div = 0xf;
}
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_CP, 0xF, div - 1);
break;
case d1_upll_clk_mif:
parents = cal_clk_getrate(p1_upll);
div = (parents + rate - 1) / rate;
if (div > 0xf) {
div = 0xf;
}
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_MIF, 0xF, div - 1);
break;
case d1_upll_clk_gnss:
parents = cal_clk_getrate(p1_upll);
div = (parents + rate - 1) / rate;
if (div > 0xf) {
div = 0xf;
}
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_GNSS, 0xF, div - 1);
break;
case d1_acpu_l1:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1f) {
div = 0x1f;
}
modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, 0x1F, div - 1);
break;
case d1_acpu_l2:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1f) {
div = 0x1f;
}
modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, 0x1F << 8, (div - 1) << 8);
break;
case d1_acpu_l3:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1f) {
div = 0x1f;
}
modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, 0x1F << 16, (div - 1) << 16);
break;
case d1_sdio:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x7f) {
div = 0x7f;
}
modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_SDIO_CLK, 0x7F, div - 1);
break;
case d1_spi0:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_SPI0_CLK, 0x1F, div - 1);
break;
case d1_usi0:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_USI0_CLK, 0x1F, div - 1);
break;
case d1_usi1:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_USI1_CLK, 0x1F, div - 1);
break;
case d1_mif_l2:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1f) {
div = 0x1f;
}
modifyreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK, 0x1F << 0, (div - 1) << 0);
break;
case d1_mif_l3:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1f) {
div = 0x1f;
}
modifyreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK, 0x1F << 8, (div - 1) << 8);
break;
case d1_qspi:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_QSPI_CLK, 0x1F, div - 1);
break;
case d1_smc:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_SMC_CLK, 0x1F, div - 1);
break;
case d1_uart0:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART0_CLK, 0x1F, div - 1);
break;
case d1_uart1:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (parents + rate - 1) / rate;
if (div > 0x1F) {
div = 0x1F;
}
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART1_CLK, 0x1F, div - 1);
break;
default:
break;
}
return 0;
}
unsigned long cal_clk_getrate(unsigned int id)
{
unsigned long parents;
unsigned long rate = 0;
unsigned long div;
switch (id) {
case p1_upll:
if (((getreg32(SCMU_PLL_CON0_UPLL) >> 4) & 1) == 0) {
rate = OSCCLK;
} else {
unsigned long p, m, s;
p = (getreg32(SCMU_PLL_CON0_UPLL) >> 8) & 0x3f;
m = (getreg32(SCMU_PLL_CON0_UPLL) >> 16) & 0x3ff;
s = (getreg32(SCMU_PLL_CON0_UPLL) >> 0) & 0x7;
rate = (OSCCLK / p * m) >> s;
}
break;
case m1_timer0:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER0_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case m1_timer1:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER1_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case m1_timer2:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER2_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case m1_timer3:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER3_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case m1_timer4:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER4_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case m1_timer5:
if ((getreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER5_CLK) & 1) == 0) {
rate = OSCCLK;
} else {
rate = SLPCLK_CP;
}
break;
case d1_upll_clk_ap:
parents = cal_clk_getrate(p1_upll);
div = (getreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_AP) & 0xF) + 1;
rate = parents / div;
break;
case d1_upll_clk_cp:
parents = cal_clk_getrate(p1_upll);
div = (getreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_CP) & 0xF) + 1;
rate = parents / div;
break;
case d1_upll_clk_mif:
parents = cal_clk_getrate(p1_upll);
div = (getreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_MIF) & 0xF) + 1;
rate = parents / div;
break;
case d1_upll_clk_gnss:
parents = cal_clk_getrate(p1_upll);
div = (getreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_GNSS) & 0xF) + 1;
rate = parents / div;
break;
case d1_acpu_l1:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (getreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_acpu_l2:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = ((getreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK) >> 8) & 0x1F) + 1;
rate = parents / div;
break;
case d1_acpu_l3:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = ((getreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK) >> 16) & 0x1F) + 1;
rate = parents / div;
break;
case d1_sdio:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (getreg32(ACMU_CLK_CON_DIV_CKDIVA_SDIO_CLK) & 0x7F) + 1;
rate = parents / div;
break;
case d1_spi0:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (getreg32(ACMU_CLK_CON_DIV_CKDIVA_SPI0_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_usi0:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (getreg32(ACMU_CLK_CON_DIV_CKDIVA_USI0_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_usi1:
parents = cal_clk_getrate(d1_upll_clk_ap);
div = (getreg32(ACMU_CLK_CON_DIV_CKDIVA_USI1_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_mif_l2:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = ((getreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK) >> 0) & 0x1F) + 1;
rate = parents / div;
break;
case d1_mif_l3:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = ((getreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK) >> 8) & 0x1F) + 1;
rate = parents / div;
break;
case d1_qspi:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (getreg32(MIFCMU_CLK_CON_DIV_CKDIVF_QSPI_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_smc:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (getreg32(MIFCMU_CLK_CON_DIV_CKDIVF_SMC_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_uart0:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (getreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART0_CLK) & 0x1F) + 1;
rate = parents / div;
break;
case d1_uart1:
parents = cal_clk_getrate(d1_upll_clk_mif);
div = (getreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART1_CLK) & 0x1F) + 1;
rate = parents / div;
break;
default:
break;
}
return rate;
}
int cal_clk_enable(unsigned int id)
{
switch (id) {
case p1_upll:
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 31), 1);
while (!(getreg32(SCMU_PLL_CON0_UPLL) & (1 << 29))) {
};
modifyreg32(SCMU_PLL_CON0_UPLL, (1 << 4), 1 << 4);
break;
default:
break;
}
return 0;
}
int cal_clk_disable(unsigned int id)
{
switch (id) {
case p1_upll:
modifyreg32(SCMU_PLL_CON0_UPLL, (1 << 4), 0 << 4);
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 31), 0);
break;
default:
break;
}
return 0;
}
int cal_init(void)
{
/* disable 0 value setting to reduce binary size */
/* enable UPLL */
modifyreg32(SCMU_PLL_CON0_UPLL, (0x3ff << 16), (0x18c << 16));
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 31), (1 << 31));
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_AP, 0xf, 1);
/* need to fix to 0x1 */
modifyreg32(SCMU_CLK_CON_DIV_CKDIVS_UPLL_CLK_MIF, 0xf, 0x1);
// modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, (0x1f << 0), 0); /* L1 CLK */
// modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, (0x1f << 8), 0); /* L2 CLK */
modifyreg32(ACMU_CLK_CON_DIV_MULTI3_CKDIVA_ACPU_CLK, (0x1f << 16), 1 << 16); /* L3 CLK */
// modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_SDIO_CLK, 0x7f, 0);
modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_SPI0_CLK, 0x1f, 1);
// modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_USI0_CLK, 0x1f, 0);
// modifyreg32(ACMU_CLK_CON_DIV_CKDIVA_USI1_CLK, 0x1f, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER0_CLK, 0x1, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER1_CLK, 0x1, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER2_CLK, 0x1, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER3_CLK, 0x1, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER4_CLK, 0x1, 0);
// modifyreg32(ACMU_CLK_CON_MUX_CKMUXA_TIMER5_CLK, 0x1, 0);
// modifyreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK, (0x1f << 0), 0); /* L2 CLK */
modifyreg32(MIFCMU_CLK_CON_DIV_MULTI2_CKDIVF_MIF_SRC_CLK, (0x1f << 8), 1 << 8); /* L3 CLK */
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_QSPI_CLK, 0x1f, 4); //QSPI_CLK to be 40Mhz as first
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_SMC_CLK, 0x1f, 1);
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART0_CLK, 0x1f, 1);
modifyreg32(MIFCMU_CLK_CON_DIV_CKDIVF_UART1_CLK, 0x1f, 1);
/* wait for UPLL lock */
while (!(getreg32(SCMU_PLL_CON0_UPLL) & (1 << 29))) {
};
modifyreg32(SCMU_PLL_CON0_UPLL, (0x1 << 4), (1 << 4));
#if 0
/* Q-CHANNEL enable */
//modifyreg32(ACMU_AP_ACMU_CONTROLLER_OPTION, (0x3 << 28), (0x3 << 28));
modifyreg32(SCMU_SYS_SCMU_CONTROLLER_OPTION, (0x3 << 28), (0x3 << 28));
modifyreg32(MIFCMU_MIF_MIFCMU_CONTROLLER_OPTION, (0x3 << 28), (0x3 << 28));
/* BUS_FREQ_EN, MIN_FREQ_EN enable */
modifyreg32(ACMU_ACMU_DFSC_CTL, (0x3 << 1), (0x3 << 1));
#endif
/* PDMAC Q-CH workaround */
putreg32(0x4046, ACMU_ACMU_BUS_ACT_MSK);
/* Gate clocks of unused peripherals */
// SDIO HOST
putreg32(0x100000, ACMU_CLK_CON_GAT_GOUT_AP_UID_SDIO_IPCLKPORT_CLK);
putreg32(0x100000, ACMU_CLK_CON_GAT_GOUT_AP_UID_SDIO_IPCLKPORT_L2CLK);
putreg32(0x100000, ACMU_CLK_CON_GAT_GOUT_AP_UID_SDIO_IPCLKPORT_SDIO_HCLK);
// PPMUs
putreg32(0x100000, ACMU_CLK_CON_GAT_GOUT_AP_UID_ABUS_IPCLKPORT_PPMU_L2CLK);
putreg32(0x100000, ACMU_CLK_CON_GAT_GOUT_AP_UID_ABUS_IPCLKPORT_PPMU_L3CLK);
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_MIFBUS_IPCLKPORT_PPMU_ACPU2MIF_L2CLK);
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_MIFBUS_IPCLKPORT_PPMU_ACPU2MIF_L3CLK);
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_MIFBUS_IPCLKPORT_PPMU_MCPU2MIF_L2CLK);
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_MIFBUS_IPCLKPORT_PPMU_MCPU2MIF_L3CLK);
// SMC
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_SMC_IPCLKPORT_CLK);
putreg32(0x100000, MIFCMU_CLK_CON_GAT_GOUT_MIF_UID_SMC_IPCLKPORT_L2CLK);
return 0;
}