423 lines
12 KiB
C
423 lines
12 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 <stdbool.h>
|
|
#include "s1sbp6a.h"
|
|
#include "s1sbp6a_type.h"
|
|
#include "s1sbp6a_cmu.h"
|
|
|
|
void bp6a_cmu_set_mcu_clock_gate_bypass(bool en)
|
|
{
|
|
modifyreg32(&BP_SYSCON->MCU_CLK_GATE, CMU_MCU_CLK_GATE_BYPASS_MASK, CMU_MCU_CLK_GATE_BYPASS(en));
|
|
}
|
|
|
|
void bp6a_cmu_set_mcu_clock_src(cmu_src_clk_t clock)
|
|
{
|
|
modifyreg32(&BP_SYSCON->MCU_CLK_CTRL, CMU_MCU_CLK_CTRL_SEL_MCU_SRC_MASK,
|
|
CMU_MCU_CLK_CTRL_SEL_MCU_SRC(clock));
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_mcu_clock_src(void)
|
|
{
|
|
return (cmu_src_clk_t)(getreg32(&BP_SYSCON->MCU_CLK_CTRL) &
|
|
CMU_MCU_CLK_CTRL_SEL_MCU_SRC_MASK);
|
|
}
|
|
|
|
uint32_t bp6a_get_mcu_src_clock_freq(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->MCU_CLK_CTRL) & CMU_MCU_CLK_CTRL_SEL_MCU_SRC_MASK;
|
|
|
|
if (clk_ctrl == CMU_SRC_CLK_LSOSC) {
|
|
return LSOSC_CLK_FREQ;
|
|
} else if (clk_ctrl == CMU_SRC_CLK_EXT_4M) {
|
|
return EXT_CLK_FREQ;
|
|
} else if (clk_ctrl == CMU_SRC_CLK_HSOSC) {
|
|
return HSOSC_CLK_FREQ;
|
|
} else {
|
|
return EXT_CLK_FREQ * CMU_PLL_AMP_GAIN;
|
|
}
|
|
}
|
|
|
|
void bp6a_cmu_set_peri_clock_src(cmu_src_clk_t clock)
|
|
{
|
|
modifyreg32(&BP_SYSCON->PERI_CLK_CTRL, CMU_PERI_CLK_CTRL_SEL_SRC_MASK,
|
|
CMU_PERI_CLK_CTRL_SEL_SRC(clock));
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_peri_clock_src(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->PERI_CLK_CTRL) & CMU_PERI_CLK_CTRL_SEL_SRC_MASK;
|
|
|
|
if (clk_ctrl == CMU_SRC_CLK_LSOSC) {
|
|
return LSOSC_CLK_FREQ;
|
|
} else if (clk_ctrl == CMU_SRC_CLK_EXT_4M) {
|
|
return EXT_CLK_FREQ;
|
|
} else if (clk_ctrl == CMU_SRC_CLK_HSOSC) {
|
|
return HSOSC_CLK_FREQ;
|
|
} else {
|
|
return EXT_CLK_FREQ * CMU_PLL_AMP_GAIN;
|
|
}
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_afe_con_clock_freq(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->AFE_CLK_CTRL) & CMU_MCU_CLK_CTRL_SEL_MCU_SRC_MASK;
|
|
|
|
if (clk_ctrl == CMU_SRC_CLK_LSOSC) {
|
|
return LSOSC_CLK_FREQ;
|
|
} else if (clk_ctrl == CMU_SRC_CLK_HSOSC) {
|
|
return HSOSC_CLK_FREQ;
|
|
} else {
|
|
return EXT_CLK_FREQ;
|
|
}
|
|
}
|
|
|
|
void bp6a_set_muc_clock_div(uint32_t div)
|
|
{
|
|
modifyreg32(&BP_SYSCON->MCU_CLK_CTRL,
|
|
CMU_MCU_CLK_CTRL_AHBCLK_DIV_MASK |
|
|
CMU_MCU_CLK_CTRL_APBCLK_DIV_MASK |
|
|
CMU_MCU_CLK_CTRL_SRPCLK_DIV_MASK,
|
|
CMU_MCU_CLK_CTRL_AHBCLK_DIV(div) |
|
|
CMU_MCU_CLK_CTRL_APBCLK_DIV(div) |
|
|
CMU_MCU_CLK_CTRL_SRPCLK_DIV(div));
|
|
}
|
|
|
|
void bp6a_cmu_peri_clock_div(uint32_t div)
|
|
{
|
|
modifyreg32(&BP_SYSCON->PERI_CLK_CTRL, CMU_PERI_CLK_CTRL_CLK_DIV_MASK, CMU_PERI_CLK_CTRL_CLK_DIV(div));
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_pri_clock_div(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->PERI_CLK_CTRL);
|
|
|
|
return ((clk_ctrl & CMU_PERI_CLK_CTRL_CLK_DIV_MASK) >> CMU_PERI_CLK_CTRL_CLK_DIV_SHIFT);
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_ahb_clock_div(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->MCU_CLK_CTRL);
|
|
|
|
return ((clk_ctrl & CMU_MCU_CLK_CTRL_AHBCLK_DIV_MASK) & CMU_MCU_CLK_CTRL_AHBCLK_DIV_SHIFT);
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_apb_clock_div(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->MCU_CLK_CTRL);
|
|
|
|
return ((clk_ctrl & CMU_MCU_CLK_CTRL_APBCLK_DIV_MASK) >> CMU_MCU_CLK_CTRL_APBCLK_DIV_SHIFT);
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_srp_clock_div(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
clk_ctrl = getreg32(&BP_SYSCON->MCU_CLK_CTRL);
|
|
|
|
return ((clk_ctrl & CMU_MCU_CLK_CTRL_SRPCLK_DIV_MASK) >> CMU_MCU_CLK_CTRL_SRPCLK_DIV_SHIFT);
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_afe_smp_clock_div(void)
|
|
{
|
|
uint32_t clk_ctrl = 0;
|
|
|
|
clk_ctrl = getreg32(&BP_SYSCON->AFE_CLK_CTRL);
|
|
|
|
return ((clk_ctrl & CMU_AFE_CLK_CTRL_SMP_CLK_DIV_MASK) >> CMU_AFE_CLK_CTRL_SMP_CLK_DIV_SHIFT);
|
|
}
|
|
|
|
int bp6a_cmu_enable_clock(cmu_clock_t clock, bool en)
|
|
{
|
|
|
|
if ((clock < CMU_FCLK_AHBCLK) || (clock >= CMU_CLK_INVALID)) {
|
|
return -1;
|
|
}
|
|
|
|
if (clock <= CMU_WATCHDOG_APBCLK) {
|
|
#ifdef CMU_CTRL_UDMA_C
|
|
if (clock == CMU_UDMAC_AHBCLK) {
|
|
if (en) {
|
|
modifyreg32(&(BP_SYSCON->MCU_CLK_GATE), CMU_MCU_CLK_GATE_UDMAC_ACG_MASK, CMU_MCU_CLK_GATE_UDMAC_ACG(en));
|
|
modifyreg32(&(BP_SYSCON->MCU_CLK_GATE), 0x01 << (clock - CMU_FCLK_AHBCLK), en << (clock - CMU_FCLK_AHBCLK));
|
|
} else {
|
|
modifyreg32(&(BP_SYSCON->MCU_CLK_GATE), 0x01 << (clock - CMU_FCLK_AHBCLK), en << (clock - CMU_FCLK_AHBCLK));
|
|
modifyreg32(&(BP_SYSCON->MCU_CLK_GATE), CMU_MCU_CLK_GATE_UDMAC_ACG_MASK, CMU_MCU_CLK_GATE_UDMAC_ACG(en));
|
|
|
|
}
|
|
} else
|
|
#endif
|
|
modifyreg32(&(BP_SYSCON->MCU_CLK_GATE), 0x01 << (clock - CMU_FCLK_AHBCLK), en << (clock - CMU_FCLK_AHBCLK));
|
|
} else {
|
|
modifyreg32(&(BP_SYSCON->PERI_CLK_GATE), 0x01 << (clock - CMU_UART0_CLK), en << (clock - CMU_UART0_CLK));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bp6a_cmu_set_peri_clock_mux(cmu_clock_t clock, cmu_mux_peri_clock_t mux)
|
|
{
|
|
if ((clock < CMU_UART0_CLK) || (clock >= CMU_CLK_INVALID)) {
|
|
return -1;
|
|
}
|
|
|
|
modifyreg32(&BP_SYSCON->PERI_CLK_MUX, 0x01 << (clock - CMU_UART0_CLK), mux << (clock - CMU_UART0_CLK));
|
|
|
|
return 0;
|
|
}
|
|
|
|
cmu_mux_peri_clock_t CMU_GetClockMux(cmu_clock_t clock)
|
|
{
|
|
uint32_t clk_mux = 0;
|
|
|
|
clk_mux = getreg32(&BP_SYSCON->PERI_CLK_MUX);
|
|
|
|
return (cmu_mux_peri_clock_t)((clk_mux >> (clock - CMU_UART0_CLK)) & 0x01);
|
|
}
|
|
|
|
void bp6a_cmu_set_smp_clock_src(cmu_sel_smp_clk_t clock)
|
|
{
|
|
modifyreg32(&BP_SYSCON->AFE_CLK_CTRL, CMU_AFE_CLK_CTRL_SEL_AFECON32_MASK,
|
|
CMU_AFE_CLK_CTRL_SEL_AFECON32(clock));
|
|
}
|
|
|
|
static void bp6a_cmu_set_hsosc_cal(uint8_t mode, uint8_t cal, uint8_t tol)
|
|
{
|
|
modifyreg32(&BP_SYSCON->HSOSC_CTRL,
|
|
CMU_HOSC_CTRL_MODE_MASK |
|
|
CMU_HOSC_CTRL_CAL_MASK |
|
|
CMU_HOSC_CTRL_TOL_MASK,
|
|
CMU_HOSC_CTRL_MODE(mode) |
|
|
CMU_HOSC_CTRL_CAL(cal) |
|
|
CMU_HOSC_CTRL_TOL(tol));
|
|
}
|
|
|
|
static void bp6a_cmu_set_lsosc_cal(uint8_t mode, uint8_t cal, uint8_t tol)
|
|
{
|
|
modifyreg32(&BP_SYSCON->LSOSC_CTRL,
|
|
CMU_HOSC_CTRL_MODE_MASK |
|
|
CMU_HOSC_CTRL_CAL_MASK |
|
|
CMU_HOSC_CTRL_TOL_MASK,
|
|
CMU_HOSC_CTRL_MODE(mode) |
|
|
CMU_HOSC_CTRL_CAL(cal) |
|
|
CMU_HOSC_CTRL_TOL(tol));
|
|
}
|
|
|
|
static uint32_t bp6a_cmu_get_clock_div(cmu_clock_t clock)
|
|
{
|
|
uint32_t mux;
|
|
switch (clock) {
|
|
case CMU_SAMPLE_CLK_AFTER_DIV:
|
|
return bp6a_cmu_get_afe_con_clock_freq();
|
|
case CMU_SRPCLK_AFTER_DIV:
|
|
return bp6a_cmu_get_srp_clock_div();
|
|
case CMU_AHBCLK_AFTER_DIV:
|
|
return bp6a_cmu_get_ahb_clock_div();
|
|
case CMU_APBCLK_AFTER_DIV:
|
|
return bp6a_cmu_get_apb_clock_div();
|
|
case CMU_PERICLK_AFTER_DIV:
|
|
return bp6a_cmu_get_pri_clock_div();
|
|
case CMU_SRP_SRPCLK:
|
|
return bp6a_cmu_get_srp_clock_div();
|
|
case CMU_FCLK_AHBCLK:
|
|
case CMU_GPIO_AHBCLK:
|
|
case CMU_UDMAC_AHBCLK:
|
|
case CMU_DTRNG_AHBCLK:
|
|
case CMU_AES_AHBCLK:
|
|
case CMU_SRC_AHBCLK:
|
|
case CMU_QSPI_AHBCLK:
|
|
return bp6a_cmu_get_ahb_clock_div();
|
|
case CMU_TIMER0_APBCLK:
|
|
case CMU_TIMER1_APBCLK:
|
|
case CMU_TIMER2_APBCLK:
|
|
case CMU_TIMER3_APBCLK:
|
|
case CMU_TIMER4_APBCLK:
|
|
case CMU_TIMER5_APBCLK:
|
|
case CMU_TIMER6_APBCLK:
|
|
case CMU_PWMTIMER_APBCLK:
|
|
case CMU_DUALTIMER_APBCLK:
|
|
case CMU_WATCHDOG_APBCLK:
|
|
return bp6a_cmu_get_apb_clock_div();
|
|
|
|
case CMU_UART0_CLK:
|
|
case CMU_UART1_CLK:
|
|
case CMU_UART2_CLK:
|
|
case CMU_SPI0_CLK:
|
|
case CMU_SPI1_CLK:
|
|
case CMU_SPI2_CLK:
|
|
case CMU_SPI3_CLK:
|
|
case CMU_SPI4_CLK:
|
|
case CMU_I2C0_CLK:
|
|
case CMU_I2C1_CLK:
|
|
case CMU_I2C2_CLK:
|
|
case CMU_I2C3_CLK:
|
|
case CMU_I2C4_CLK:
|
|
mux = CMU_GetClockMux(clock);
|
|
if (mux == CMU_MUX_MCU_CLK) {
|
|
return bp6a_cmu_get_apb_clock_div();
|
|
} else { //(CMU_MUX_MCU_CLK == CMU_MUX_PERI_CLK)
|
|
return bp6a_cmu_get_pri_clock_div();
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool bp6a_cmu_get_clock_enabled(cmu_clock_t clock)
|
|
{
|
|
if (clock <= CMU_WATCHDOG_APBCLK) {
|
|
return ((getreg32(&BP_SYSCON->MCU_CLK_GATE) >> (clock - CMU_FCLK_AHBCLK)) & 0x01);
|
|
} else {
|
|
return ((getreg32(&BP_SYSCON->PERI_CLK_GATE) >> (clock - CMU_UART0_CLK)) & 0x01);
|
|
}
|
|
}
|
|
|
|
uint32_t bp6a_get_clock_src_freq(cmu_clock_t clock)
|
|
{
|
|
uint32_t mux;
|
|
|
|
switch (clock) {
|
|
case CMU_SAMPLE_CLK_AFTER_DIV:
|
|
return bp6a_cmu_get_afe_con_clock_freq();
|
|
case CMU_SRPCLK_AFTER_DIV:
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
case CMU_AHBCLK_AFTER_DIV:
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
case CMU_APBCLK_AFTER_DIV:
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
|
|
case CMU_PERICLK_AFTER_DIV:
|
|
return bp6a_cmu_get_peri_clock_src();
|
|
case CMU_SRP_SRPCLK:
|
|
if (bp6a_cmu_get_clock_enabled(clock)) {
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
} else {
|
|
return 0;
|
|
}
|
|
case CMU_FCLK_AHBCLK:
|
|
case CMU_GPIO_AHBCLK:
|
|
case CMU_UDMAC_AHBCLK:
|
|
case CMU_DTRNG_AHBCLK:
|
|
case CMU_AES_AHBCLK:
|
|
case CMU_SRC_AHBCLK:
|
|
case CMU_QSPI_AHBCLK:
|
|
if (bp6a_cmu_get_clock_enabled(clock)) {
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
} else {
|
|
return 0;
|
|
}
|
|
case CMU_TIMER0_APBCLK:
|
|
case CMU_TIMER1_APBCLK:
|
|
case CMU_TIMER2_APBCLK:
|
|
case CMU_TIMER3_APBCLK:
|
|
case CMU_TIMER4_APBCLK:
|
|
case CMU_TIMER5_APBCLK:
|
|
case CMU_TIMER6_APBCLK:
|
|
case CMU_PWMTIMER_APBCLK:
|
|
case CMU_DUALTIMER_APBCLK:
|
|
case CMU_WATCHDOG_APBCLK:
|
|
if (bp6a_cmu_get_clock_enabled(clock)) {
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
} else {
|
|
return 0;
|
|
}
|
|
case CMU_UART0_CLK:
|
|
case CMU_UART1_CLK:
|
|
case CMU_UART2_CLK:
|
|
case CMU_SPI0_CLK:
|
|
case CMU_SPI1_CLK:
|
|
case CMU_SPI2_CLK:
|
|
case CMU_SPI3_CLK:
|
|
case CMU_SPI4_CLK:
|
|
case CMU_I2C0_CLK:
|
|
case CMU_I2C1_CLK:
|
|
case CMU_I2C2_CLK:
|
|
case CMU_I2C3_CLK:
|
|
case CMU_I2C4_CLK:
|
|
if (bp6a_cmu_get_clock_enabled(clock)) {
|
|
mux = CMU_GetClockMux(clock);
|
|
if (mux == CMU_MUX_MCU_CLK) {
|
|
return bp6a_get_mcu_src_clock_freq();
|
|
} else { //(CMU_MUX_MCU_CLK == CMU_MUX_PERI_CLK)
|
|
return bp6a_cmu_get_peri_clock_src();
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32_t bp6a_cmu_get_clock_freq(cmu_clock_t clock)
|
|
{
|
|
uint32_t src_clk = 0;
|
|
uint32_t clk_div = 0;
|
|
|
|
if (clock >= CMU_CLK_INVALID) {
|
|
return 0;
|
|
}
|
|
|
|
src_clk = bp6a_get_clock_src_freq(clock);
|
|
clk_div = bp6a_cmu_get_clock_div(clock);
|
|
|
|
if (clk_div == 0) {
|
|
clk_div = 1;
|
|
}
|
|
|
|
return (uint32_t)(src_clk / clk_div);
|
|
}
|
|
|
|
void bp6a_cmu_init(cmu_src_clk_t mcu_clk, cmu_src_clk_t peri_clk)
|
|
{
|
|
int i;
|
|
bp6a_set_muc_clock_div(1);
|
|
bp6a_cmu_set_mcu_clock_src(mcu_clk);
|
|
bp6a_cmu_peri_clock_div(1);
|
|
bp6a_cmu_set_peri_clock_src(peri_clk);
|
|
bp6a_cmu_set_hsosc_cal(1, 0, 0);
|
|
bp6a_cmu_set_lsosc_cal(1, 0, 0);
|
|
bp6a_cmu_set_mcu_clock_gate_bypass(false);
|
|
/* clock gate */
|
|
for (i = CMU_FCLK_AHBCLK ; i < CMU_I2C4_CLK; i++) {
|
|
bp6a_cmu_enable_clock(i, (INIT_CLOCK_CONFIG >> (i - CMU_FCLK_AHBCLK)) & 0x01);
|
|
}
|
|
|
|
/* internal OSC calibration enable */
|
|
modifyreg32(0x4001C60C, 0x2, 0x2);
|
|
modifyreg32(0x4001C610, 0x2, 0x2);
|
|
|
|
/* AFE Clock disable */
|
|
putreg32(0x4001A000, 0);
|
|
modifyreg32(0x4001A000, 0x08, 0x8);
|
|
}
|