Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_syslib.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 14 KB Fix file modes.
/***************************************************************************//**
* \file cy_syslib.c
* \version 2.90
*
*  Description:
*   Provides system API implementation for the SysLib driver.
*
********************************************************************************
* Copyright 2016-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_M33SYSCPUSS) || defined (CY_IP_M4CPUSS)

#include "cy_syslib.h"

#ifdef CY_IP_M4CPUSS
#include "cy_ipc_drv.h"
#endif
#if !defined(NDEBUG)
    #include <string.h>
#endif /* NDEBUG */

#if defined (CY_DEVICE_SECURE)
#include "cy_pra.h"
#endif /* defined (CY_DEVICE_SECURE) */

#ifdef CY_IP_M4CPUSS
/* Flash wait states (ULP mode at 0.9v) */
#define CY_SYSLIB_FLASH_ULP_WS_0_FREQ_MAX    ( 16UL)
#define CY_SYSLIB_FLASH_ULP_WS_1_FREQ_MAX    ( 33UL)
#define CY_SYSLIB_FLASH_ULP_WS_2_FREQ_MAX    ( 50UL)

/* ROM and SRAM wait states for the slow clock domain (LP mode at 1.1v) */
#define CY_SYSLIB_LP_SLOW_WS_0_FREQ_MAX      (100UL)
#define CY_SYSLIB_LP_SLOW_WS_1_FREQ_MAX      (120UL)

/* ROM and SRAM wait states for the slow clock domain (ULP mode at 0.9v) */
#define CY_SYSLIB_ULP_SLOW_WS_0_FREQ_MAX     ( 25UL)
#define CY_SYSLIB_ULP_SLOW_WS_1_FREQ_MAX     ( 50UL)
#elif CY_IP_M33SYSCPUSS
/* These definitions can be removed once SystemCorClockUpdate() function is implemented */
#define CY_SYSCLK_IMO_FREQ          (8000000UL) /* Hz */
#define CY_DELAY_1K_THRESHOLD           (1000u)
#define CY_DELAY_1K_MINUS_1_THRESHOLD   (CY_DELAY_1K_THRESHOLD - 1u)
#define CY_DELAY_1M_THRESHOLD           (1000000u)
#define CY_DELAY_1M_MINUS_1_THRESHOLD   (CY_DELAY_1M_THRESHOLD - 1u)
#define CY_DELAY_MS_OVERFLOW_THRESHOLD  (0x8000u)

#endif

#if defined (CY_IP_MXS40SRSS)
/* RESET_CAUSE2 macro for CAT1A devices */
#define CY_SRSS_RES_CAUSE2_CSV_LOSS_Msk    (SRSS_RES_CAUSE2_RESET_CSV_HF_LOSS_Msk)
#define CY_SRSS_RES_CAUSE2_CSV_LOSS_Pos    (SRSS_RES_CAUSE2_RESET_CSV_HF_LOSS_Pos)
#define CY_SRSS_RES_CAUSE2_CSV_ERROR_Msk    (SRSS_RES_CAUSE2_RESET_CSV_HF_FREQ_Msk)
#define CY_SRSS_RES_CAUSE2_CSV_ERROR_Pos    (SRSS_RES_CAUSE2_RESET_CSV_HF_FREQ_Pos)
#endif

#if  defined (CY_IP_MXS40SSRSS) || defined (CY_IP_MXS28SRSS)
/* RESET_CAUSE2 macro for CAT1B devices */
#define CY_SRSS_RES_CAUSE2_CSV_LOSS_Msk    (SRSS_RES_CAUSE2_RESET_CSV_HF_Msk)
#define CY_SRSS_RES_CAUSE2_CSV_LOSS_Pos    (SRSS_RES_CAUSE2_RESET_CSV_HF_Pos)
#define CY_SRSS_RES_CAUSE2_CSV_ERROR_Msk    (SRSS_RES_CAUSE2_RESET_CSV_REF_Msk)
#define CY_SRSS_RES_CAUSE2_CSV_ERROR_Pos    (SRSS_RES_CAUSE2_RESET_CSV_REF_Pos)
#endif


#if !defined(NDEBUG)
    CY_NOINIT char_t cy_assertFileName[CY_MAX_FILE_NAME_SIZE];
    CY_NOINIT uint32_t cy_assertLine;
#endif /* NDEBUG */

#if (CY_ARM_FAULT_DEBUG == CY_ARM_FAULT_DEBUG_ENABLED)
    CY_NOINIT cy_stc_fault_frame_t cy_faultFrame;
#endif /* (CY_ARM_FAULT_DEBUG == CY_ARM_FAULT_DEBUG_ENABLED) */

#if defined(__ARMCC_VERSION)
        #if (__ARMCC_VERSION >= 6010050)
            static void Cy_SysLib_AsmInfiniteLoop(void) { __ASM (" b . "); };
        #else
            static __ASM void Cy_SysLib_AsmInfiniteLoop(void) { b . };
        #endif /* (__ARMCC_VERSION >= 6010050) */
#endif  /* (__ARMCC_VERSION) */


void Cy_SysLib_Delay(uint32_t milliseconds)
{
    while(milliseconds > CY_DELAY_MS_OVERFLOW)
    {
        /* This loop prevents an overflow in value passed to Cy_SysLib_DelayCycles() API.
         * At 100 MHz, (milliseconds * cy_delayFreqKhz) product overflows
         * in case if milliseconds parameter is more than 42 seconds.
         */
        Cy_SysLib_DelayCycles(cy_delay32kMs);
        milliseconds -= CY_DELAY_MS_OVERFLOW;
    }

    Cy_SysLib_DelayCycles(milliseconds * cy_delayFreqKhz);
}


void Cy_SysLib_DelayUs(uint16_t microseconds)
{
    Cy_SysLib_DelayCycles((uint32_t) microseconds * cy_delayFreqMhz);
}

__WEAK void Cy_SysLib_Rtos_Delay(uint32_t milliseconds)
{
    Cy_SysLib_Delay(milliseconds);
}

__WEAK void Cy_SysLib_Rtos_DelayUs(uint16_t microseconds)
{
    Cy_SysLib_DelayUs(microseconds);
}

__NO_RETURN void Cy_SysLib_Halt(uint32_t reason)
{
    if(0U != reason)
    {
        /* To remove an unreferenced local variable warning */
    }

    #if defined (__ARMCC_VERSION)
        __breakpoint(0x0);
    #elif defined(__GNUC__)
        CY_HALT();
    #elif defined (__ICCARM__)
        CY_HALT();
    #else
        #error "An unsupported toolchain"
    #endif  /* (__ARMCC_VERSION) */

    while(true) {}
}


__WEAK void Cy_SysLib_AssertFailed(const char_t * file, uint32_t line)
{
#if !defined(NDEBUG) || defined(CY_DOXYGEN)
    (void) strncpy(cy_assertFileName, file, CY_MAX_FILE_NAME_SIZE);
    cy_assertLine = line;
    Cy_SysLib_Halt(0UL);
#else
    (void) file;
    (void) line;
#endif  /* !defined(NDEBUG) || defined(CY_DOXYGEN) */
}

#ifdef CY_IP_M4CPUSS


void Cy_SysLib_ClearFlashCacheAndBuffer(void)
{
    #if CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE)
        CY_PRA_REG32_SET(CY_PRA_INDX_FLASHC_FLASH_CMD, FLASHC_FLASH_CMD_INV_Msk);
    #else
        FLASHC_FLASH_CMD = FLASHC_FLASH_CMD_INV_Msk;
    #endif /* CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE) */
}
#endif


cy_en_syslib_status_t Cy_SysLib_ResetBackupDomain(void)
{
    BACKUP_RESET = BACKUP_RESET_RESET_Msk;
    return (Cy_SysLib_GetResetStatus());
}


uint32_t Cy_SysLib_GetResetReason(void)
{
    uint32_t retVal = SRSS_RES_CAUSE;

    if(0U != _FLD2VAL(SRSS_PWR_HIBERNATE_TOKEN, SRSS_PWR_HIBERNATE))
    {
        retVal |= CY_SYSLIB_RESET_HIB_WAKEUP;
    }

    if(0U != _FLD2VAL(CY_SRSS_RES_CAUSE2_CSV_LOSS, SRSS_RES_CAUSE2))
    {
        retVal |= CY_SYSLIB_RESET_CSV_LOSS_WAKEUP;
    }

    if(0U != _FLD2VAL(CY_SRSS_RES_CAUSE2_CSV_ERROR, SRSS_RES_CAUSE2))
    {
        retVal |= CY_SYSLIB_RESET_CSV_ERROR_WAKEUP;
    }

    return (retVal);
}


void Cy_SysLib_ClearResetReason(void)
{
    /* RES_CAUSE and RES_CAUSE2 register's bits are RW1C (every bit is cleared upon writing 1),
     * so write all ones to clear all the reset reasons.
     */
    SRSS_RES_CAUSE  = 0xFFFFFFFFU;
    SRSS_RES_CAUSE2 = 0xFFFFFFFFU;
    
    if(0U != _FLD2VAL(SRSS_PWR_HIBERNATE_TOKEN, SRSS_PWR_HIBERNATE))
    {
        /* Clears PWR_HIBERNATE token */
#if CY_CPU_CORTEX_M4 && defined (CY_DEVICE_SECURE)
        CY_PRA_REG32_CLR_SET(CY_PRA_INDX_SRSS_PWR_HIBERNATE, SRSS_PWR_HIBERNATE_TOKEN, 0UL);
#else
        SRSS_PWR_HIBERNATE &= ~SRSS_PWR_HIBERNATE_TOKEN_Msk;
#endif /* CY_CPU_CORTEX_M4 && defined (CY_DEVICE_SECURE) */       
    }
}

#ifdef CY_IP_M4CPUSS
#if (CY_CPU_CORTEX_M0P)


void Cy_SysLib_SoftResetCM4(void)
{
    static uint32_t msg = CY_IPC_DATA_FOR_CM4_SOFT_RESET;

    /* Tries to acquire the IPC structure and pass the arguments to SROM API.
    *  SROM API parameters:
    *   ipcPtr: IPC Structure 0 reserved for M0+ Secure Access.
    *   notifyEvent_Intr: 1U - IPC Interrupt Structure 1 is used for Releasing IPC 0 (M0+ NMI Handler).
    *   msgPtr: &msg - The address of SRAM with the API's parameters.
    */
    if(CY_IPC_DRV_SUCCESS != Cy_IPC_Drv_SendMsgPtr(Cy_IPC_Drv_GetIpcBaseAddress(CY_IPC_CHAN_SYSCALL_CM0), 1U, (void *) &msg))
    {
        CY_ASSERT(0U != 0U);
    }

    while(Cy_IPC_Drv_IsLockAcquired(Cy_IPC_Drv_GetIpcBaseAddress(CY_IPC_CHAN_SYSCALL_CM0)))
    {
        /* Waits until SROM API runs the command (sent over the IPC channel) and releases the IPC0 structure. */
    }
}
#endif /* CY_CPU_CORTEX_M0P || defined (CY_DOXYGEN) */

#ifdef CY_IP_M4CPUSS


uint64_t Cy_SysLib_GetUniqueId(void)
{
    uint32_t uniqueIdHi;
    uint32_t uniqueIdLo;

    uniqueIdHi = ((uint32_t) SFLASH_DIE_YEAR        << (CY_UNIQUE_ID_DIE_YEAR_Pos  - CY_UNIQUE_ID_DIE_X_Pos)) |
                 (((uint32_t)SFLASH_DIE_MINOR & 1U) << (CY_UNIQUE_ID_DIE_MINOR_Pos - CY_UNIQUE_ID_DIE_X_Pos)) |
                 ((uint32_t) SFLASH_DIE_SORT        << (CY_UNIQUE_ID_DIE_SORT_Pos  - CY_UNIQUE_ID_DIE_X_Pos)) |
                 ((uint32_t) SFLASH_DIE_Y           << (CY_UNIQUE_ID_DIE_Y_Pos     - CY_UNIQUE_ID_DIE_X_Pos)) |
                 ((uint32_t) SFLASH_DIE_X);

    uniqueIdLo = ((uint32_t) SFLASH_DIE_WAFER       << CY_UNIQUE_ID_DIE_WAFER_Pos) |
                 ((uint32_t) SFLASH_DIE_LOT(2U)     << CY_UNIQUE_ID_DIE_LOT_2_Pos) |
                 ((uint32_t) SFLASH_DIE_LOT(1U)     << CY_UNIQUE_ID_DIE_LOT_1_Pos) |
                 ((uint32_t) SFLASH_DIE_LOT(0U));

    return (((uint64_t) uniqueIdHi << CY_UNIQUE_ID_DIE_X_Pos) | uniqueIdLo);
}
#endif
#endif

#if (CY_ARM_FAULT_DEBUG == CY_ARM_FAULT_DEBUG_ENABLED)


void Cy_SysLib_FaultHandler(uint32_t const *faultStackAddr)
{
    /* Stores general registers */
    cy_faultFrame.r0  = faultStackAddr[CY_R0_Pos];
    cy_faultFrame.r1  = faultStackAddr[CY_R1_Pos];
    cy_faultFrame.r2  = faultStackAddr[CY_R2_Pos];
    cy_faultFrame.r3  = faultStackAddr[CY_R3_Pos];
    cy_faultFrame.r12 = faultStackAddr[CY_R12_Pos];
    cy_faultFrame.lr  = faultStackAddr[CY_LR_Pos];
    cy_faultFrame.pc  = faultStackAddr[CY_PC_Pos];
    cy_faultFrame.psr = faultStackAddr[CY_PSR_Pos];

#ifdef CY_IP_M4CPUSS
#if (CY_CPU_CORTEX_M4)
    /* Stores the Configurable Fault Status Register state with the fault cause */
    cy_faultFrame.cfsr.cfsrReg = SCB->CFSR;
    /* Stores the Hard Fault Status Register */
    cy_faultFrame.hfsr.hfsrReg = SCB->HFSR;
    /* Stores the System Handler Control and State Register */
    cy_faultFrame.shcsr.shcsrReg = SCB->SHCSR;
    /* Store MemMange fault address */
    cy_faultFrame.mmfar = SCB->MMFAR;
    /* Store Bus fault address */
    cy_faultFrame.bfar = SCB->BFAR;

#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \
     (defined (__FPU_USED   ) && (__FPU_USED    == 1U)))
    /* Checks cumulative exception bits for floating-point exceptions */
    if(0U != (__get_FPSCR() & (CY_FPSCR_IXC_Msk | CY_FPSCR_IDC_Msk)))
    {
        cy_faultFrame.s0    = faultStackAddr[CY_S0_Pos];
        cy_faultFrame.s1    = faultStackAddr[CY_S1_Pos];
        cy_faultFrame.s2    = faultStackAddr[CY_S2_Pos];
        cy_faultFrame.s3    = faultStackAddr[CY_S3_Pos];
        cy_faultFrame.s4    = faultStackAddr[CY_S4_Pos];
        cy_faultFrame.s5    = faultStackAddr[CY_S5_Pos];
        cy_faultFrame.s6    = faultStackAddr[CY_S6_Pos];
        cy_faultFrame.s7    = faultStackAddr[CY_S7_Pos];
        cy_faultFrame.s8    = faultStackAddr[CY_S8_Pos];
        cy_faultFrame.s9    = faultStackAddr[CY_S9_Pos];
        cy_faultFrame.s10   = faultStackAddr[CY_S10_Pos];
        cy_faultFrame.s11   = faultStackAddr[CY_S11_Pos];
        cy_faultFrame.s12   = faultStackAddr[CY_S12_Pos];
        cy_faultFrame.s13   = faultStackAddr[CY_S13_Pos];
        cy_faultFrame.s14   = faultStackAddr[CY_S14_Pos];
        cy_faultFrame.s15   = faultStackAddr[CY_S15_Pos];
        cy_faultFrame.fpscr = faultStackAddr[CY_FPSCR_Pos];
    }
#endif /* __FPU_PRESENT */
#endif /* CY_CPU_CORTEX_M4 */
#endif
    Cy_SysLib_ProcessingFault();
}


__WEAK void Cy_SysLib_ProcessingFault(void)
{
    #if defined(__ARMCC_VERSION)
        /* Assembly implementation of an infinite loop
         * is used for the armcc compiler to preserve the call stack.
         * Otherwise, the compiler destroys the call stack,
         * because treats this API as a no return function.
         */
        Cy_SysLib_AsmInfiniteLoop();
    #else
        while(true) {}
    #endif  /* (__ARMCC_VERSION) */
}
#endif /* (CY_ARM_FAULT_DEBUG == CY_ARM_FAULT_DEBUG_ENABLED) || defined(CY_DOXYGEN) */


void Cy_SysLib_SetWaitStates(bool ulpMode, uint32_t clkHfMHz)
{
#ifdef CY_IP_M4CPUSS
#if !((CY_CPU_CORTEX_M4) && (defined(CY_DEVICE_SECURE)))
    uint32_t waitStates;
    uint32_t freqMax;

    freqMax = ulpMode ? CY_SYSLIB_ULP_SLOW_WS_0_FREQ_MAX : CY_SYSLIB_LP_SLOW_WS_0_FREQ_MAX;
    waitStates = (clkHfMHz <= freqMax) ? 0UL : 1UL;

    /* ROM */
    CPUSS_ROM_CTL = _CLR_SET_FLD32U(CPUSS_ROM_CTL, CPUSS_ROM_CTL_SLOW_WS, waitStates);
    CPUSS_ROM_CTL = _CLR_SET_FLD32U(CPUSS_ROM_CTL, CPUSS_ROM_CTL_FAST_WS, 0UL);

    /* SRAM */
    CPUSS_RAM0_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM0_CTL0, CPUSS_RAM0_CTL0_SLOW_WS, waitStates);
    CPUSS_RAM0_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM0_CTL0, CPUSS_RAM0_CTL0_FAST_WS, 0UL);
    #if defined (RAMC1_PRESENT) && (RAMC1_PRESENT == 1UL)
        CPUSS_RAM1_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM1_CTL0, CPUSS_RAM1_CTL0_SLOW_WS, waitStates);
        CPUSS_RAM1_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM1_CTL0, CPUSS_RAM1_CTL0_FAST_WS, 0UL);
    #endif /* defined (RAMC1_PRESENT) && (RAMC1_PRESENT == 1UL) */
    #if defined (RAMC2_PRESENT) && (RAMC2_PRESENT == 1UL)
        CPUSS_RAM2_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM2_CTL0, CPUSS_RAM2_CTL0_SLOW_WS, waitStates);
        CPUSS_RAM2_CTL0 = _CLR_SET_FLD32U(CPUSS_RAM2_CTL0, CPUSS_RAM2_CTL0_FAST_WS, 0UL);
    #endif /* defined (RAMC2_PRESENT) && (RAMC2_PRESENT == 1UL) */

    /* Flash */
    if (ulpMode)
    {
        waitStates =  (clkHfMHz <= CY_SYSLIB_FLASH_ULP_WS_0_FREQ_MAX) ? 0UL :
                     ((clkHfMHz <= CY_SYSLIB_FLASH_ULP_WS_1_FREQ_MAX) ? 1UL : 2UL);
    }
    else
    {
        waitStates =  (clkHfMHz <= cy_device->flashCtlMainWs0Freq) ? 0UL :
                     ((clkHfMHz <= cy_device->flashCtlMainWs1Freq) ? 1UL :
                     ((clkHfMHz <= cy_device->flashCtlMainWs2Freq) ? 2UL :
                     ((clkHfMHz <= cy_device->flashCtlMainWs3Freq) ? 3UL :
                     ((clkHfMHz <= cy_device->flashCtlMainWs4Freq) ? 4UL : 5UL))));
    }

    FLASHC_FLASH_CTL = _CLR_SET_FLD32U(FLASHC_FLASH_CTL, FLASHC_FLASH_CTL_MAIN_WS, waitStates);
#else
    (void) ulpMode;
    (void) clkHfMHz;
#endif /* !((CY_CPU_CORTEX_M4) && (defined(CY_DEVICE_SECURE))) */
#endif
}


uint8_t Cy_SysLib_GetDeviceRevision(void)
{
#ifdef CY_IP_M4CPUSS
    return ((SFLASH_SI_REVISION_ID == 0UL) ? CY_SYSLIB_DEVICE_REV_0A : SFLASH_SI_REVISION_ID);
#else
    return 0; 
#endif    
}

uint16_t Cy_SysLib_GetDevice(void)
{
#ifdef CY_IP_M4CPUSS
    return ((SFLASH_FAMILY_ID == 0UL) ? CY_SYSLIB_DEVICE_PSOC6ABLE2 : SFLASH_FAMILY_ID);
#else
    return 0;
#endif    
}

#endif /* CY_IP_M33SYSCPUSS, CY_IP_M4CPUSS */

/* [] END OF FILE */