/********************************************************************
 *
 * Copyright (C) 2005-2023 On-Bright Electronics Co., Ltd. All rights reserved.
 *
 * SPDX-License-Identifier : BSD 3-Clause license
 *
 * This software component is licensed by On-Bright under BSD 3-Clause license,
 * the "License"; You may not use this file execept in compliance with the
 * License. You may obtain a copy of the License at :
 * https://opensource.org/license/BSD-3-Clause
 *
********************************************************************/

#include <stdint.h>
#include "OB6623P.h"
#include "system_OB6623P.h"
#include "math.h"

// System Clock Type
#define SYS_CLK_TYPE_HIRC       0x00
#define SYS_CLK_TYPE_HIRC_DPLL  0x02

// DPLL Clock Option
#define DPLL_CLK_12M        12000000
#define DPLL_CLK_16M        16000000
#define DPLL_CLK_18M        18000000
#define DPLL_CLK_32M        32000000
#define DPLL_CLK_36M        36000000
#define DPLL_CLK_48M        48000000
#define DPLL_CLK_72M        72000000
// System Clock (Setting by User)
#define DEFAULT_SYS_CLOCK_TYPE  SYS_CLK_TYPE_HIRC_DPLL       // Select system clock type

#define HIRC_FREQ           24000000                    // The HIRC frequence
#define DPLL_FREQ           DPLL_CLK_72M                // The DPLL frequence


#if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC )
    #define DEFAULT_SYS_CLOCK HIRC_FREQ
#elif (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_XTAL)
    #define DEFAULT_SYS_CLOCK XTAL_FREQ
#else
    #define DEFAULT_SYS_CLOCK DPLL_FREQ
#endif

volatile uint32_t SystemCoreClock = DEFAULT_SYS_CLOCK; // Current system core clock.

void SystemInit (void)
{
    // Setting system clock

#if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC)
    OB_SYSCON->CCLKCFG = OB_SYSCON->CCLKCFG & 0xFFFFF0FF;
    while((OB_SYSCON->CPUCHIPCTR0 & 0x00800000) != 0x00800000);     // Wait Ready

#else
    // DPLL Init

    uint32_t nInputSounre = 0;
    uint32_t nDiv_2M = 0;
    volatile uint32_t* pDPLLCT;
    volatile uint32_t* pDPLLDM;

    //-----------------------------------------
    pDPLLDM  = (uint32_t*) 0x50010090;
    pDPLLCT  = (uint32_t*) 0x50010098;
    *pDPLLDM = 0x02;
    *pDPLLCT = (135) | (140 <<16);

    //--------------------force HIRC
    OB_SYSCON->CCLKCFG = OB_SYSCON->CCLKCFG & 0xFFFFF0FF;
    while((OB_SYSCON->CPUCHIPCTR0 & 0x00800000) != 0x00800000);     // Wait Ready

    nInputSounre = 0x01;
    nDiv_2M = (HIRC_FREQ / 2000000) - 1;
    nDiv_2M = (nDiv_2M << 0x04);

    switch (DPLL_FREQ)
    {
    case DPLL_CLK_12M:
        OB_SYSCON->DPLLCON = (0xF0020C00) | ( nDiv_2M) | nInputSounre; // 144/12 = 12M
        break;
    case DPLL_CLK_16M:
        OB_SYSCON->DPLLCON = (0xF0020900) | ( nDiv_2M) | nInputSounre; // 144/9 = 16M
        break;
    case DPLL_CLK_18M:
        OB_SYSCON->DPLLCON = (0xF0020800) | ( nDiv_2M) | nInputSounre; // 144/8 = 18M
        break;
    case DPLL_CLK_32M:
        *pDPLLCT = (151) | (156 <<16);
        OB_SYSCON->DPLLCON = (0xF0040500) | ( nDiv_2M) | nInputSounre; // 160/5 = 32M
        break;
    case DPLL_CLK_36M:
        OB_SYSCON->DPLLCON = (0xF0020400) | ( nDiv_2M) | nInputSounre; // 144/4 = 36M
        break;
    case DPLL_CLK_48M:
        OB_SYSCON->DPLLCON = (0xF0020300) | ( nDiv_2M) | nInputSounre; // 144/3 = 48M
        break;
    case DPLL_CLK_72M:
        OB_SYSCON->DPLLCON = (0xF0020200) | ( nDiv_2M) | nInputSounre; // 144/2 = 72M
        break;
    default:
        OB_SYSCON->DPLLCON = (0xF0020300) | ( nDiv_2M) | nInputSounre; // 144/3 = 48M
        break;
    }

    if (DEFAULT_SYS_CLOCK > 48000000)
        OB_SYSCON->CCLKCFG = OB_SYSCON->CCLKCFG | 0x0800; // CPU Wait 2 Cycle
    else if (DEFAULT_SYS_CLOCK > 24000000)
        OB_SYSCON->CCLKCFG = OB_SYSCON->CCLKCFG | 0x0400; // CPU Wait 1 Cycle

    OB_SYSCON->CCLKCFG = OB_SYSCON->CCLKCFG | 0x0100;
    while((OB_SYSCON->CPUCHIPCTR0 & 0x00400000) != 0x00400000);     // Wait Ready
#endif
}

void SystemCoreClockUpdate (void)
{
    uint32_t nDiv = OB_SYSCON->CCLKCFG & 0x00FF;

    SystemCoreClock = DEFAULT_SYS_CLOCK / (nDiv + 1);
}

uint32_t GetPeripheralClock(void)
{
    
    return SystemCoreClock ;
}

void WaitingCPUReady(void)
{
#if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC)
    while((OB_SYSCON->CPUCHIPCTR0 & 0x00800000) != 0x00800000);     // Wait Ready
#else
    while((OB_SYSCON->CPUCHIPCTR0 & 0x00400000) != 0x00400000);     // Wait Ready
#endif
}
