/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include "system_M012x.h"
#include "../cpu_drv.h"

/*******************************************************************************
 * the defines
 ******************************************************************************/

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the functions
 ******************************************************************************/
void SystemInit(void)
{
    /* PFLASH prefetch */
    SimReg_SetFlashPFlsFlushEn(SIM, 1); /* Enable Flush PFLASH pre-fetch */
    SimReg_SetFlashPFlsPfbEn(SIM, 1);   /* Enable PFLASH pre-fetch*/
    SimReg_SetFlashPFlsFlushEn(SIM, 0); /* Disable Flush PFLASH prefetch */

    /* Unlock SCG and PCC */
    Scg0Reg_SetKey(SCG0, 0x19962020);
    Pcc0Reg_SetKey(PCC0, 0x55534552);
    RcmReg_SetKey(RCM, 0x52434D4B);

    Scg1Reg_SetCkSrcSysDiv(SCG1, 1); /* Divide-by-2, restore default value */

    /* Switch system clock to default clock */
    if(Scg2Reg_GetCsrSysSt(SCG2) == 2)
    {
        /* Flash AHB bus read access time configure */
        FtfcReg_SetFcnfgBusReadTm(FTFC, 0); /* 1T required */
        Scg2Reg_SetCsrSrcSys(SCG2, 0);
        while(Scg2Reg_GetCsrSysSt(SCG2) != 0)
        {
            ;
        }
    }

#ifdef _USE_EXT_OSC_
    /* Use External oscillator */
    Scg0Reg_SetOscCtrlRange(SCG0, 1);  /* set SOSC frequency range(use max value when SOSC as the clock source of the PLL) */
    Scg0Reg_SetOscCtrlEnSosc(SCG0, 1); /* enable SOSC */
    while(Scg0Reg_GetStatusSoscRdy(SCG0) == 0)
    {
        ; /* wait until SOSC is ready */
    }

    /* Disable PLL and PLL loss reset */
    RcmReg_SetRstCtrlPllLossEn(RCM, 0);
    Scg0Reg_SetPllCtrl0PllEn(SCG0, 0);
    /* PLL configuration:
     * - PLL input clock source : SOSC
     * - PLL pre-divider : 1
     * - feedback divider : 40
     * - PLL OUT DIV : 2
     * - PLL post-divider setting : 2
     */
    Scg0Reg_SetPllCtrl1PllClkinSel(SCG0, 1);
    Scg0Reg_SetPllCtrl0PllPreDiv(SCG0, 0);
    Scg0Reg_SetPllCtrl0PllM(SCG0, 40);
    Scg0Reg_SetPllCtrl0PllOutDiv(SCG0, 1);
    Scg0Reg_SetPllCtrl0PllPosDiv(SCG0, 2);
    /* Enable PLL */
    Scg0Reg_SetPllCtrl0PllEn(SCG0, 1);

    /* Use systick for delay: load:4000-1ms,8000-2ms based on 4M system clk */
    SysTick->LOAD = 8000U;
    SysTick->VAL  = 0U;
    SysTick->CTRL = 5U; /* SysTick uses the processor clock and enable sysTick */
    while(SysTick->CTRL < 0x10000)
    {
        ; /* wait for COUNTFLAG setting*/
    }
    /*recover sysTick register*/
    SysTick->CTRL = 4U;
    SysTick->LOAD = 0U;
    SysTick->VAL  = 0U;

    while(Scg0Reg_GetStatusPllLock(SCG0) == 0)
    {
        ;
    }

    /* Flash AHB bus read access time configure */
    FtfcReg_SetFcnfgBusReadTm(FTFC, 1); /* 2T required for 80M AHB */

    /* Set clk_pll as system clock */
    Scg2Reg_SetCsrSrcSys(SCG2, 2);
    while(Scg2Reg_GetCsrSysSt(SCG2) != 2)
    {
        ;
    }
#else
    /* Disable PLL and PLL loss reset */
    RcmReg_SetRstCtrlPllLossEn(RCM, 0);
    Scg0Reg_SetPllCtrl0PllEn(SCG0, 0);
    /* PLL configuration:
     * - PLL input clock source : SIRC
     * - PLL pre-divider : 1
     * - feedback divider : 40
     * - PLL OUT DIV : 2
     * - PLL post-divider setting : 2
     */
    Scg0Reg_SetPllCtrl1PllClkinSel(SCG0, 0);
    Scg0Reg_SetPllCtrl0PllPreDiv(SCG0, 0);
    Scg0Reg_SetPllCtrl0PllM(SCG0, 40);
    Scg0Reg_SetPllCtrl0PllOutDiv(SCG0, 1);
    Scg0Reg_SetPllCtrl0PllPosDiv(SCG0, 2);
    /* Enable PLL */
    Scg0Reg_SetPllCtrl0PllEn(SCG0, 1);
    while(Scg0Reg_GetStatusPllLock(SCG0) == 0)
    {
        ;
    }

    /* Flash AHB bus read access time configure */
    FtfcReg_SetFcnfgBusReadTm(FTFC, 1); /* 2T required for 80M AHB */

    /* Set clk_pll as system clock */
    Scg2Reg_SetCsrSrcSys(SCG2, 2);
    while(Scg2Reg_GetCsrSysSt(SCG2) != 2)
    {
        ;
    }
#endif

    /* Set Core and APB clock source divider */
    Scg1Reg_SetCkSrcSysDiv(SCG1, 0); /* Divide-by-1 */
    Scg2Reg_SetCsrDivAips(SCG2, 0);  /* Divide-by-1 */
    /* Set FLASH clock, must be 8M */
    Pcc1Reg_SetFlsCtlCntDiv(PCC1, 9); /* Divide-by-10 */

    /* Finish setting up the clock */
    Scg0Reg_SetKey(SCG0, 0); /* lock SCG again */
    Pcc0Reg_SetKey(PCC0, 0); /* lock PCC again */
    RcmReg_SetKey(RCM, 0);   /* lock RCM again */
}
