blob: 579ea08086d97030f4fa22a003d9b6afa31c26fe [file] [log] [blame]
/*
* 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 */