/* * Copyright 2021-2023 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_mu.h" /******************************************************************************* * Definitions ******************************************************************************/ /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.mu1" #endif #if defined(MU_RSTS) #define MU_RESETS_ARRAY MU_RSTS #endif /******************************************************************************* * Variables ******************************************************************************/ #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) #if (defined(MU_CLOCKS)) /*! @brief Pointers to mu clocks for each instance. */ static const clock_ip_name_t s_muClocks[] = MU_CLOCKS; #endif #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ #if defined(MU_RESETS_ARRAY) /* Reset array */ static const reset_ip_name_t s_muResets[] = MU_RESETS_ARRAY; #endif /*! @brief Pointers to mu bases for each instance. */ static MU_Type *const s_muBases[] = MU_BASE_PTRS; /****************************************************************************** * Code *****************************************************************************/ uint32_t MU_GetInstance(MU_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ for (instance = 0U; instance < (sizeof(s_muBases) / sizeof(s_muBases[0])); instance++) { if (MSDK_REG_SECURE_ADDR(s_muBases[instance]) == MSDK_REG_SECURE_ADDR(base)) { break; } } assert(instance < (sizeof(s_muBases) / sizeof(s_muBases[0]))); return instance; } /*! * brief Initializes the MU module. * * This function enables the MU clock only. * * param base MU peripheral base address. */ void MU_Init(MU_Type *base) { #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) #if (defined(MU_CLOCKS)) (void)CLOCK_EnableClock(s_muClocks[MU_GetInstance(base)]); #endif #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ #if defined(MU_RESETS_ARRAY) RESET_ReleasePeripheralReset(s_muResets[MU_GetInstance(base)]); #endif } /*! * brief De-initializes the MU module. * * This function disables the MU clock only. * * param base MU peripheral base address. */ void MU_Deinit(MU_Type *base) { #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) #if (defined(MU_CLOCKS)) (void)CLOCK_DisableClock(s_muClocks[MU_GetInstance(base)]); #endif #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } /*! * brief Blocks to send a message. * * This function waits until the TX register is empty and sends the message. * * param base MU peripheral base address. * param regIndex TX register index. * param msg Message to send. */ void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg) { assert(regIndex < MU_TR_COUNT); /* Wait TX register to be empty. */ while (0U == (base->TSR & (1UL << regIndex))) { ; /* Intentional empty while*/ } base->TR[regIndex] = msg; } /*! * brief Blocks to receive a message. * * This function waits until the RX register is full and receives the message. * * param base MU peripheral base address. * param regIndex RX register index. * return The received message. */ uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex) { assert(regIndex < MU_RR_COUNT); /* Wait RX register to be full. */ while (0U == (base->RSR & (1UL << regIndex))) { ; /* Intentional empty while*/ } return base->RR[regIndex]; } /*! * brief Blocks setting the 3-bit MU flags reflect on the other MU side. * * This function blocks setting the 3-bit MU flags. Every time the 3-bit MU flags are changed, * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are * updating to the other side. After the 3-bit MU flags are updated, the status flag * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period, * the flags cannot be changed. This function waits for the MU status flag * \c kMU_FlagsUpdatingFlag cleared and sets the 3-bit MU flags. * * param base MU peripheral base address. * param flags The 3-bit MU flags to set. */ void MU_SetFlags(MU_Type *base, uint32_t flags) { /* Wait for update finished. */ while (0U != (base->SR & ((uint32_t)MU_SR_FUP_MASK))) { ; /* Intentional empty while*/ } MU_SetFlagsNonBlocking(base, flags); } /* * brief Gets the MU status flags. * * This function returns the bit mask of the MU status flags. See _mu_status_flags. * * uint32_t flags; * flags = MU_GetStatusFlags(base); Get all status flags. * if (kMU_Tx0EmptyFlag & flags) * { * The TX0 register is empty. Message can be sent. * MU_SendMsgNonBlocking(base, kMU_MsgReg0, MSG0_VAL); * } * if (kMU_Tx1EmptyFlag & flags) * { * The TX1 register is empty. Message can be sent. * MU_SendMsgNonBlocking(base, kMU_MsgReg1, MSG1_VAL); * } * * param base MU peripheral base address. * return Bit mask of the MU status flags, see _mu_status_flags. */ uint32_t MU_GetStatusFlags(MU_Type *base) { uint32_t flags = 0; /* TX */ flags |= MU_TX_FLAG(base->TSR); /* RX */ flags |= MU_RX_FLAG(base->RSR); /* General purpose interrupt */ flags |= MU_GI_FLAG(base->GSR); /* Status */ flags |= MU_STAT_FLAG(base->SR); #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS)) /* Core interrupt. */ flags |= MU_CORE_FLAG(base->CSSR0); #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */ return flags; } /*! * brief Triggers interrupts to the other core. * * This function triggers the specific interrupts to the other core. The interrupts * to trigger are passed in as bit mask. See \ref _mu_interrupt_trigger. * The MU should not trigger an interrupt to the other core when the previous interrupt * has not been processed by the other core. This function checks whether the * previous interrupts have been processed. If not, it returns an error. * * code * if (kStatus_Success != MU_TriggerInterrupts(base, kMU_GenInt0InterruptTrigger | kMU_GenInt2InterruptTrigger)) * { * Previous general purpose interrupt 0 or general purpose interrupt 2 * has not been processed by the other core. * } * endcode * * param base MU peripheral base address. * param interrupts Bit mask of the interrupts to trigger. See _mu_interrupt_trigger. * retval kStatus_Success Interrupts have been triggered successfully. * retval kStatus_Fail Previous interrupts have not been accepted. */ status_t MU_TriggerInterrupts(MU_Type *base, uint32_t interrupts) { uint32_t localInerrupts = MU_GET_GI_INTR(interrupts); return MU_TriggerGeneralPurposeInterrupts(base, localInerrupts); } /* * brief Triggers general purpose interrupts to the other core. * * This function triggers the specific general purpose interrupts to the other core. * The interrupts to trigger are passed in as bit mask. See mu_general_purpose_interrupt_t. * The MU should not trigger an interrupt to the other core when the previous interrupt * has not been processed by the other core. This function checks whether the * previous interrupts have been processed. If not, it returns an error. * * code status_t status; status = MU_TriggerGeneralPurposeInterrupts(base, kMU_GeneralPurposeInterrupt0 | kMU_GeneralPurposeInterrupt2); if (kStatus_Success != status) { Previous general purpose interrupt 0 or general purpose interrupt 2 has not been processed by the other core. } endcode * * param base MU peripheral base address. * param interrupts Bit mask of the interrupts to trigger. See mu_general_purpose_interrupt_t. * retval kStatus_Success Interrupts have been triggered successfully. * retval kStatus_Fail Previous interrupts have not been accepted. */ status_t MU_TriggerGeneralPurposeInterrupts(MU_Type *base, uint32_t interrupts) { status_t status; uint32_t gcr = base->GCR; /* Previous interrupt has not been accepted. */ if (0U != (gcr & interrupts)) { status = kStatus_Fail; } else { base->GCR = (gcr | interrupts); status = kStatus_Success; } return status; } #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI)) /* * brief Triggers NMI to the other core. * * This function triggers the NMI to the other core. * The MU should not trigger NMI to the other core when the previous interrupt * has not been processed by the other core. This function checks whether the * previous interrupts have been processed. If not, it returns an error. * * param base MU peripheral base address. * retval kStatus_Success Interrupts have been triggered successfully. * retval kStatus_Fail Previous interrupts have not been accepted. */ status_t MU_TriggerNmi(MU_Type *base) { status_t status; uint32_t ccr0 = base->CCR0; if (0U != (ccr0 & MU_CCR0_NMI_MASK)) { status = kStatus_Fail; } else { #if !(defined(FSL_FEATURE_MU_HAS_HR) && (FSL_FEATURE_MU_HAS_HR == 0)) ccr0 &= ~MU_CCR0_HR_MASK; #endif base->CCR0 = ccr0 | MU_CCR0_NMI_MASK; status = kStatus_Success; } return status; } #endif /* FSL_FEATURE_MU_NO_NMI */ #if !(defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT)) /*! * brief Boots the other core. * * This function boots the other core with a boot configuration. * * param base MU peripheral base address. * param mode The other core boot mode. */ void MU_BootOtherCore(MU_Type *base, mu_core_boot_mode_t mode) { uint32_t ccr0; #if defined(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn) assert(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn(base) != 0); #endif ccr0 = base->CCR0; #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI)) ccr0 &= ~MU_CCR0_NMI_MASK; #endif #if !(defined(FSL_FEATURE_MU_HAS_HR) && (0 == FSL_FEATURE_MU_HAS_HR)) /* Don't need to check whether the instance support it, always clear it. */ ccr0 &= ~MU_CCR0_HR_MASK; #endif #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH)) /* Don't need to check whether the MU instance support RSTH, always clear the bit. */ ccr0 &= ~MU_CCR0_RSTH_MASK; #endif ccr0 = (ccr0 & ~MU_CCR0_BOOT_MASK) | MU_CCR0_BOOT(mode); base->CCR0 = ccr0; } #endif /* FSL_FEATURE_MU_HAS_BOOT */ #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH)) /* * brief Holds the other core reset. * * This function causes the other core to be held in reset following any reset event. * * param base MU peripheral base address. */ void MU_HoldOtherCoreReset(MU_Type *base) { uint32_t ccr0; #if defined(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn) /* The MU instance must support the feature. */ assert(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn(base) != 0); #endif ccr0 = base->CCR0; #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI)) ccr0 &= ~MU_CCR0_NMI_MASK; #endif ccr0 = (ccr0 & ~(MU_CCR0_HR_MASK)) | MU_CCR0_RSTH_MASK; base->CCR0 = ccr0; } #endif /* FSL_FEATURE_MU_HAS_RSTH */ #if !(defined(FSL_FEATURE_MU_HAS_HR) && (FSL_FEATURE_MU_HAS_HR == 0)) /*! * brief Hardware reset the other core. * * This function resets the other core, the other core could mask the * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset * mask feature is only available for some platforms. * This function could be used together with MU_BootOtherCore to control the * other core reset workflow. * * Example 1: Reset the other core, and no hold reset * code * MU_HardwareResetOtherCore(MU_A, true, false, bootMode); * endcode * In this example, the core at MU side B will reset with the specified boot mode. * * Example 2: Reset the other core and hold it, then boot the other core later. * code * Here the other core enters reset, and the reset is hold * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare); * Current core boot the other core when necessary. * MU_BootOtherCore(MU_A, bootMode); * endcode * * param base MU peripheral base address. * param waitReset Wait the other core enters reset. * - true: Wait until the other core enters reset, if the other * core has masked the hardware reset, then this function will * be blocked. * - false: Don't wait the reset. * param holdReset Hold the other core reset or not. * - true: Hold the other core in reset, this function returns * directly when the other core enters reset. * - false: Don't hold the other core in reset, this function * waits until the other core out of reset. * param bootMode Boot mode of the other core, if p holdReset is true, this * parameter is useless. */ void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode) { #if defined(FSL_FEATURE_MU_HAS_HR_BY_INSTANCEn) assert(FSL_FEATURE_MU_HAS_HR_BY_INSTANCEn(base) != 0); #endif #if (defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT)) assert(bootMode == kMU_CoreBootModeDummy); #endif #if (defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH)) assert(holdReset == false); #endif #if defined(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn) if (FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn(base) == 0) { assert(holdReset == false); } #endif #if (defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS)) assert(waitReset == false); #endif uint32_t ccr0 = base->CCR0; ccr0 &= ~MU_CCR0_HR_MASK; #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI)) ccr0 &= ~MU_CCR0_NMI_MASK; #endif /* FSL_FEATURE_MU_NO_NMI */ #if !(defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT)) #if defined(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn) if (FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn(base) != 0) #endif { ccr0 &= ~MU_CCR0_BOOT_MASK; ccr0 |= MU_CCR0_BOOT(bootMode); } #endif /* FSL_FEATURE_MU_HAS_BOOT */ #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH)) ccr0 &= ~MU_CCR0_RSTH_MASK; /* Don't need check whether the instance support hold reset, it is already * checked at the begining of this function. */ if (holdReset) { ccr0 |= MU_CCR0_RSTH_MASK; } #endif /* FSL_FEATURE_MU_HAS_RSTH */ #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS)) #if !(defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && (FSL_FEATURE_MU_HAS_RESET_ASSERT_INT == 0)) /* Clean the reset assert pending flag. */ base->CSSR0 = MU_CSSR0_RAIP_MASK; #endif #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */ /* Set CCR0[HR] to trigger hardware reset. */ base->CCR0 = ccr0 | MU_CCR0_HR_MASK; /* If wait the other core enters reset. */ if (waitReset) { #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS)) #if !(defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && (FSL_FEATURE_MU_HAS_RESET_ASSERT_INT == 0)) /* Wait for the other core go to reset. */ while (0U == (base->CSSR0 & MU_CSSR0_RAIP_MASK)) { ; /* Intentional empty while*/ } #endif /* FSL_FEATURE_MU_HAS_RESET_ASSERT_INT */ #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */ #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH)) if (!holdReset) { /* Clear CCR[HR]. */ base->CCR0 = ccr0; } #endif /* FSL_FEATURE_MU_HAS_RSTH */ } } #endif /* FSL_FEATURE_MU_HAS_HR */