/***********************************************************************************************************************
 * Copyright [2015-2017] Renesas Electronics Corporation and/or its licensors. All Rights Reserved.
 * 
 * This file is part of Renesas SynergyTM Software Package (SSP)
 *
 * The contents of this file (the "contents") are proprietary and confidential to Renesas Electronics Corporation
 * and/or its licensors ("Renesas") and subject to statutory and contractual protections.
 *
 * This file is subject to a Renesas SSP license agreement. Unless otherwise agreed in an SSP license agreement with
 * Renesas: 1) you may not use, copy, modify, distribute, display, or perform the contents; 2) you may not use any name
 * or mark of Renesas for advertising or publicity purposes or in connection with your use of the contents; 3) RENESAS
 * MAKES NO WARRANTY OR REPRESENTATIONS ABOUT THE SUITABILITY OF THE CONTENTS FOR ANY PURPOSE; THE CONTENTS ARE PROVIDED
 * "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT; AND 4) RENESAS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, OR
 * CONSEQUENTIAL DAMAGES, INCLUDING DAMAGES RESULTING FROM LOSS OF USE, DATA, OR PROJECTS, WHETHER IN AN ACTION OF
 * CONTRACT OR TORT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CONTENTS. Third-party contents
 * included in this file may be subject to different terms.
 **********************************************************************************************************************/
/***********************************************************************************************************************
* File Name    : system_S1JA.c
* Description  : Initializes C runtime environment, system clocks, pins, and interrupts. Calls warm start functions.
***********************************************************************************************************************/

/***********************************************************************************************************************
Includes   <System Includes> , "Project Includes"
***********************************************************************************************************************/
#include "bsp_api.h"
#include "stdlib.h"
#if defined(BSP_MCU_GROUP_S1JA)
#include "r_elc.h"
/* This include file is need only for the 'temporary' fix to insure that the Ioport reference counter is zeroed before it
 * gets referenced. Ioport init is currently called before the C Runtime initialization takes place.
 * It will be removed when a more complete solution for this problem is added.
 */
#include "../../../src/driver/r_ioport/hw/hw_ioport_private.h"

/* BSP Pin Configuration. Allocate BSP pin configuration table in this module. */
#include "bsp_pin_cfg.h"

/***********************************************************************************************************************
Macro definitions
***********************************************************************************************************************/

/***********************************************************************************************************************
Typedef definitions
***********************************************************************************************************************/

/***********************************************************************************************************************
Exported global variables (to be accessed by other files)
***********************************************************************************************************************/
/*LDRA_NOANALYSIS LDRA_INSPECTED below not working. */
/*LDRA_INSPECTED 27 D This variable must be be publicly accessible per the CMSIS standard. It cannot be static. */
uint32_t SystemCoreClock = 0U;  /*!< System Clock Frequency (Core Clock)*/
/*LDRA_ANALYSIS */

#if defined(__GNUC__)
/* Generated by linker. */
/*LDRA_INSPECTED 219 S Linker sections start with underscore. */
extern uint32_t __etext;
/*LDRA_INSPECTED 219 S Linker sections start with underscore. */
extern uint32_t __data_start__;
/*LDRA_INSPECTED 219 S Linker sections start with underscore. */
extern uint32_t __data_end__;
/*LDRA_INSPECTED 219 S Linker sections start with underscore. */
extern uint32_t __bss_start__;
/*LDRA_INSPECTED 219 S Linker sections start with underscore. */
extern uint32_t __bss_end__;
#elif defined(__ICCARM__)
#pragma section=".bss"
#pragma section=".data"
#pragma section=".data_init"
#endif

/* Initialize Static Constructors */
#if defined(__GNUC__)
/*LDRA_INSPECTED 219 S In the GCC compiler, __init_array_start starts with underscore. */
/*LDRA_INSPECTED 219 S */
extern void (*__init_array_start []) (void);
/*LDRA_INSPECTED 219 S In the GCC compiler, __init_array_end starts with underscore. */
/*LDRA_INSPECTED 219 S */
extern void (*__init_array_end []) (void);
#elif defined(__ICCARM__)
extern void __call_ctors(void const *, void const *);
#pragma section = "SHT$$PREINIT_ARRAY" const
#pragma section = "SHT$$INIT_ARRAY" const
#endif

/* IOPORT implementation for this BSP. */
extern const ioport_api_t g_ioport_on_ioport;

/***********************************************************************************************************************
Private global variables and functions
***********************************************************************************************************************/
static void bsp_section_zero(uint8_t * pstart, uint32_t bytes);
static void bsp_section_copy(uint8_t * psource, uint8_t * pdest, uint32_t bytes);
static void bsp_reset_trng_circuit(void);
static void bsp_init_prng(void);

/* ram section to read for prng seed generation */
/*LDRA_INSPECTED 219 S*/
/*LDRA_INSPECTED 57 D*/
/*LDRA_INSPECTED 57 D*/
static volatile uint64_t bsp_seed BSP_PLACE_IN_SECTION_V2(".noinit");

/** Currently this structure is not being used. Eventually it will be tool generated. */
static const elc_cfg_t g_elc_cfg =
{
    .autostart = true,
    .link_count  = 0U,
    .link_list = NULL
};

#if defined(__ICCARM__)
#pragma weak R_BSP_WarmStart
void R_BSP_WarmStart(bsp_warm_start_event_t event);
#elif defined(__GNUC__)
/*LDRA_INSPECTED 293 S - There is no way to implement a weak reference without using a Non ANSI/ISO construct. */
void R_BSP_WarmStart (bsp_warm_start_event_t event) __attribute__ ((weak));
#endif

/***********************************************************************************************************************
* Function Name: SystemCoreClockUpdate
* Description  : Update SystemCoreClock variable based on current clock settings.
* Arguments    : none
* Return Value : none
***********************************************************************************************************************/
void SystemCoreClockUpdate (void)
{
    SystemCoreClock = bsp_cpu_clock_get();
}

/***********************************************************************************************************************
* Function Name: SystemInit
* Description  : Setup MCU.
* Arguments    : none
* Return Value : none
***********************************************************************************************************************/
void SystemInit (void)
{
    /* Call Pre C runtime initialization hook. */
    R_BSP_WarmStart(BSP_WARM_START_PRE_C);

    /* Initialize register protection. */
    bsp_register_protect_open();

    /* Initialize grouped interrupts. */
    bsp_group_interrupt_open();

    /* Initialize FMI. */
    g_fmi_on_fmi.init();

    /* Configure system clocks using CGC module. */
    bsp_clock_init();

    /* To prevent an undesired current draw, this MCU requires a reset of the TRNG circuit subsequent to having the clocks initialized */
    bsp_reset_trng_circuit();

    /* Temporary fix to initialize ioport reference counter to 0, needed before C runtime init. This will be removed
     * in the next release in favor of a more complete solution. */
    HW_IOPORT_Init_Reference_Counter();

    /* Initialize pins. */
    g_ioport_on_ioport.init(&g_bsp_pin_cfg);

    /* Initialize C runtime environment. */
    /* Zero out BSS */
#if defined(__GNUC__)
    bsp_section_zero((uint8_t *)&__bss_start__, ((uint32_t)&__bss_end__ - (uint32_t)&__bss_start__));
#elif defined(__ICCARM__)
    bsp_section_zero((uint8_t *)__section_begin(".bss"), (uint32_t)__section_size(".bss"));
#endif

    /* Copy initialized RAM data from ROM to RAM. */
#if defined(__GNUC__)
    bsp_section_copy((uint8_t *)&__etext,
                     (uint8_t *)&__data_start__,
                     ((uint32_t)&__data_end__ - (uint32_t)&__data_start__));
#elif defined(__ICCARM__)
    bsp_section_copy((uint8_t *)__section_begin(".data_init"),
                     (uint8_t *)__section_begin(".data"),
                     (uint32_t)__section_size(".data"));
    /* Copy functions to be executed from RAM. */
    #pragma section=".code_in_ram"
    #pragma section=".code_in_ram_init"
    bsp_section_copy((uint8_t *)__section_begin(".code_in_ram_init"),
                     (uint8_t *)__section_begin(".code_in_ram"),
                     (uint32_t)__section_size(".code_in_ram"));
    /* Copy main thread TLS to RAM. */
    #pragma section="__DLIB_PERTHREAD_init"
    #pragma section="__DLIB_PERTHREAD"
    bsp_section_copy((uint8_t *)__section_begin("__DLIB_PERTHREAD_init"),
                     (uint8_t *)__section_begin("__DLIB_PERTHREAD"),
                     (uint32_t)__section_size("__DLIB_PERTHREAD_init"));
#endif

#if defined(__IAR_SYSTEMS_ICC__)
    #pragma section=".stack"
#elif defined(__GNUC__)
    /*LDRA_INSPECTED 219 S Linker sections start with underscore. */
    extern uint32_t __StackLimit;
    /*LDRA_INSPECTED 219 S Linker sections start with underscore. */
    extern uint32_t __StackTop;
#endif

    R_SPMON->MSPMPUCTL = (uint16_t) 0x0000;                   /* Disable MSP monitoring  */

    R_SPMON->MSPMPUOAD = 0xA500;                              /* Setup NMI interrupt  */

#if defined(__IAR_SYSTEMS_ICC__)
    R_SPMON->MSPMPUSA = (uint32_t)__section_begin(".stack");   /* Setup start address  */
    R_SPMON->MSPMPUEA = (uint32_t)__section_end(".stack") - 1U;/* Setup end address  */

#elif defined(__GNUC__)
    R_SPMON->MSPMPUSA = (uint32_t)&__StackLimit;               /* Setup start address  */
    R_SPMON->MSPMPUEA = (uint32_t)&__StackTop - 1U;            /* Setup end address  */

#endif

    R_ICU->NMIER |= (uint16_t)0x1000;                          /* Set SPEEN bit to enable NMI on stack monitor exception */
    R_SPMON->MSPMPUCTL = (uint16_t)0x0001;                     /* Enable MSP monitoring  */

    /* Initialize SystemCoreClock variable. */
    SystemCoreClockUpdate();

    /* Call Post C runtime initialization hook. */
    R_BSP_WarmStart(BSP_WARM_START_POST_C);

    /* Initialize Static Constructors */
#if defined(__GNUC__)
    /*LDRA_INSPECTED 219 S In the GCC compiler, __init_array_start and __init_array_end starts with underscore. */
    /*LDRA_INSPECTED 219 S */
    int32_t count = __init_array_end - __init_array_start;
    for (int32_t i = 0; i < count; i++)
    {
        __init_array_start [i]();
    }
#elif defined(__ICCARM__)
    void const * pibase = __section_begin("SHT$$PREINIT_ARRAY");
    void const * ilimit = __section_end("SHT$$INIT_ARRAY");
    __call_ctors(pibase, ilimit);
#endif

    /* Initialize the Hardware locks to 'Unlocked' */
    bsp_init_hardware_locks();

    /* Initialize ELC events that will be used to trigger NVIC interrupts. */
    bsp_irq_cfg();

    /* Initialize ELC. */
    g_elc_on_elc.init(&g_elc_cfg);
    
    /* Initialize the libc pseudo random number generator */
    bsp_init_prng();

    /* Call any BSP specific code. No arguments are needed so NULL is sent. */
    bsp_init(NULL);
}

/***********************************************************************************************************************
* Function Name: bsp_section_zero
* Description  : Zero out input section
* Arguments    : pstart -
*                    Start address of the section
*                bytes -
*                    Size of section in bytes
* Return Value : none
***********************************************************************************************************************/
static void bsp_section_zero (uint8_t * pstart, uint32_t bytes)
{
    while (bytes > 0U)
    {
        bytes--;
        pstart[bytes] = 0U;
    }
}

/***********************************************************************************************************************
* Function Name: bsp_section_copy
* Description  : Zero out input section
* Arguments    : psource -
*                    Address of where to copy data from
*                pdest -
*                    Address of where to copy data to
*                bytes -
*                    Size of section in bytes
* Return Value : none
***********************************************************************************************************************/
static void bsp_section_copy (uint8_t * psource, uint8_t * pdest, uint32_t bytes)
{
    uint32_t index;
    for (index = 0U; index < bytes; index++,pdest++,psource++)
    {
        *pdest = *psource;
    }
}

/***********************************************************************************************************************
* Function Name: R_BSP_WarmStart
* Description  : This function is called at various points during the startup process. This function is declared as a
*                weak symbol higher up in this file because it is meant to be overridden by a user implemented version.
*                One of the main uses for this function is to call functional safety code during the startup process.
*                To use this function just copy this function into your own code and modify it to meet your needs.
* Arguments    : event -
*                    Where at in the start up process the code is currently at
* Return Value : none
***********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_PRE_C == event)
    {
        /* C runtime environment has not been setup so you cannot use globals. System clocks and pins are not setup. */
    }
    else if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment, system clocks, and pins are all setup. */
    }
    else
    {
        /* Unhandled case. */
    }
}

/*******************************************************************************************************************//**
 * @brief Disable trng circuit to prevent unnecessary current draw which may otherwise occur when the Crypto module
 * is not in use.
 *
 **********************************************************************************************************************/
static void bsp_reset_trng_circuit (void)
{
    volatile uint8_t read_port = 0U;
    SSP_PARAMETER_NOT_USED(read_port);   /// Prevent compiler 'unused' warning

    /* Enable TRNG function (disable stop function) */
    R_MSTP->MSTPCRC_b.MSTPC28 = 0U;      ///< TRNG Module Stop needs to be started/stopped for S1 series.

    /* Wait for at least 3 PCLKB cycles */
    read_port = R_PFS->P000PFS_b.PODR;
    read_port = R_PFS->P000PFS_b.PODR;
    read_port = R_PFS->P000PFS_b.PODR;

    /* Disable TRNG function (enable stop function) */
    R_MSTP->MSTPCRC_b.MSTPC28 = 1U;
}

/*******************************************************************************************************************//**
 * @brief Read ram section that has not been initialized and use that value to generate a seed value for the libc PRNG.
 *
 **********************************************************************************************************************/
static void bsp_init_prng(void)
{
    uint64_t temp = (bsp_seed & 0xFFFFFFFF);
    /*initialize srand() with SRAM value*/
    srand( (uint32_t)(temp^(bsp_seed >> 32)) );
    bsp_seed += (0xF4E64FE3A1E75416ULL); //large prime in LE64
    bsp_seed ^= (0xFDAD522B9E92B837ULL); //another large prime in LE64
}

#endif
