Newer
Older
mbed-os / targets / TARGET_NUVOTON / TARGET_M2354 / device / StdDriver / src / m2354_dpm.c
@Chun-Chieh Li Chun-Chieh Li on 25 May 2021 12 KB M2354: Support TF-M
/**************************************************************************//**
 * @file     dpm.c
 * @version  V3.00
 * @brief    Debug Protection Mechanism (DPM) driver source file
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NuMicro.h"


/** @addtogroup Standard_Driver Standard Driver
  @{
*/

/** @addtogroup DPM_Driver DPM Driver
  @{
*/

/** @addtogroup DPM_EXPORTED_FUNCTIONS DPM Exported Functions
  @{
*/

/**
  * @brief      Set Debug Disable
  * @param[in]  u32dpm  The pointer of the specified DPM module
  *                     - \ref SECURE_DPM
  *                     - \ref NONSECURE_DPM
  * @return     None
  * @details    This macro sets Secure or Non-secure DPM debug disable.
  *             The debug disable function works after reset (chip reset or pin reset).
  */
void DPM_SetDebugDisable(uint32_t u32dpm)
{
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->CTL = (DPM->CTL & (~DPM_CTL_WVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_CTL_DBGDIS_Msk);
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSCTL = (dpm->NSCTL & (~DPM_NSCTL_WVCODE_Msk)) | (DPM_NSCTL_WVCODE|DPM_NSCTL_DBGDIS_Msk);
    }
}

/**
  * @brief      Set Debug Lock
  * @param[in]  u32dpm  Select DPM module. Valid values are:
  *                     - \ref SECURE_DPM
  *                     - \ref NONSECURE_DPM
  * @return     None
  * @details    This macro sets Secure or Non-secure DPM debug lock.
  *             The debug lock function works after reset (chip reset or pin reset).
  */
void DPM_SetDebugLock(uint32_t u32dpm)
{
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->CTL = (dpm->CTL & (~DPM_CTL_WVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_CTL_LOCK_Msk);
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSCTL = (dpm->NSCTL & (~DPM_NSCTL_WVCODE_Msk)) | (DPM_NSCTL_WVCODE|DPM_NSCTL_LOCK_Msk);
    }
}

/**
  * @brief      Get Debug Disable
  * @param[in]  u32dpm  Select DPM module. Valid values are:
  *                     - \ref SECURE_DPM
  *                     - \ref NONSECURE_DPM
  * @retval     0   Debug is not in disable status
  * @retval     1   Debug is in disable status
  * @details    This macro gets Secure or Non-secure DPM debug disable status.
  *             If Secure debug is disabled, debugger cannot access Secure region and can access Non-secure region only.
  *             If Non-secure debug is disabled, debugger cannot access all Secure and Non-secure region.
  */
uint32_t DPM_GetDebugDisable(uint32_t u32dpm)
{
    uint32_t u32RetVal = 0;
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        u32RetVal = (dpm->STS & DPM_STS_DBGDIS_Msk)>>DPM_STS_DBGDIS_Pos;
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        u32RetVal = (dpm->NSSTS & DPM_NSSTS_DBGDIS_Msk)>>DPM_NSSTS_DBGDIS_Pos;
    }

    return u32RetVal;
}

/**
  * @brief      Get Debug Lock
  * @param[in]  u32dpm  Select DPM module. Valid values are:
  *                     - \ref SECURE_DPM
  *                     - \ref NONSECURE_DPM
  * @retval     0   Debug is not in lock status
  * @retval     1   Debug is in lock status
  * @details    This macro gets Secure or Non-secure DPM debug disable status.
  *             If Secure debug is locked, debugger cannot access Secure region and can access Non-secure region only.
  *             If Non-secure debug is locked, debugger cannot access all Secure and Non-secure region.
  */
uint32_t DPM_GetDebugLock(uint32_t u32dpm)
{
    uint32_t u32RetVal = 0;
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        u32RetVal = (dpm->STS & DPM_STS_LOCK_Msk)>>DPM_STS_LOCK_Pos;
    }
    else                    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        u32RetVal = (dpm->NSSTS & DPM_NSSTS_LOCK_Msk)>>DPM_NSSTS_LOCK_Pos;
    }

    return u32RetVal;
}

/**
  * @brief      Update DPM Password
  * @param[in]  u32dpm        Select DPM module. Valid values are:
  *                           - \ref SECURE_DPM
  *                           - \ref NONSECURE_DPM
  * @param[in]  au32Password  Password length is 256 bits.
  * @retval     0   No password is updated. The password update count has reached the maximum value.
  * @retval     1   Password update is successful.
  * @details    This macro updates Secure or Non-secure DPM password.
  */
uint32_t DPM_SetPasswordUpdate(uint32_t u32dpm, uint32_t au32Pwd[])
{
    uint32_t u32i, u32RetVal=0;
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        /* Set Secure DPM password */
        for(u32i=0; u32i<4; u32i++)
        {
            while(dpm->STS & DPM_STS_BUSY_Msk);
            dpm->SPW[u32i] = au32Pwd[u32i];
        }

        /* Set Secure DPM password update */
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->CTL = (dpm->CTL & (~DPM_CTL_WVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_CTL_PWUPD_Msk);

        /* Check Secure DPM password update flag */
        while(dpm->STS & DPM_STS_BUSY_Msk);
        u32RetVal = (dpm->STS & DPM_STS_PWUOK_Msk)>>DPM_STS_PWUOK_Pos;

        /* Clear Secure DPM password update flag */
        if(u32RetVal) dpm->STS = DPM_STS_PWUOK_Msk;
    }
    else    /* Non-secure DPM */
    {
        /* Set Non-secure DPM password */
        for(u32i=0; u32i<4; u32i++)
        {
            while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
            dpm->NSPW[u32i] = au32Pwd[u32i];
        }

        /* Set Non-secure DPM password update */
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSCTL = (dpm->NSCTL & (~DPM_CTL_WVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_NSCTL_PWUPD_Msk);

        /* Check Non-secure DPM password update flag */
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        u32RetVal = (dpm->NSSTS & DPM_NSSTS_PWUOK_Msk)>>DPM_NSSTS_PWUOK_Pos;

        /* Clear Non-secure DPM password update flag */
        if(u32RetVal) dpm->NSSTS = DPM_NSSTS_PWUOK_Msk;
    }

    return u32RetVal;
}

/**
  * @brief      Compare DPM Password
  * @param[in]  u32dpm  Select DPM module. Valid values are:
  *                     - \ref SECURE_DPM
  *                     - \ref NONSECURE_DPM
  * @retval     0   The password comparison can be proccessed.
  * @retval     1   No more password comparison can be proccessed. \n
  *                 The password comparison fail times has reached the maximum value.
  * @details    This macro sets Secure or Non-secure DPM password comparison. \n
  *             The comparison result is checked by DPM_GetPasswordErrorFlag().
  */
uint32_t DPM_SetPasswordCompare(uint32_t u32dpm, uint32_t au32Pwd[])
{
    uint32_t u32i, u32RetVal=0;
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        /* Check Secure DPM password compare fail times maximum flag */
        while(dpm->STS & DPM_STS_BUSY_Msk);
        if(dpm->STS & DPM_STS_PWFMAX_Msk)
        {
            u32RetVal=1;
        }
        else
        {
            /* Set Secure DPM password */
            for(u32i=0; u32i<4; u32i++)
            {
                while(dpm->STS & DPM_STS_BUSY_Msk);
                dpm->SPW[u32i] = au32Pwd[u32i];
            }

            /* Set Secure DPM password cpmpare */
            while(dpm->STS & DPM_STS_BUSY_Msk);
            dpm->CTL = (dpm->CTL & (~DPM_CTL_WVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_CTL_PWCMP_Msk);
        }
    }
    else    /* Non-secure DPM */
    {
        /* Check Non-secure DPM password compare fail times maximum flag */
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        if(dpm->NSSTS & DPM_NSSTS_PWFMAX_Msk)
        {
            u32RetVal=1;
        }
        else
        {
            /* Set Non-secure DPM password */
            for(u32i=0; u32i<4; u32i++)
            {
                while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
                dpm->NSPW[u32i] = au32Pwd[u32i];
            }

            /* Set Non-secure DPM password compare */
            while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
            dpm->NSCTL = (dpm->NSCTL & (~DPM_NSCTL_WVCODE_Msk)) | (DPM_NSCTL_WVCODE|DPM_NSCTL_PWCMP_Msk);
        }
    }

    return u32RetVal;
}

/**
  * @brief      Get DPM Password Error Flag
  * @param[in]  u32dpm        Select DPM module. Valid values are:
  *                           - \ref SECURE_DPM
  *                           - \ref NONSECURE_DPM
  * @return     Specified DPM module password compare error flag.
  * @details    This macro returns Secure or Non-secure DPM password compare error flag.
  */
uint32_t DPM_GetPasswordErrorFlag(uint32_t u32dpm)
{
    uint32_t u32RetVal=0;
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        /* Check Secure DPM password compare error flag */
        while(dpm->STS & DPM_STS_BUSY_Msk);
        u32RetVal = (dpm->STS & DPM_STS_PWCERR_Msk)>>DPM_STS_PWCERR_Pos;
    }
    else    /* Non-secure DPM */
    {
        /* Check Non-secure DPM password compare error flag */
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        u32RetVal = (dpm->NSSTS & DPM_NSSTS_PWCERR_Msk)>>DPM_NSSTS_PWCERR_Pos;
    }

    return u32RetVal;
}

/**
  * @brief      Get DPM Interrupt Flag
  * @param      None
  * @return     Secure DPM interrupt flag.
  * @details    This macro returns Secure DPM interrupt flag.
  *             Secure DPM interrupt flag includes Secure and Non-secure DPM password compare error flag.
  *             This macro is for Secure DPM and Secure region only.
  */
uint32_t DPM_GetIntFlag(void)
{
    while(DPM->STS & DPM_STS_BUSY_Msk);
    return (DPM->STS & DPM_STS_INT_Msk)>>DPM_STS_INT_Pos;
}


/**
  * @brief      Clear DPM Password Error Flag
  * @param[in]  u32dpm        Select DPM module. Valid values are:
  *                           - \ref SECURE_DPM
  *                           - \ref NONSECURE_DPM
  * @return     Specified DPM module interrupt flag.
  * @details    This macro clears Secure or Non-secure DPM password compare error flag.
  */
void DPM_ClearPasswordErrorFlag(uint32_t u32dpm)
{
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->STS = DPM_STS_PWCERR_Msk;
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSSTS = DPM_NSSTS_PWCERR_Msk;
    }
}

/**
  * @brief      Enable Debugger Write Access
  * @param[in]  u32dpm        Select DPM module. Valid values are:
  *                           - \ref SECURE_DPM
  *                           - \ref NONSECURE_DPM
  * @return     None.
  * @details    This macro enables external debugger to write Secure or Non-secure DPM registers.
  */
void DPM_EnableDebuggerWriteAccess(uint32_t u32dpm)
{
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->CTL = (dpm->CTL & (~(DPM_CTL_RVCODE_Msk|DPM_CTL_DACCWDIS_Msk))) | DPM_CTL_WVCODE;
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSCTL = (dpm->NSCTL & (~(DPM_NSCTL_RVCODE_Msk|DPM_NSCTL_DACCWDIS_Msk))) | DPM_NSCTL_WVCODE;
    }
}

/**
  * @brief      Disable Debugger Write Access
  * @param[in]  u32dpm        Select DPM module. Valid values are:
  *                           - \ref SECURE_DPM
  *                           - \ref NONSECURE_DPM
  * @return     None.
  * @details    This macro disables external debugger to write Secure or Non-secure DPM registers.
  */
void DPM_DisableDebuggerWriteAccess(uint32_t u32dpm)
{
    DPM_T *dpm;

    if(__PC()&NS_OFFSET) dpm = DPM_NS;
    else dpm = DPM;

    if(u32dpm==SECURE_DPM)  /* Secure DPM */
    {
        while(dpm->STS & DPM_STS_BUSY_Msk);
        dpm->CTL = (dpm->CTL & (~DPM_CTL_RVCODE_Msk)) | (DPM_CTL_WVCODE|DPM_CTL_DACCWDIS_Msk);
    }
    else    /* Non-secure DPM */
    {
        while(dpm->NSSTS & DPM_NSSTS_BUSY_Msk);
        dpm->NSCTL = (dpm->NSCTL & (~DPM_NSCTL_RVCODE_Msk)) | (DPM_NSCTL_WVCODE|DPM_NSCTL_DACCWDIS_Msk);
    }
}


/**@}*/ /* end of group DPM_EXPORTED_FUNCTIONS */

/**@}*/ /* end of group DPM_Driver */

/**@}*/ /* end of group Standard_Driver */

/*** (C) COPYRIGHT 2020 Nuvoton Technology Corp. ***/