/* ======================================================================
 *   Copyright (c) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

 /**
 *  \file     Wdg_Platform.c
 *
 */

/* ========================================================================== */
/*                         Include Files                                      */
/* ========================================================================== */
#include "soc.h"
#include "hw_ctrl_core.h"
#include "hal_stdtypes.h"
#include "Wdg_priv.h"

/* ========================================================================== */
/*                         Macros & Typedefs                                  */
/* ========================================================================== */

#define WDG_NUM_RTI_REGS        1U

#define WDG_DWWDPRLD_MULTIPLIER_SHIFT   (13U)

/* Watchdog Triggers */
#define WDG_TRIGGER_FIRST_KEY           ((uint32) 0xE51AU)
#define WDG_TRIGGER_SECOND_KEY          ((uint32) 0xA35CU)
#define WDG_TRIGGER_RESET_KEY           ((uint32) 0x2345U)

/* Digital Watchdog Control */
#define WDG_CTL_ENABLED                 ((uint32) 0xA98559DAU)

#define WDG_STATUS_RESET_VAL            (0xFFU)
/* ========================================================================== */
/*                         Structure Declarations                             */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

#if (WDG_CFG_DEV_ERROR_DETECT == STD_ON)
STATIC FUNC(uint32, WDG_CODE) Wdg_getNumWdg(void);
#endif
STATIC FUNC(void, WDG_CODE) Wdg_setPreload(uint32 baseAddr,
                                           uint32 dwwdPreloadValIn);
STATIC FUNC(void, WDG_CODE) Wdg_setReaction(uint32 baseAddr,
                                            uint32 dwwdReaction);
STATIC FUNC(Std_ReturnType, WDG_CODE) Wdg_windowConfig(uint32 baseAddr,
                                                       uint32 dwwdReaction,
                                                       uint32 dwwdPreloadVal,
                                                       uint32 dwwdWindowSize);
STATIC FUNC(void, WDG_CODE) Wdg_clearStatus(uint32 baseAddr, uint32 status);

/* ========================================================================== */
/*                          Global Variables                                  */
/* ========================================================================== */
#define WDG_START_SEC_CONST_UNSPECIFIED
#include "Wdg_MemMap.h"
static const uint32 Wdg_RTIChannelAddr[WDG_NUM_RTI_REGS] =
{
    SOC_WDG_REG_BASE
};
#define WDG_STOP_SEC_CONST_UNSPECIFIED
#include "Wdg_MemMap.h"

/** @fn void dwdInit(rtiBASE_t* rtiBaseAddr, uint16 dwdPreload)
*   @brief Initialize DWD Expiration Period
*   @param[in] rtidwdBaseAddr - Base address of Watchdog to be configured
*   @param[in] dwdPreload DWD Preload value for expiration time.
*              - Texp = (dwdPreload +1) / RTICLK
*              - n: Divide by n + 1
*
*   This function can be called to set the DWD expiration
*
*/

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
#define WDG_START_SEC_CODE
#include "Wdg_MemMap.h"

#if (WDG_CFG_DEV_ERROR_DETECT == STD_ON)
STATIC FUNC(uint32, WDG_CODE) Wdg_getNumWdg(void)
{
    return (WDG_NUM_RTI_REGS);
}
#endif

STATIC FUNC(void, WDG_CODE) Wdg_clearStatus(uint32 baseAddr, uint32 status)
{

    ((rtiBASE_t*)baseAddr)->WDSTATUS = status;
}

STATIC FUNC(void, WDG_CODE) Wdg_setPreload(uint32 baseAddr,
                                           uint32 dwwdPreloadValIn)
{

   ((rtiBASE_t*)baseAddr)->DWDPRLD = dwwdPreloadValIn;
}

STATIC FUNC(void, WDG_CODE) Wdg_setReaction(uint32 baseAddr,
                                            uint32 dwwdReaction)
{

    /* Configuring Digital Windowed Watchdog Reaction */
    ((rtiBASE_t*)baseAddr)->WWDRXNCTRL  = dwwdReaction;
}

STATIC FUNC(Std_ReturnType, WDG_CODE) Wdg_windowConfig(uint32 baseAddr,
                                                       uint32 dwwdReaction,
                                                       uint32 dwwdPreloadVal,
                                                       uint32 dwwdWindowSize)
{
    Std_ReturnType configStatus;

    if (WDG_CFG_MAX_PRELOAD_VALUE >= dwwdPreloadVal)
    {
        /* Configure window in which watch-dog should be serviced */
        ((rtiBASE_t*)baseAddr)->WWDSIZECTRL = dwwdWindowSize;

        /* Initialize DWD Expiration Period */
        Wdg_setPreload(baseAddr, dwwdPreloadVal);
        /* Configure Digital Windowed Watchdog Reaction */
        Wdg_setReaction(baseAddr, dwwdReaction);

        configStatus = (Std_ReturnType)E_OK;
    }
    else
    {
        configStatus = (Std_ReturnType)E_NOT_OK;
    }

    return (configStatus);
}

/** @fn FUNC(void, WDG_CODE) Wdg_counterEnable(uint32 baseAddr)
*   @brief Enable DWD
*   @param[in] baseAddr - Base address of Watchdog to be configured
*
*   This function will Enable the DWD counter.
*
*/
FUNC(void, WDG_CODE) Wdg_counterEnable(uint32 baseAddr)
{

    /* Enable DWWD by writing pre-defined value '0xA98559DA' to RTIDWDCTRL    */
    ((rtiBASE_t*)baseAddr)->DWDCTRL = WDG_CTL_ENABLED;
}

/** @fn FUNC(uint32, MCU_CODE) Wdg_getWdgBaseAddr(uint16 regNum)
*   @brief Gets the base address of the Watchdog module instance
*   @param[in] regNum - Watchdog Module instances
*
*   This function returns the base address of the Watchdog module instance.
*
*/
FUNC(uint32, MCU_CODE) Wdg_getWdgBaseAddr(uint16 regNum)
{
    uint32 baseAddr;

    baseAddr = Wdg_RTIChannelAddr[regNum];

    return (baseAddr);
}

/** @fn FUNC(uint32, WDG_CODE) Wdg_getCurrentDownCounter(uint32 baseAddr)
*   @brief Get the current DWWD Down Counter
*   @param[in] baseAddr - Base address of Watchdog to be configured
*   @return Current tick of selected compare
*
*   This function will get the current DWWD down counter value.
*
*/
FUNC(uint32, WDG_CODE) Wdg_getCurrentDownCounter(uint32 baseAddr)
{

    return (((rtiBASE_t*)baseAddr)->DWDCNTR);
}

/** @fn FUNC(void, WDG_CODE) Wdg_generateSysReset(uint32 baseAddr)
*   @brief Generate System Reset through DWD
*   @param[in] baseAddr - Base address of Watchdog to be configured
*
*   This function can be called to generate system reset using DWD.
*
*/

FUNC(void, WDG_CODE) Wdg_generateSysReset(uint32 baseAddr)
{

    ((rtiBASE_t*)baseAddr)->WDKEY = WDG_TRIGGER_FIRST_KEY;

    ((rtiBASE_t*)baseAddr)->WDKEY = WDG_TRIGGER_RESET_KEY;
}

/** @fn FUNC(void, WDG_CODE) Wdg_service(uint32 baseAddr)
*   @brief Reset Digital Watchdog
*   @param[in] baseAddr - Base address of Watchdog to be configured
*
*   This function can be called to reset Digital Watchdog.
*
*/
FUNC(void, WDG_CODE) Wdg_service(uint32 baseAddr)
{

    ((rtiBASE_t*)baseAddr)->WDKEY = WDG_TRIGGER_FIRST_KEY;

    ((rtiBASE_t*)baseAddr)->WDKEY = WDG_TRIGGER_SECOND_KEY;
}

/** @fn FUNC(uint32, WDG_CODE) Wdg_getReloadValue(uint32 baseAddr)
*   @brief Returns the Watchdog actual Reload Value
*   @param[in] baseAddr - Base address of Watchdog to be configured
*
*   This function returns the value which is reloaded into the down counter.
*
*/
FUNC(uint32, WDG_CODE) Wdg_getReloadValue(uint32 baseAddr)
{
    uint32 dwwdReloadVal;
    dwwdReloadVal = ((rtiBASE_t*)baseAddr)->DWDPRLD;
    dwwdReloadVal = (dwwdReloadVal + 1U) << WDG_DWWDPRLD_MULTIPLIER_SHIFT;
    return(dwwdReloadVal);
}

/** @fn FUNC(Std_ReturnType, WDG_CODE) Wdg_platformInit(
*       P2CONST(Wdg_ConfigType, AUTOMATIC, WDG_APPL_CONST) ConfigPtr)
*   @brief Initialize the Watchdog module
*   @param[in] ConfigPtr - pointer to the Watchdog configuration
*
*   This function sets the Preload value, Watchdog Window size and Watchdog
*   reaction upon Violation or Expiration.
*
*/
FUNC(Std_ReturnType, WDG_CODE) Wdg_platformInit(
    P2CONST(Wdg_ConfigType, AUTOMATIC, WDG_APPL_CONST) ConfigPtr)
{
    Std_ReturnType status;
    uint32         baseAddr;

#if (WDG_CFG_DEV_ERROR_DETECT == STD_ON)
    if (ConfigPtr->instanceId >= Wdg_getNumWdg())
    {
        (void) Det_ReportError(
            WDG_MODULE_ID, 0, WDG_API_INIT, WDG_E_PARAM_CONFIG);
        status = (Std_ReturnType) E_NOT_OK;
    }
    else
#endif
    {
        if (ConfigPtr->defaultMode == WDGIF_OFF_MODE)
        {
            status = (Std_ReturnType) E_NOT_OK;

        }
        else
        {
        baseAddr = Wdg_getWdgBaseAddr(ConfigPtr->instanceId);

        /* Clear any previous violations */
        Wdg_clearStatus(baseAddr, WDG_STATUS_RESET_VAL);



        if (ConfigPtr->defaultMode == WDGIF_FAST_MODE)
        {
            status = Wdg_windowConfig(baseAddr,
                                      (uint32)ConfigPtr->fastModeCfg.reaction,
                                      ConfigPtr->fastModeCfg.preloadValue,
                                      (uint32)ConfigPtr->fastModeCfg.windowSize);
        }
        else
        {
            /* WDGIF_SLOW_MODE */
            status = Wdg_windowConfig(baseAddr,
                                      (uint32)ConfigPtr->slowModeCfg.reaction,
                                      ConfigPtr->slowModeCfg.preloadValue,
                                      (uint32)ConfigPtr->slowModeCfg.windowSize);
        }

        if ((Std_ReturnType)E_OK == status)
        {
#ifdef  MCAL_DYNAMIC_BUILD            
            (void) regWriteReadback(&toprcmREG->WARM_RESET_CONFIG, M_EIGHTEEN, M_SIXTEEN, 0x0U);            
#else             
            (void) regWriteReadback(&toprcmREG->WARM_RESET_CONFIG, M_EIGHTEEN, M_SIXTEEN, 0x7U);
#endif            
        }
        else
        {
#if (STD_ON == WDG_CFG_DEV_ERROR_DETECT)
            (void)Det_ReportError(WDG_MODULE_ID, 0, WDG_API_INIT,
                                  WDG_E_PARAM_CONFIG);
#endif
            }
        }
    }

    return (status);
}

#if (STD_ON == WDG_CFG_DEV_ERROR_DETECT)
void Wdg_reportDetError(uint8 apiId, uint8 errorId)
{
    (void) Det_ReportError(WDG_MODULE_ID, WDG_INSTANCE_ID, apiId, errorId);
    return;
}
#endif  /* #if (STD_ON == SPI_CFG_DEV_ERROR_DETECT) */

#define WDG_STOP_SEC_CODE
#include "Wdg_MemMap.h"
