/* SPDX-License-Identifier: Apache-2.0 */
/******************************************************************************/
/**                                                                           */
/** RK0 - The Embedded Real-Time Kernel '0'                                   */
/** (C) 2026 Antonio Giacomelli <dev@kernel0.org>                             */
/**                                                                           */
/** VERSION: V0.60.0                                                          */
/**                                                                           */
/** You may obtain a copy of the License at :                                 */
/** http://www.apache.org/licenses/LICENSE-2.0                                */
/**                                                                           */
/******************************************************************************/

#include <kcoredefs.h>

#if (RK_CONF_SYSCORECLK == 0)
/* CMSIS-Core exports SystemCoreClock when RK_CONF_SYSCORECLK is zero */
extern unsigned long int SystemCoreClock;
unsigned long RK_gSysCoreClock = 0;
#else
unsigned long RK_gSysCoreClock = RK_CONF_SYSCORECLK;
#endif

#ifdef RK_CONF_SYSTICK_DIV
unsigned long RK_gSyTickDiv = RK_CONF_SYSTICK_DIV;
#else
unsigned long RK_gSyTickDiv = 0;
#endif

static inline unsigned kCoreSysTickConfig_(unsigned ticks)
{
    /* check if number of ticks is valid (24-bit reload) */
    if ((ticks - 1U) > 0xFFFFFFUL)
    {
        return (0xFFFFFFFF);
    }

#if (RK_CONF_SYSCORECLK == 0)
    if (RK_gSysCoreClock == 0)
    {
        RK_gSysCoreClock = SystemCoreClock;
    }
#endif

    /* Set reload register */
    RK_REG_SYSTICK_LOAD = (ticks - 1U);

    /* Reset the SysTick counter */
    RK_REG_SYSTICK_VAL = 0;

    RK_REG_SYSTICK_CTRL = 0x06; /* keep interrupt disabled */

#ifndef RK_CONF_SYSTICK_DIV

    RK_gSysTickInterval = (ticks * 1000UL) / (RK_gSysCoreClock);

#else

    RK_gSysTickInterval = 1000UL / RK_CONF_SYSTICK_DIV;

#endif

    return (0);
}


static inline void kCoreSetInterruptPriority_(int IRQn, unsigned priority)
{
    unsigned char prio = (unsigned char)((priority & 0xFU) << 4);

    if (IRQn < 0)
    {
        volatile unsigned char *shp =
            (volatile unsigned char *)(RK_CORE_SCB_BASE + 0x18U);
        unsigned offset = (((unsigned)IRQn) & 0xFU) - 4U;
        shp[offset] = prio;
    }
    else
    {
        volatile unsigned char *ip =
            (volatile unsigned char *)(RK_CORE_NVIC_BASE + 0x300U);
        ip[IRQn] = prio;
    }
}


void kCoreInit(void)
{
    unsigned long refClk =
#if (RK_CONF_SYSCORECLK == 0)
        (RK_gSysCoreClock ? RK_gSysCoreClock : SystemCoreClock);
#else
        RK_gSysCoreClock;
#endif

    kCoreSysTickConfig_(refClk / RK_CONF_SYSTICK_DIV);
    kCoreSetInterruptPriority_(RK_CORE_SVC_IRQN, 0x05);
    kCoreSetInterruptPriority_(RK_CORE_SYSTICK_IRQN, 0x06);
    kCoreSetInterruptPriority_(RK_CORE_PENDSV_IRQN, 0x07);
}
