/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2021. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

/*!
 * @file system_ac7840x.c
 *
 * @brief This file provides system clock config integration functions.
 *
 */

/* PRQA S 0380 EOF */ /* Number of macro definitions exceeds 4095 */
/* PRQA S 0306,0303 EOF */ /* Type conversion. */
/* PRQA S 2889 EOF */ /* More than one 'return'. */
/* PRQA S 3415 EOF */ /* with persistent side effects. */
/* PRQA S 1503,1505,3408 EOF */ /* Is defined but not used. */

/* ===========================================  Includes  =========================================== */
#include "device_register.h"
#if SYSTEM_USE_CKGEN
#include "ckgen_drv.h"
#endif

/* ============================================  Define  ============================================ */
/** @brief Standby retention base address. */
#define SRAM_RETENTION_BASE      (SRAM_U_START_ADDRESS - SRAM_RETENTION_SIZE)

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;  /* System/core clock */

volatile uint8_t s_disIrqReqTimes = 0U;
volatile uint8_t s_disIrqFltTimes = 0U;
/* ====================================  Functions declaration  ===================================== */
/* Externals declaration */
#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
extern uint32_t __Vectors;
#endif

/* ======================================  Functions define  ======================================== */
/*!
 * @brief Initialize SPLL then set system clock to the SPLL clock
 *        (just support SPLL refer clock 4/8/12/16/30MHz, others need to modify).
 *
 * @param[in] refClk: 0: HSI clock, 1: HSE clock
 * @param[in] freq: SPLL out frequency (16 - 120)
 * @return status 0: success others: error
 */
uint32_t SetSysClkToSPLL(uint8_t refClk, uint8_t freq)
{
    uint32_t ret = 0U, status, outFreq = freq;
    uint32_t timeout = 100000U, posdiv, fbkdiv, prediv;

    if (outFreq > 120U)
    {
        outFreq = 120U;
    }
    if (outFreq < 16U)
    {
        outFreq = 16U;
    }

    if (refClk != 0U)
    {
        /* Set XOSC bypass mode */
        MODIFY_REG32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_HSEBYP_Msk, SPM_PWR_MGR_CFG1_XOSC_HSEBYP_Pos, 0U);
        /* XOSC enable */
        SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_HSEEN_Msk);
        do
        {
            status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_RDY_Msk);
            --timeout;
        } while ((0U == status) && (timeout != 0U));

        if (0U == timeout)
        {
            ret = 1U;
        }

        /* SPLL configuration outFreq = (srcFreq / (prediv + 1)) * fbkdiv / (posdiv * 2) */
#if (CKGEN_HSE_FREQ == 30000000U)  /* For HSE frequency 30MHz */
        if (outFreq == 120U)
        {
            posdiv = 5U;
            fbkdiv = 160U;
        }
        else if (outFreq == 96U)
        {
            posdiv = 5U;
            fbkdiv = 128U;
        }
        else if (outFreq == 80U)
        {
            posdiv = 6U;
            fbkdiv = 128U;
        }
        else  /* Output frequency 48MHz */
        {
            posdiv = 10U;
            fbkdiv = 128U;
            outFreq = 48U;
        }
        prediv = 3U;
#elif (CKGEN_HSE_FREQ == 16000000U)  /* For HSE frequency 16MHz */
        if (outFreq > 64U)
        {
            posdiv = 4U;
            fbkdiv = outFreq;
        }
        else if (outFreq > 32U)
        {
            posdiv = 8U;
            fbkdiv = outFreq * 2U;
        }
        else
        {
            posdiv = 16U;
            fbkdiv = outFreq * 4U;
        }
        prediv = 1U;
#elif (CKGEN_HSE_FREQ == 12000000U)  /* For HSE frequency 12MHz */
        if (outFreq > 62U)
        {
            posdiv = 6U;
            fbkdiv = outFreq;
        }
        else if (outFreq > 31U)
        {
            posdiv = 12U;
            fbkdiv = outFreq * 2U;
        }
        else
        {
            posdiv = 24U;
            fbkdiv = outFreq * 4U;
        }
        prediv = 0U;
#elif (CKGEN_HSE_FREQ == 4000000U)  /* For HSE frequency 4MHz */
        if (outFreq > 64U)
        {
            posdiv = 4U;
            fbkdiv = outFreq * 2;
        }
        else if (outFreq > 32U)
        {
            posdiv = 8U;
            fbkdiv = outFreq * 4U;
        }
        else
        {
            posdiv = 16U;
            fbkdiv = outFreq * 8U;
        }
        prediv = 0U;
#else  /* For default HSE 8MHz */
        if (outFreq > 64U)
        {
            posdiv = 4U;
            fbkdiv = outFreq;
        }
        else if (outFreq > 32U)
        {
            posdiv = 8U;
            fbkdiv = outFreq * 2U;
        }
        else
        {
            posdiv = 16U;
            fbkdiv = outFreq * 4U;
        }
        prediv = 0U;
#endif
    }
    else
    {
        /* HSI enable */
        SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_HSI_EN_NORMAL_Msk);
        timeout = 1000U;
        do
        {
            status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_HSI_RDY_Msk);
            --timeout;
        } while ((0U == status) && (timeout != 0U));

        if (0U == timeout)
        {
            ret = 2U;
        }

        /* For HSI 8MHz */
        if (outFreq > 64U)
        {
            posdiv = 4U;
            fbkdiv = outFreq;
        }
        else if (outFreq > 32U)
        {
            posdiv = 8U;
            fbkdiv = outFreq * 2U;
        }
        else
        {
            posdiv = 16U;
            fbkdiv = outFreq * 4U;
        }
        prediv = 0U;
    }

    if (0U == ret)
    {
        CLEAR_BIT32(CKGEN->CTRL, CKGEN_CTRL_LOCK_Msk);
        /* Configure SPLL */
        if (refClk != 0U)
        {
            SET_BIT32(CKGEN->CTRL, CKGEN_CTRL_PLL_REF_SEL_Msk);
        }
        else
        {
            CLEAR_BIT32(CKGEN->CTRL, CKGEN_CTRL_PLL_REF_SEL_Msk);
        }
        MODIFY_REG32(ANA->SPLL_CFG0, ANA_SPLL_CFG0_POSDIV_Msk, ANA_SPLL_CFG0_POSDIV_Pos, posdiv);
        MODIFY_REG32(ANA->SPLL_CFG0, ANA_SPLL_CFG0_FBKDIV_Msk, ANA_SPLL_CFG0_FBKDIV_Pos, fbkdiv);
        MODIFY_REG32(ANA->SPLL_CFG0, ANA_SPLL_CFG0_PREDIV_Msk, ANA_SPLL_CFG0_PREDIV_Pos, prediv);
        MODIFY_REG32(ANA->SPLL_CFG1, ANA_SPLL_CFG1_LD_DLY_SEL_Msk, ANA_SPLL_CFG1_LD_DLY_SEL_Pos, 3U);
        /* SPLL enable */
        SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_SPLL_EN_Msk);
        timeout = 10000U;
        do
        {
            status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_SPLL_RDY_Msk);
            --timeout;
        } while ((0U == status) && (timeout != 0U));

        if (0U == timeout)
        {
            ret = 3U;
        }
    }

    if (0U == ret)
    {
        /* Unlock and set flash clock frequency */
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY1);
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY2);
        MODIFY_REG32(FLASH->CNFG, FLASH_CNFG_CLKFREQ_Msk, FLASH_CNFG_CLKFREQ_Pos, outFreq);
        /* Switch system clock to spll */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos, 3U);
        /* Set divider, default sysdiv is 1 divider and busdiv is 2 divider */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_DIV_Msk, CKGEN_CTRL_SYSCLK_DIV_Pos, 0U);
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_BUS_CLK_DIV_RUN_Msk, CKGEN_CTRL_BUS_CLK_DIV_RUN_Pos, 1U);
        /* Check current system clock */
        if (3U != ((CKGEN->CTRL & CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk) >> CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos))
        {
            ret = 4U;
        }
    }

    return ret;
}

/*!
 * @brief Initialize VHSI then set system clock to the VHSI clock.
 *
 * @param[in] none
 * @return status 0: success others: error
 */
uint32_t SetSysClkToVHSI(void)
{
    uint32_t ret = 0U, status, timeout = 100U;

    /* VHSI enable */
    SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_VHSI_EN_Msk);
    do
    {
        status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_VHSI_RDY_Msk);
         --timeout;
    } while ((0U == status) && (timeout != 0U));

    if (0U == timeout)
    {
        ret = 1U;
    }

    if (0U == ret)
    {
        CLEAR_BIT32(CKGEN->CTRL, CKGEN_CTRL_LOCK_Msk);
        /* Unlock and set flash clock frequency */
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY1);
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY2);
        MODIFY_REG32(FLASH->CNFG, FLASH_CNFG_CLKFREQ_Msk, FLASH_CNFG_CLKFREQ_Pos, 48U);
        /* Switch system clock to vhsi */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos, 0U);
        /* Set divider, default sysdiv is 1 divider and busdiv is 2 divider */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_DIV_Msk, CKGEN_CTRL_SYSCLK_DIV_Pos, 0U);
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_BUS_CLK_DIV_RUN_Msk, CKGEN_CTRL_BUS_CLK_DIV_RUN_Pos, 1U);
        /* Check current system clock */
        if (0U != ((CKGEN->CTRL & CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk) >> CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos))
        {
            ret = 2U;
        }
    }

    return ret;
}

/*!
 * @brief Initialize HSE then set system clock to the HSE clock.
 *
 * @param[in] bypass: 0: disable, 1: enable
 * @return status 0: success others: error
 */
uint32_t SetSysClkToHSE(uint8_t bypass)
{
    uint32_t ret = 0U, status, timeout = 100000U;

    /* Set XOSC bypass mode */
    if (bypass != 0U)
    {
        SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_HSEBYP_Msk);
    }
    else
    {
        CLEAR_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_HSEBYP_Msk);
    }
    /* XOSC enable */
    SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_HSEEN_Msk);
    do
    {
        status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_XOSC_RDY_Msk);
        --timeout;
    } while ((0U == status) && (timeout != 0U));

    if (0U == timeout)
    {
        ret = 1U;
    }

    if (0U == ret)
    {
        CLEAR_BIT32(CKGEN->CTRL, CKGEN_CTRL_LOCK_Msk);
        /* Unlock and set flash clock frequency */
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY1);
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY2);
        MODIFY_REG32(FLASH->CNFG, FLASH_CNFG_CLKFREQ_Msk, FLASH_CNFG_CLKFREQ_Pos, CKGEN_HSE_FREQ / 1000000U);
        /* Switch system clock to hse */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos, 1U);
        /* Set divider, default sysdiv is 1 divider and busdiv is 2 divider */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_DIV_Msk, CKGEN_CTRL_SYSCLK_DIV_Pos, 0U);
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_BUS_CLK_DIV_RUN_Msk, CKGEN_CTRL_BUS_CLK_DIV_RUN_Pos, 1U);
        /* Check current system clock */
        if (1U != ((CKGEN->CTRL & CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk) >> CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos))
        {
            ret = 2U;
        }
    }

    return ret;
}

/*!
 * @brief Initialize HSI then set system clock to the HSI clock.
 *
 * @param[in] none
 * @return status 0: success others: error
 */
uint32_t SetSysClkToHSI(void)
{
    uint32_t ret = 0U, status, timeout = 100U;

    /* HSI enable */
    SET_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_HSI_EN_NORMAL_Msk);
    do
    {
        status = READ_BIT32(SPM->PWR_MGR_CFG1, SPM_PWR_MGR_CFG1_HSI_RDY_Msk);
        --timeout;
    } while ((0U == status) && (timeout != 0U));

    if (0U == timeout)
    {
        ret = 1U;
    }

    if (0U == ret)
    {
        CLEAR_BIT32(CKGEN->CTRL, CKGEN_CTRL_LOCK_Msk);
        /* Unlock and set flash clock frequency */
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY1);
        WRITE_REG32(FLASH->KEYUNLK, FLASH_UNLOCK_KEY2);
        MODIFY_REG32(FLASH->CNFG, FLASH_CNFG_CLKFREQ_Msk, FLASH_CNFG_CLKFREQ_Pos, 8U);
        /* Switch system clock to hsi */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk, CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos, 2U);
        /* Set divider, default sysdiv is 1 divider and busdiv is 2 divider */
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_SYSCLK_DIV_Msk, CKGEN_CTRL_SYSCLK_DIV_Pos, 0U);
        MODIFY_REG32(CKGEN->CTRL, CKGEN_CTRL_BUS_CLK_DIV_RUN_Msk, CKGEN_CTRL_BUS_CLK_DIV_RUN_Pos, 1U);
        /* Check current system clock */
        if (2U != ((CKGEN->CTRL & CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk) >> CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos))
        {
            ret = 2U;
        }
    }

    return ret;
}

/* PRQA S 3408 ++ */
/*!
 * @brief Get MCU CPUID.
 *
 * @param[in] none
 * @return MCU CPUID
 */
uint32_t GetCPUID(void)
{
    return SCB->CPUID;
}
/* PRQA S 3408 -- */

/*!
 * @brief Get UUID from device.
 *
 * @param[out] uuidBuffer: UUID buffer
 * @return none
 */
void GetUUID(uint32_t *uuidBuffer)
{
#define UUID_BASE_ADDRESS  0x00201800U

    uint32_t i;

    if (uuidBuffer != NULL)
    {
        for (i = 0U; i < 4U; i++)
        {
            uuidBuffer[i] = (*(__IO uint32_t *)(UUID_BASE_ADDRESS + (i * 4U)));
        }
    }
}

/*!
 * @brief Setup the microcontroller system. Initialize the System.
 *
 * @param[in] none
 * @return none
 */
void SystemInit(void)
{
    /* Sram L&U ECC read enable */
#if (SRAM_ECC_READ_ENABLE)
    MCM->MLMDR0 |= MCM_MLMDR0_LREEN_Msk | MCM_MLMDR0_UREEN_Msk;
    /* Sram ECC 2bit error reset disable */
#if !(SRAM_ECC_ERR_RST_ENABLE)
    CKGEN->RCM_EN &= ~CKGEN_RCM_EN_ECC2_ERR_RST_EN_Msk;
#endif
#endif

    /* Set CP10 and CP11 Full Access */
#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U)
    SCB->CPACR |= ((3U << (10U * 2U)) | (3U << (11U * 2U)));
#endif

    /* Disable watchdog */
#if (WDG_DISABLE)
#define WDG_UNLOCK_VALUE1      0xE064D987U
#define WDG_UNLOCK_VALUE2      0x868A8478U
    WDG->CNT = (uint32_t)WDG_UNLOCK_VALUE1;
    WDG->CNT = (uint32_t)WDG_UNLOCK_VALUE2;
    WDG->CS0 &= ~WDG_CS0_EN_Msk;
#endif

    /* Relocate vector table */
#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)
    SCB->VTOR = (uint32_t) &__Vectors;
#endif

#if 0//NOT_INIT_SRAM_AFTER_RESET
    /* Clear reset status, user can clear status in main when user need to read the reset status */
    CKGEN->RCM_STATUS |= CKGEN_RCM_STATUS_RST_STATUS_CLR_Msk;
#endif
}

/*!
 * @brief Initialize the SRAM to value.
 *
 * @param[in] Start: Main stack start address.
 * @param[in] End:  Main stack end address.
 * @param[in] Val:  Main stack end address.
 * @return none
 */
/** @brief Initialize RAM from [start] to [end] with [val]. */
static void SystemInitRamInternal(uint32_t Start, uint32_t End, uint32_t Val)
{
    uint32_t Addr = Start;

    while (Addr < End)
    {
        *(__IO uint32_t *)(Addr)      = Val;
        *(__IO uint32_t *)(Addr + 4U) = Val;
        Addr += 8U;
    }
}

/*!
 * @brief Initialize the SRAM to 0 for ECC.
 *
 * @param[in] StackBase: Main stack start address.
 * @param[in] StackEnd:  Main stack end address.
 * @return none
 */
void InitSram(uint32_t StackBase, uint32_t StackEnd)
{
#if NOT_INIT_SRAM_AFTER_RESET
    /* When the status is power on, lvr or standby wakeup, init SRAM */
    if ((0U == (CKGEN->RCM_STATUS & (CKGEN_RCM_STATUS_POR_RST_FLAG_Msk | CKGEN_RCM_STATUS_LVR_RST_FLAG_Msk)))
            && (0U == (SPM->STB_WP_STATUS & 0x1FFFFU)))
    {
        return;
    }
#endif

    /* Initialize SRAM. */
    if (0U == (SPM->STB_WP_STATUS & 0x1FFFFU))  /* POR. */
    {
        SystemInitRamInternal(SRAM_L_START_ADDRESS, StackBase, 0U);
        SystemInitRamInternal(StackEnd, SRAM_U_END_ADDRESS, 0U);
    }
    else /* Standby wakeup skip the retention SRAM. */
    {
        if (StackEnd <= SRAM_RETENTION_BASE)
        { /* Stack locate in SRAM_L but not in retention. */
            SystemInitRamInternal(SRAM_L_START_ADDRESS, StackBase, 0U);
            SystemInitRamInternal(StackEnd, SRAM_RETENTION_BASE, 0U);
            SystemInitRamInternal(SRAM_U_START_ADDRESS, SRAM_U_END_ADDRESS, 0U);
        }
        else if (StackBase >= SRAM_U_START_ADDRESS)
        { /* Stack locate in SRAM_U. */
            SystemInitRamInternal(SRAM_L_START_ADDRESS, SRAM_RETENTION_BASE, 0U);
            SystemInitRamInternal(SRAM_U_START_ADDRESS, StackBase, 0U);
            SystemInitRamInternal(StackEnd, SRAM_U_END_ADDRESS, 0U);
        }
        else if ((StackBase < SRAM_RETENTION_BASE) && (StackEnd > SRAM_RETENTION_BASE))
        { /* Stack location in SRAM_L and retention. */
            SystemInitRamInternal(SRAM_L_START_ADDRESS, StackBase, 0U);
            SystemInitRamInternal(SRAM_U_START_ADDRESS, SRAM_U_END_ADDRESS, 0U);
        }
        else if ((StackBase < SRAM_U_START_ADDRESS) &&  (StackEnd > SRAM_U_START_ADDRESS))
        { /* Stack location in SRAM_U and retention. */
            SystemInitRamInternal(SRAM_L_START_ADDRESS, SRAM_RETENTION_BASE, 0U);
            SystemInitRamInternal(StackEnd, SRAM_U_END_ADDRESS, 0U);
        }
        else
        { /* Stack location in retention fullly. */
            SystemInitRamInternal(SRAM_L_START_ADDRESS, SRAM_RETENTION_BASE, 0U);
            SystemInitRamInternal(SRAM_U_START_ADDRESS, SRAM_U_END_ADDRESS, 0U);
        }
    }

    /* Initialize FlexRAM if not used by CSE. */
    if (READ_BIT32(FLASH->PART, FLASH_PART_EPART_Msk) == FLASH_PART_EPART_Msk)
    {
        SystemInitRamInternal(FLEXRAM_BASE_ADDRESS, (FLEXRAM_BASE_ADDRESS + FLEX_RAM_SIZE), 0U);
    }
}

/*!
 * @brief Update system clock frequence.
 *
 * @param[in] none
 * @return none
 */
void SystemCoreClockUpdate(void)
{
#if SYSTEM_USE_CKGEN
    (void)CKGEN_DRV_GetFreq(CORE_CLK, &SystemCoreClock);
#else
    uint32_t runMode, clkSrc, sysDiv, prediv, fbkdiv, postdiv, srcFreq;

    runMode = SPM->STATUS & SPM_STATUS_CURR_POWER_MODE_Msk;
    if (1U == runMode)  /* VLPR mode */
    {
        sysDiv = (CKGEN->CTRL & CKGEN_CTRL_SYSCLK_DIV_VLPR_Msk) >> CKGEN_CTRL_SYSCLK_DIV_VLPR_Pos;
        srcFreq = CKGEN_HSI_FREQ;
    }
    else  /* RUN mode */
    {
        sysDiv = (CKGEN->CTRL & CKGEN_CTRL_SYSCLK_DIV_Msk) >> CKGEN_CTRL_SYSCLK_DIV_Pos;
        clkSrc = (CKGEN->CTRL & CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Msk) >> CKGEN_CTRL_SYSCLK_SRC_SEL_RUN_Pos;
        switch (clkSrc)
        {
        case 1U:  /* HSE clock, user define */
            srcFreq = CKGEN_HSE_FREQ;
            break;

        case 2U:  /* HSI clock */
            srcFreq = CKGEN_HSI_FREQ;
            break;

        case 3U:  /* SPLL clock */
            prediv = (ANA->SPLL_CFG0 & ANA_SPLL_CFG0_PREDIV_Msk) >> ANA_SPLL_CFG0_PREDIV_Pos;
            fbkdiv = (ANA->SPLL_CFG0 & ANA_SPLL_CFG0_FBKDIV_Msk) >> ANA_SPLL_CFG0_FBKDIV_Pos;
            postdiv = (ANA->SPLL_CFG0 & ANA_SPLL_CFG0_POSDIV_Msk) >> ANA_SPLL_CFG0_POSDIV_Pos;
            /* Get reference clock */
            if (0U == ((CKGEN->CTRL & CKGEN_CTRL_PLL_REF_SEL_Msk) >> CKGEN_CTRL_PLL_REF_SEL_Pos))
            {
                srcFreq = CKGEN_HSI_FREQ;
            }
            else
            {
                srcFreq = CKGEN_HSE_FREQ;
            }
            /* Calculate SPLL frequency */
            if (postdiv != 0U)
            {
                srcFreq = (srcFreq / (prediv + 1U)) * fbkdiv / (postdiv * 2U);
            }
            break;

        default:  /* VHSI clock */
            srcFreq = CKGEN_VHSI_FREQ;
            break;
        }
    }

    SystemCoreClock = srcFreq / (sysDiv + 1U);
#endif
}

/*!
 * @brief Enable NMI, after set pinmux.
 *
 * @param[in] enable: enable state
 * @return none
 */
void EnableNMI(uint8_t enable)
{
    if (enable != 0U)
    {
        SET_BIT32(MCM->MNCR, MCM_MNCR_NMI_EN_Msk);
    }
    else
    {
        CLEAR_BIT32(MCM->MNCR, MCM_MNCR_NMI_EN_Msk);
    }
}

/* =============================================  EOF  ============================================== */
