Newer
Older
mbed-os / targets / TARGET_Samsung / TARGET_SIDK_S1SBP6A / device / s1sbp6a_cmu.c
@Heuisam Kwag Heuisam Kwag on 11 Aug 2020 12 KB introduce S1SBP6A
/****************************************************************************
 *
 * 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);
}