| /* |
| * Copyright (c) 2015, Freescale Semiconductor, Inc. |
| * Copyright 2016-2019 NXP |
| * All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include "fsl_mu.h" |
| |
| /* Component ID definition, used by tools. */ |
| #ifndef FSL_COMPONENT_ID |
| #define FSL_COMPONENT_ID "platform.drivers.mu" |
| #endif |
| |
| /******************************************************************************* |
| * Variables |
| ******************************************************************************/ |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| /*! @brief Pointers to mu clocks for each instance. */ |
| static const clock_ip_name_t s_muClocks[] = MU_CLOCKS; |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| /*! @brief Pointers to mu bases for each instance. */ |
| static MU_Type *const s_muBases[] = MU_BASE_PTRS; |
| |
| /****************************************************************************** |
| * Code |
| *****************************************************************************/ |
| static 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 (s_muBases[instance] == 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) |
| CLOCK_EnableClock(s_muClocks[MU_GetInstance(base)]); |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| } |
| |
| /*! |
| * 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) |
| CLOCK_DisableClock(s_muClocks[MU_GetInstance(base)]); |
| #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->SR & (((uint32_t)kMU_Tx0EmptyFlag) >> 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_TR_COUNT); |
| |
| /* Wait RX register to be full. */ |
| while (0U == (base->SR & (((uint32_t)kMU_Rx0FullFlag) >> 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 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 mask 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 mask) |
| { |
| status_t status = kStatus_Success; |
| uint32_t reg = base->CR; |
| |
| /* Previous interrupt has been accepted. */ |
| if (0U == (reg & mask)) |
| { |
| /* All interrupts have been accepted, trigger now. */ |
| reg = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | mask; |
| base->CR = reg; |
| status = kStatus_Success; |
| } |
| else |
| { |
| status = kStatus_Fail; |
| } |
| |
| return status; |
| } |
| |
| #if !(defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH) |
| /*! |
| * brief Boots the core at B side. |
| * |
| * This function sets the B side core's boot configuration and releases the |
| * core from reset. |
| * |
| * param base MU peripheral base address. |
| * param mode Core B boot mode. |
| * note Only MU side A can use this function. |
| */ |
| void MU_BootCoreB(MU_Type *base, mu_core_boot_mode_t mode) |
| { |
| #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) |
| /* Clean the reset de-assert pending flag. */ |
| base->SR = MU_SR_RDIP_MASK; |
| #endif |
| |
| #if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR) |
| uint32_t reg = base->CCR; |
| |
| reg = (reg & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK)) | MU_CCR_BOOT(mode); |
| |
| base->CCR = reg; |
| #else |
| uint32_t reg = base->CR; |
| |
| reg = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_HR_MASK | MU_CR_RSTH_MASK | MU_CR_BBOOT_MASK)) | |
| MU_CR_BBOOT(mode); |
| |
| base->CR = reg; |
| #endif |
| } |
| |
| /*! |
| * 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) |
| { |
| /* |
| * MU_BootOtherCore and MU_BootCoreB are the same, MU_BootCoreB is kept |
| * for compatible with older platforms. |
| */ |
| MU_BootCoreB(base, mode); |
| } |
| #endif /* FSL_FEATURE_MU_NO_RSTH */ |
| |
| #if !(defined(FSL_FEATURE_MU_NO_HR) && FSL_FEATURE_MU_NO_HR) |
| #if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR) |
| /*! |
| * 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_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH) |
| /* If MU does not support hold reset, then the parameter must be false. */ |
| assert(false == holdReset); |
| #endif |
| uint32_t ccr = base->CCR & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK); |
| |
| ccr |= MU_CCR_BOOT(bootMode); |
| |
| if (holdReset) |
| { |
| ccr |= MU_CCR_RSTH_MASK; |
| } |
| |
| /* Clean the reset assert pending flag. */ |
| base->SR = (MU_SR_RAIP_MASK | MU_SR_RDIP_MASK); |
| |
| /* Set CCR[HR] to trigger hardware reset. */ |
| base->CCR = ccr | MU_CCR_HR_MASK; |
| |
| /* If wait the other core enters reset. */ |
| if (waitReset) |
| { |
| /* Wait for the other core go to reset. */ |
| while (0U == (base->SR & MU_SR_RAIP_MASK)) |
| { |
| ; /* Intentional empty while*/ |
| } |
| |
| if (!holdReset) |
| { |
| /* Clear CCR[HR]. */ |
| base->CCR = ccr; |
| |
| /* Wait for the other core out of reset. */ |
| while (0U == (base->SR & MU_SR_RDIP_MASK)) |
| { |
| ; /* Intentional empty while*/ |
| } |
| } |
| } |
| } |
| #else /* FSL_FEATURE_MU_HAS_CCR */ |
| /*! |
| * 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_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH) |
| /* If MU does not support hold reset, then the parameter must be false. */ |
| assert(false == holdReset); |
| #endif |
| uint32_t resetFlag = 0; |
| |
| uint32_t cr = base->CR & ~(MU_CR_HR_MASK | MU_CR_RSTH_MASK | MU_CR_BOOT_MASK | MU_CR_GIRn_MASK | MU_CR_NMI_MASK); |
| |
| cr |= MU_CR_BOOT(bootMode); |
| |
| if (holdReset) |
| { |
| cr |= MU_CR_RSTH_MASK; |
| } |
| |
| #if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) |
| resetFlag |= MU_SR_RAIP_MASK; |
| #endif |
| #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) |
| resetFlag |= MU_SR_RDIP_MASK; |
| #endif |
| /* Clean the reset assert pending flag. */ |
| base->SR = resetFlag; |
| |
| /* Set CR[HR] to trigger hardware reset. */ |
| base->CR = cr | MU_CR_HR_MASK; |
| |
| /* If wait the other core enters reset. */ |
| if (waitReset) |
| { |
| #if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) |
| /* Wait for the other core go to reset. */ |
| while (0U == (base->SR & MU_SR_RAIP_MASK)) |
| { |
| ; /* Intentional empty while*/ |
| } |
| #endif |
| |
| if (!holdReset) |
| { |
| /* Clear CR[HR]. */ |
| base->CR = cr; |
| |
| #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) |
| /* Wait for the other core out of reset. */ |
| while (0U == (base->SR & MU_SR_RDIP_MASK)) |
| { |
| ; /* Intentional empty while*/ |
| } |
| #endif |
| } |
| } |
| } |
| #endif /* FSL_FEATURE_MU_HAS_CCR */ |
| #endif /* FSL_FEATURE_MU_NO_HR */ |