1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020, 2023 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_mu.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.mu"
17 #endif
18 
19 #if defined(MU_RSTS)
20 #define MU_RESETS_ARRAY MU_RSTS
21 #endif
22 
23 /*******************************************************************************
24  * Variables
25  ******************************************************************************/
26 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
27 /*! @brief Pointers to mu clocks for each instance. */
28 static const clock_ip_name_t s_muClocks[] = MU_CLOCKS;
29 /*! @brief Pointers to mu bases for each instance. */
30 static MU_Type *const s_muBases[] = MU_BASE_PTRS;
31 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
32 
33 #if defined(MU_RESETS_ARRAY)
34 /* Reset array */
35 static const reset_ip_name_t s_muResets[] = MU_RESETS_ARRAY;
36 #endif
37 
38 /******************************************************************************
39  * Code
40  *****************************************************************************/
41 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
MU_GetInstance(MU_Type * base)42 static uint32_t MU_GetInstance(MU_Type *base)
43 {
44     uint32_t instance;
45 
46     /* Find the instance index from base address mappings. */
47     for (instance = 0U; instance < (sizeof(s_muBases) / sizeof(s_muBases[0])); instance++)
48     {
49         if (s_muBases[instance] == base)
50         {
51             break;
52         }
53     }
54 
55     assert(instance < (sizeof(s_muBases) / sizeof(s_muBases[0])));
56 
57     return instance;
58 }
59 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
60 
61 /*!
62  * brief Initializes the MU module.
63  *
64  * This function enables the MU clock only.
65  *
66  * param base MU peripheral base address.
67  */
MU_Init(MU_Type * base)68 void MU_Init(MU_Type *base)
69 {
70 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
71     (void)CLOCK_EnableClock(s_muClocks[MU_GetInstance(base)]);
72 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
73 
74 #if defined(MU_RESETS_ARRAY)
75     RESET_ReleasePeripheralReset(s_muResets[MU_GetInstance(base)]);
76 #endif
77 }
78 
79 /*!
80  * brief De-initializes the MU module.
81  *
82  * This function disables the MU clock only.
83  *
84  * param base MU peripheral base address.
85  */
MU_Deinit(MU_Type * base)86 void MU_Deinit(MU_Type *base)
87 {
88 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
89     (void)CLOCK_DisableClock(s_muClocks[MU_GetInstance(base)]);
90 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
91 }
92 
93 /*!
94  * brief Blocks to send a message.
95  *
96  * This function waits until the TX register is empty and sends the message.
97  *
98  * param base MU peripheral base address.
99  * param regIndex  TX register index.
100  * param msg      Message to send.
101  */
MU_SendMsg(MU_Type * base,uint32_t regIndex,uint32_t msg)102 void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg)
103 {
104     assert(regIndex < MU_TR_COUNT);
105 
106     /* Wait TX register to be empty. */
107     while (0U == (base->SR & (((uint32_t)kMU_Tx0EmptyFlag) >> regIndex)))
108     {
109         ; /* Intentional empty while*/
110     }
111 
112     base->TR[regIndex] = msg;
113 }
114 
115 /*!
116  * brief Blocks to receive a message.
117  *
118  * This function waits until the RX register is full and receives the message.
119  *
120  * param base MU peripheral base address.
121  * param regIndex  RX register index.
122  * return The received message.
123  */
MU_ReceiveMsg(MU_Type * base,uint32_t regIndex)124 uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex)
125 {
126     assert(regIndex < MU_TR_COUNT);
127 
128     /* Wait RX register to be full. */
129     while (0U == (base->SR & (((uint32_t)kMU_Rx0FullFlag) >> regIndex)))
130     {
131         ; /* Intentional empty while*/
132     }
133 
134     return base->RR[regIndex];
135 }
136 
137 /*!
138  * brief Blocks setting the 3-bit MU flags reflect on the other MU side.
139  *
140  * This function blocks setting the 3-bit MU flags. Every time the 3-bit MU flags are changed,
141  * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are
142  * updating to the other side. After the 3-bit MU flags are updated, the status flag
143  * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period,
144  * the flags cannot be changed. This function waits for the MU status flag
145  * \c kMU_FlagsUpdatingFlag cleared and sets the 3-bit MU flags.
146  *
147  * param base MU peripheral base address.
148  * param flags The 3-bit MU flags to set.
149  */
MU_SetFlags(MU_Type * base,uint32_t flags)150 void MU_SetFlags(MU_Type *base, uint32_t flags)
151 {
152     /* Wait for update finished. */
153     while (0U != (base->SR & ((uint32_t)MU_SR_FUP_MASK)))
154     {
155         ; /* Intentional empty while*/
156     }
157 
158     MU_SetFlagsNonBlocking(base, flags);
159 }
160 
161 /*!
162  * brief Triggers interrupts to the other core.
163  *
164  * This function triggers the specific interrupts to the other core. The interrupts
165  * to trigger are passed in as bit mask. See \ref _mu_interrupt_trigger.
166  * The MU should not trigger an interrupt to the other core when the previous interrupt
167  * has not been processed by the other core. This function checks whether the
168  * previous interrupts have been processed. If not, it returns an error.
169  *
170  * code
171  * if (kStatus_Success != MU_TriggerInterrupts(base, kMU_GenInt0InterruptTrigger | kMU_GenInt2InterruptTrigger))
172  * {
173  *     Previous general purpose interrupt 0 or general purpose interrupt 2
174  *     has not been processed by the other core.
175  * }
176  * endcode
177  *
178  * param base MU peripheral base address.
179  * param mask Bit mask of the interrupts to trigger. See _mu_interrupt_trigger.
180  * retval kStatus_Success    Interrupts have been triggered successfully.
181  * retval kStatus_Fail       Previous interrupts have not been accepted.
182  */
MU_TriggerInterrupts(MU_Type * base,uint32_t mask)183 status_t MU_TriggerInterrupts(MU_Type *base, uint32_t mask)
184 {
185     status_t status = kStatus_Success;
186     uint32_t reg    = base->CR;
187 
188     /* Previous interrupt has been accepted. */
189     if (0U == (reg & mask))
190     {
191         /* All interrupts have been accepted, trigger now. */
192         reg      = (reg & ~(MU_CR_GIRn_MASK | MU_CR_NMI_MASK)) | mask;
193         base->CR = reg;
194         status   = kStatus_Success;
195     }
196     else
197     {
198         status = kStatus_Fail;
199     }
200 
201     return status;
202 }
203 
204 #if !(defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
205 /*!
206  * brief Boots the core at B side.
207  *
208  * This function sets the B side core's boot configuration and releases the
209  * core from reset.
210  *
211  * param base MU peripheral base address.
212  * param mode Core B boot mode.
213  * note Only MU side A can use this function.
214  */
MU_BootCoreB(MU_Type * base,mu_core_boot_mode_t mode)215 void MU_BootCoreB(MU_Type *base, mu_core_boot_mode_t mode)
216 {
217 #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
218     /* Clean the reset de-assert pending flag. */
219     base->SR = MU_SR_RDIP_MASK;
220 #endif
221 
222 #if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
223     uint32_t reg = base->CCR;
224 
225     reg = (reg & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK)) | MU_CCR_BOOT(mode);
226 
227     base->CCR = reg;
228 #else
229     uint32_t reg = base->CR;
230 
231     reg = (reg & ~((MU_CR_GIRn_MASK | MU_CR_NMI_MASK) | MU_CR_HR_MASK | MU_CR_RSTH_MASK | MU_CR_BBOOT_MASK)) |
232           MU_CR_BBOOT(mode);
233 
234     base->CR = reg;
235 #endif
236 }
237 
238 /*!
239  * brief Boots the other core.
240  *
241  * This function boots the other core with a boot configuration.
242  *
243  * param base MU peripheral base address.
244  * param mode The other core boot mode.
245  */
MU_BootOtherCore(MU_Type * base,mu_core_boot_mode_t mode)246 void MU_BootOtherCore(MU_Type *base, mu_core_boot_mode_t mode)
247 {
248     /*
249      * MU_BootOtherCore and MU_BootCoreB are the same, MU_BootCoreB is kept
250      * for compatible with older platforms.
251      */
252     MU_BootCoreB(base, mode);
253 }
254 #endif /* FSL_FEATURE_MU_NO_RSTH */
255 
256 #if !(defined(FSL_FEATURE_MU_NO_HR) && FSL_FEATURE_MU_NO_HR)
257 #if (defined(FSL_FEATURE_MU_HAS_CCR) && FSL_FEATURE_MU_HAS_CCR)
258 /*!
259  * brief Hardware reset the other core.
260  *
261  * This function resets the other core, the other core could mask the
262  * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset
263  * mask feature is only available for some platforms.
264  * This function could be used together with MU_BootOtherCore to control the
265  * other core reset workflow.
266  *
267  * Example 1: Reset the other core, and no hold reset
268  * code
269  * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
270  * endcode
271  * In this example, the core at MU side B will reset with the specified boot mode.
272  *
273  * Example 2: Reset the other core and hold it, then boot the other core later.
274  * code
275  *    Here the other core enters reset, and the reset is hold
276  * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
277  *    Current core boot the other core when necessary.
278  * MU_BootOtherCore(MU_A, bootMode);
279  * endcode
280  *
281  * param base MU peripheral base address.
282  * param waitReset Wait the other core enters reset.
283  *                    - true: Wait until the other core enters reset, if the other
284  *                      core has masked the hardware reset, then this function will
285  *                      be blocked.
286  *                    - false: Don't wait the reset.
287  * param holdReset Hold the other core reset or not.
288  *                    - true: Hold the other core in reset, this function returns
289  *                      directly when the other core enters reset.
290  *                    - false: Don't hold the other core in reset, this function
291  *                      waits until the other core out of reset.
292  * param bootMode Boot mode of the other core, if p holdReset is true, this
293  *                 parameter is useless.
294  */
MU_HardwareResetOtherCore(MU_Type * base,bool waitReset,bool holdReset,mu_core_boot_mode_t bootMode)295 void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode)
296 {
297 #if (defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
298     /* If MU does not support hold reset, then the parameter must be false. */
299     assert(false == holdReset);
300 #endif
301     uint32_t ccr = base->CCR & ~(MU_CCR_HR_MASK | MU_CCR_RSTH_MASK | MU_CCR_BOOT_MASK);
302 
303     ccr |= MU_CCR_BOOT(bootMode);
304 
305     if (holdReset)
306     {
307         ccr |= MU_CCR_RSTH_MASK;
308     }
309 
310     /* Clean the reset assert pending flag. */
311     base->SR = (MU_SR_RAIP_MASK | MU_SR_RDIP_MASK);
312 
313     /* Set CCR[HR] to trigger hardware reset. */
314     base->CCR = ccr | MU_CCR_HR_MASK;
315 
316     /* If wait the other core enters reset. */
317     if (waitReset)
318     {
319         /* Wait for the other core go to reset. */
320         while (0U == (base->SR & MU_SR_RAIP_MASK))
321         {
322             ; /* Intentional empty while*/
323         }
324 
325         if (!holdReset)
326         {
327             /* Clear CCR[HR]. */
328             base->CCR = ccr;
329 
330             /* Wait for the other core out of reset. */
331             while (0U == (base->SR & MU_SR_RDIP_MASK))
332             {
333                 ; /* Intentional empty while*/
334             }
335         }
336     }
337 }
338 #else /* FSL_FEATURE_MU_HAS_CCR */
339 /*!
340  * brief Hardware reset the other core.
341  *
342  * This function resets the other core, the other core could mask the
343  * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset
344  * mask feature is only available for some platforms.
345  * This function could be used together with MU_BootOtherCore to control the
346  * other core reset workflow.
347  *
348  * Example 1: Reset the other core, and no hold reset
349  * code
350  * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
351  * endcode
352  * In this example, the core at MU side B will reset with the specified boot mode.
353  *
354  * Example 2: Reset the other core and hold it, then boot the other core later.
355  * code
356  *    Here the other core enters reset, and the reset is hold
357  * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
358  *    Current core boot the other core when necessary.
359  * MU_BootOtherCore(MU_A, bootMode);
360  * endcode
361  *
362  * param base MU peripheral base address.
363  * param waitReset Wait the other core enters reset.
364  *                    - true: Wait until the other core enters reset, if the other
365  *                      core has masked the hardware reset, then this function will
366  *                      be blocked.
367  *                    - false: Don't wait the reset.
368  * param holdReset Hold the other core reset or not.
369  *                    - true: Hold the other core in reset, this function returns
370  *                      directly when the other core enters reset.
371  *                    - false: Don't hold the other core in reset, this function
372  *                      waits until the other core out of reset.
373  * param bootMode Boot mode of the other core, if p holdReset is true, this
374  *                 parameter is useless.
375  */
MU_HardwareResetOtherCore(MU_Type * base,bool waitReset,bool holdReset,mu_core_boot_mode_t bootMode)376 void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode)
377 {
378 #if (defined(FSL_FEATURE_MU_NO_RSTH) && FSL_FEATURE_MU_NO_RSTH)
379     /* If MU does not support hold reset, then the parameter must be false. */
380     assert(false == holdReset);
381 #endif
382     uint32_t resetFlag = 0;
383 
384     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);
385 
386     cr |= MU_CR_BOOT(bootMode);
387 
388     if (holdReset)
389     {
390         cr |= MU_CR_RSTH_MASK;
391     }
392 
393 #if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
394     resetFlag |= MU_SR_RAIP_MASK;
395 #endif
396 #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
397     resetFlag |= MU_SR_RDIP_MASK;
398 #endif
399     /* Clean the reset assert pending flag. */
400     base->SR = resetFlag;
401 
402     /* Set CR[HR] to trigger hardware reset. */
403     base->CR = cr | MU_CR_HR_MASK;
404 
405     /* If wait the other core enters reset. */
406     if (waitReset)
407     {
408 #if (defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
409         /* Wait for the other core go to reset. */
410         while (0U == (base->SR & MU_SR_RAIP_MASK))
411         {
412             ; /* Intentional empty while*/
413         }
414 #endif
415 
416         if (!holdReset)
417         {
418             /* Clear CR[HR]. */
419             base->CR = cr;
420 
421 #if (defined(FSL_FEATURE_MU_HAS_RESET_DEASSERT_INT) && FSL_FEATURE_MU_HAS_RESET_ASSERT_INT)
422             /* Wait for the other core out of reset. */
423             while (0U == (base->SR & MU_SR_RDIP_MASK))
424             {
425                 ; /* Intentional empty while*/
426             }
427 #endif
428         }
429     }
430 }
431 #endif /* FSL_FEATURE_MU_HAS_CCR  */
432 #endif /* FSL_FEATURE_MU_NO_HR */
433