1 /*
2  * Copyright 2021-2023 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_mu.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.mu1"
16 #endif
17 
18 #if defined(MU_RSTS)
19 #define MU_RESETS_ARRAY MU_RSTS
20 #endif
21 
22 /*******************************************************************************
23  * Variables
24  ******************************************************************************/
25 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
26 #if (defined(MU_CLOCKS))
27 /*! @brief Pointers to mu clocks for each instance. */
28 static const clock_ip_name_t s_muClocks[] = MU_CLOCKS;
29 #endif
30 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
31 
32 #if defined(MU_RESETS_ARRAY)
33 /* Reset array */
34 static const reset_ip_name_t s_muResets[] = MU_RESETS_ARRAY;
35 #endif
36 
37 /*! @brief Pointers to mu bases for each instance. */
38 static MU_Type *const s_muBases[] = MU_BASE_PTRS;
39 
40 /******************************************************************************
41  * Code
42  *****************************************************************************/
MU_GetInstance(MU_Type * base)43 uint32_t MU_GetInstance(MU_Type *base)
44 {
45     uint32_t instance;
46 
47     /* Find the instance index from base address mappings. */
48     for (instance = 0U; instance < (sizeof(s_muBases) / sizeof(s_muBases[0])); instance++)
49     {
50         if (MSDK_REG_SECURE_ADDR(s_muBases[instance]) == MSDK_REG_SECURE_ADDR(base))
51         {
52             break;
53         }
54     }
55 
56     assert(instance < (sizeof(s_muBases) / sizeof(s_muBases[0])));
57 
58     return instance;
59 }
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 #if (defined(MU_CLOCKS))
72     (void)CLOCK_EnableClock(s_muClocks[MU_GetInstance(base)]);
73 #endif
74 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
75 
76 #if defined(MU_RESETS_ARRAY)
77     RESET_ReleasePeripheralReset(s_muResets[MU_GetInstance(base)]);
78 #endif
79 }
80 
81 /*!
82  * brief De-initializes the MU module.
83  *
84  * This function disables the MU clock only.
85  *
86  * param base MU peripheral base address.
87  */
MU_Deinit(MU_Type * base)88 void MU_Deinit(MU_Type *base)
89 {
90 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
91 #if (defined(MU_CLOCKS))
92     (void)CLOCK_DisableClock(s_muClocks[MU_GetInstance(base)]);
93 #endif
94 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
95 }
96 
97 /*!
98  * brief Blocks to send a message.
99  *
100  * This function waits until the TX register is empty and sends the message.
101  *
102  * param base MU peripheral base address.
103  * param regIndex  TX register index.
104  * param msg      Message to send.
105  */
MU_SendMsg(MU_Type * base,uint32_t regIndex,uint32_t msg)106 void MU_SendMsg(MU_Type *base, uint32_t regIndex, uint32_t msg)
107 {
108     assert(regIndex < MU_TR_COUNT);
109 
110     /* Wait TX register to be empty. */
111     while (0U == (base->TSR & (1UL << regIndex)))
112     {
113         ; /* Intentional empty while*/
114     }
115 
116     base->TR[regIndex] = msg;
117 }
118 
119 /*!
120  * brief Blocks to receive a message.
121  *
122  * This function waits until the RX register is full and receives the message.
123  *
124  * param base MU peripheral base address.
125  * param regIndex  RX register index.
126  * return The received message.
127  */
MU_ReceiveMsg(MU_Type * base,uint32_t regIndex)128 uint32_t MU_ReceiveMsg(MU_Type *base, uint32_t regIndex)
129 {
130     assert(regIndex < MU_RR_COUNT);
131 
132     /* Wait RX register to be full. */
133     while (0U == (base->RSR & (1UL << regIndex)))
134     {
135         ; /* Intentional empty while*/
136     }
137 
138     return base->RR[regIndex];
139 }
140 
141 /*!
142  * brief Blocks setting the 3-bit MU flags reflect on the other MU side.
143  *
144  * This function blocks setting the 3-bit MU flags. Every time the 3-bit MU flags are changed,
145  * the status flag \c kMU_FlagsUpdatingFlag asserts indicating the 3-bit MU flags are
146  * updating to the other side. After the 3-bit MU flags are updated, the status flag
147  * \c kMU_FlagsUpdatingFlag is cleared by hardware. During the flags updating period,
148  * the flags cannot be changed. This function waits for the MU status flag
149  * \c kMU_FlagsUpdatingFlag cleared and sets the 3-bit MU flags.
150  *
151  * param base MU peripheral base address.
152  * param flags The 3-bit MU flags to set.
153  */
MU_SetFlags(MU_Type * base,uint32_t flags)154 void MU_SetFlags(MU_Type *base, uint32_t flags)
155 {
156     /* Wait for update finished. */
157     while (0U != (base->SR & ((uint32_t)MU_SR_FUP_MASK)))
158     {
159         ; /* Intentional empty while*/
160     }
161 
162     MU_SetFlagsNonBlocking(base, flags);
163 }
164 
165 /*
166  * brief Gets the MU status flags.
167  *
168  * This function returns the bit mask of the MU status flags. See _mu_status_flags.
169  *
170  * uint32_t flags;
171  * flags = MU_GetStatusFlags(base);  Get all status flags.
172  * if (kMU_Tx0EmptyFlag & flags)
173  * {
174  *     The TX0 register is empty. Message can be sent.
175  *     MU_SendMsgNonBlocking(base, kMU_MsgReg0, MSG0_VAL);
176  * }
177  * if (kMU_Tx1EmptyFlag & flags)
178  * {
179  *     The TX1 register is empty. Message can be sent.
180  *     MU_SendMsgNonBlocking(base, kMU_MsgReg1, MSG1_VAL);
181  * }
182  *
183  * param base MU peripheral base address.
184  * return      Bit mask of the MU status flags, see _mu_status_flags.
185  */
MU_GetStatusFlags(MU_Type * base)186 uint32_t MU_GetStatusFlags(MU_Type *base)
187 {
188     uint32_t flags = 0;
189 
190     /* TX */
191     flags |= MU_TX_FLAG(base->TSR);
192 
193     /* RX */
194     flags |= MU_RX_FLAG(base->RSR);
195 
196     /* General purpose interrupt */
197     flags |= MU_GI_FLAG(base->GSR);
198 
199     /* Status */
200     flags |= MU_STAT_FLAG(base->SR);
201 
202 #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS))
203     /* Core interrupt. */
204     flags |= MU_CORE_FLAG(base->CSSR0);
205 #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */
206 
207     return flags;
208 }
209 
210 /*!
211  * brief Triggers interrupts to the other core.
212  *
213  * This function triggers the specific interrupts to the other core. The interrupts
214  * to trigger are passed in as bit mask. See \ref _mu_interrupt_trigger.
215  * The MU should not trigger an interrupt to the other core when the previous interrupt
216  * has not been processed by the other core. This function checks whether the
217  * previous interrupts have been processed. If not, it returns an error.
218  *
219  * code
220  * if (kStatus_Success != MU_TriggerInterrupts(base, kMU_GenInt0InterruptTrigger | kMU_GenInt2InterruptTrigger))
221  * {
222  *     Previous general purpose interrupt 0 or general purpose interrupt 2
223  *     has not been processed by the other core.
224  * }
225  * endcode
226  *
227  * param base MU peripheral base address.
228  * param interrupts Bit mask of the interrupts to trigger. See _mu_interrupt_trigger.
229  * retval kStatus_Success    Interrupts have been triggered successfully.
230  * retval kStatus_Fail       Previous interrupts have not been accepted.
231  */
MU_TriggerInterrupts(MU_Type * base,uint32_t interrupts)232 status_t MU_TriggerInterrupts(MU_Type *base, uint32_t interrupts)
233 {
234     uint32_t localInerrupts = MU_GET_GI_INTR(interrupts);
235 
236     return MU_TriggerGeneralPurposeInterrupts(base, localInerrupts);
237 }
238 
239 /*
240  * brief Triggers general purpose interrupts to the other core.
241  *
242  * This function triggers the specific general purpose interrupts to the other core.
243  * The interrupts to trigger are passed in as bit mask. See mu_general_purpose_interrupt_t.
244  * The MU should not trigger an interrupt to the other core when the previous interrupt
245  * has not been processed by the other core. This function checks whether the
246  * previous interrupts have been processed. If not, it returns an error.
247  *
248  * code
249    status_t status;
250    status = MU_TriggerGeneralPurposeInterrupts(base, kMU_GeneralPurposeInterrupt0 | kMU_GeneralPurposeInterrupt2);
251 
252    if (kStatus_Success != status)
253    {
254         Previous general purpose interrupt 0 or general purpose interrupt 2
255         has not been processed by the other core.
256    }
257    endcode
258  *
259  * param base MU peripheral base address.
260  * param interrupts Bit mask of the interrupts to trigger. See mu_general_purpose_interrupt_t.
261  * retval kStatus_Success    Interrupts have been triggered successfully.
262  * retval kStatus_Fail       Previous interrupts have not been accepted.
263  */
MU_TriggerGeneralPurposeInterrupts(MU_Type * base,uint32_t interrupts)264 status_t MU_TriggerGeneralPurposeInterrupts(MU_Type *base, uint32_t interrupts)
265 {
266     status_t status;
267     uint32_t gcr = base->GCR;
268 
269     /* Previous interrupt has not been accepted. */
270     if (0U != (gcr & interrupts))
271     {
272         status = kStatus_Fail;
273     }
274     else
275     {
276         base->GCR = (gcr | interrupts);
277         status    = kStatus_Success;
278     }
279 
280     return status;
281 }
282 
283 #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI))
284 /*
285  * brief Triggers NMI to the other core.
286  *
287  * This function triggers the NMI to the other core.
288  * The MU should not trigger NMI to the other core when the previous interrupt
289  * has not been processed by the other core. This function checks whether the
290  * previous interrupts have been processed. If not, it returns an error.
291  *
292  * param base MU peripheral base address.
293  * retval kStatus_Success    Interrupts have been triggered successfully.
294  * retval kStatus_Fail       Previous interrupts have not been accepted.
295  */
MU_TriggerNmi(MU_Type * base)296 status_t MU_TriggerNmi(MU_Type *base)
297 {
298     status_t status;
299     uint32_t ccr0 = base->CCR0;
300 
301     if (0U != (ccr0 & MU_CCR0_NMI_MASK))
302     {
303         status = kStatus_Fail;
304     }
305     else
306     {
307 #if !(defined(FSL_FEATURE_MU_HAS_HR) && (FSL_FEATURE_MU_HAS_HR == 0))
308         ccr0 &= ~MU_CCR0_HR_MASK;
309 #endif
310 
311         base->CCR0 = ccr0 | MU_CCR0_NMI_MASK;
312         status     = kStatus_Success;
313     }
314 
315     return status;
316 }
317 #endif /* FSL_FEATURE_MU_NO_NMI */
318 
319 #if !(defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT))
320 /*!
321  * brief Boots the other core.
322  *
323  * This function boots the other core with a boot configuration.
324  *
325  * param base MU peripheral base address.
326  * param mode The other core boot mode.
327  */
MU_BootOtherCore(MU_Type * base,mu_core_boot_mode_t mode)328 void MU_BootOtherCore(MU_Type *base, mu_core_boot_mode_t mode)
329 {
330     uint32_t ccr0;
331 
332 #if defined(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn)
333     assert(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn(base) != 0);
334 #endif
335 
336     ccr0 = base->CCR0;
337 
338 #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI))
339     ccr0 &= ~MU_CCR0_NMI_MASK;
340 #endif
341 
342 #if !(defined(FSL_FEATURE_MU_HAS_HR) && (0 == FSL_FEATURE_MU_HAS_HR))
343     /* Don't need to check whether the instance support it, always clear it. */
344     ccr0 &= ~MU_CCR0_HR_MASK;
345 #endif
346 
347 #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH))
348     /* Don't need to check whether the MU instance support RSTH, always clear the bit. */
349     ccr0 &= ~MU_CCR0_RSTH_MASK;
350 #endif
351 
352     ccr0 = (ccr0 & ~MU_CCR0_BOOT_MASK) | MU_CCR0_BOOT(mode);
353 
354     base->CCR0 = ccr0;
355 }
356 #endif /* FSL_FEATURE_MU_HAS_BOOT */
357 
358 #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH))
359 /*
360  * brief Holds the other core reset.
361  *
362  * This function causes the other core to be held in reset following any reset event.
363  *
364  * param base MU peripheral base address.
365  */
MU_HoldOtherCoreReset(MU_Type * base)366 void MU_HoldOtherCoreReset(MU_Type *base)
367 {
368     uint32_t ccr0;
369 
370 #if defined(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn)
371     /* The MU instance must support the feature. */
372     assert(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn(base) != 0);
373 #endif
374 
375     ccr0 = base->CCR0;
376 
377 #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI))
378     ccr0 &= ~MU_CCR0_NMI_MASK;
379 #endif
380 
381     ccr0 = (ccr0 & ~(MU_CCR0_HR_MASK)) | MU_CCR0_RSTH_MASK;
382 
383     base->CCR0 = ccr0;
384 }
385 #endif /* FSL_FEATURE_MU_HAS_RSTH */
386 
387 #if !(defined(FSL_FEATURE_MU_HAS_HR) && (FSL_FEATURE_MU_HAS_HR == 0))
388 /*!
389  * brief Hardware reset the other core.
390  *
391  * This function resets the other core, the other core could mask the
392  * hardware reset by calling ref MU_MaskHardwareReset. The hardware reset
393  * mask feature is only available for some platforms.
394  * This function could be used together with MU_BootOtherCore to control the
395  * other core reset workflow.
396  *
397  * Example 1: Reset the other core, and no hold reset
398  * code
399  * MU_HardwareResetOtherCore(MU_A, true, false, bootMode);
400  * endcode
401  * In this example, the core at MU side B will reset with the specified boot mode.
402  *
403  * Example 2: Reset the other core and hold it, then boot the other core later.
404  * code
405  *    Here the other core enters reset, and the reset is hold
406  * MU_HardwareResetOtherCore(MU_A, true, true, modeDontCare);
407  *    Current core boot the other core when necessary.
408  * MU_BootOtherCore(MU_A, bootMode);
409  * endcode
410  *
411  * param base MU peripheral base address.
412  * param waitReset Wait the other core enters reset.
413  *                    - true: Wait until the other core enters reset, if the other
414  *                      core has masked the hardware reset, then this function will
415  *                      be blocked.
416  *                    - false: Don't wait the reset.
417  * param holdReset Hold the other core reset or not.
418  *                    - true: Hold the other core in reset, this function returns
419  *                      directly when the other core enters reset.
420  *                    - false: Don't hold the other core in reset, this function
421  *                      waits until the other core out of reset.
422  * param bootMode Boot mode of the other core, if p holdReset is true, this
423  *                 parameter is useless.
424  */
MU_HardwareResetOtherCore(MU_Type * base,bool waitReset,bool holdReset,mu_core_boot_mode_t bootMode)425 void MU_HardwareResetOtherCore(MU_Type *base, bool waitReset, bool holdReset, mu_core_boot_mode_t bootMode)
426 {
427 #if defined(FSL_FEATURE_MU_HAS_HR_BY_INSTANCEn)
428     assert(FSL_FEATURE_MU_HAS_HR_BY_INSTANCEn(base) != 0);
429 #endif
430 
431 #if (defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT))
432     assert(bootMode == kMU_CoreBootModeDummy);
433 #endif
434 
435 #if (defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH))
436     assert(holdReset == false);
437 #endif
438 
439 #if defined(FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn)
440     if (FSL_FEATURE_MU_HAS_RSTH_BY_INSTANCEn(base) == 0)
441     {
442         assert(holdReset == false);
443     }
444 #endif
445 
446 #if (defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS))
447     assert(waitReset == false);
448 #endif
449 
450     uint32_t ccr0 = base->CCR0;
451 
452     ccr0 &= ~MU_CCR0_HR_MASK;
453 
454 #if !(defined(FSL_FEATURE_MU_NO_NMI) && (0 != FSL_FEATURE_MU_NO_NMI))
455     ccr0 &= ~MU_CCR0_NMI_MASK;
456 #endif /* FSL_FEATURE_MU_NO_NMI */
457 
458 #if !(defined(FSL_FEATURE_MU_HAS_BOOT) && (0 == FSL_FEATURE_MU_HAS_BOOT))
459 #if defined(FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn)
460     if (FSL_FEATURE_MU_HAS_BOOT_BY_INSTANCEn(base) != 0)
461 #endif
462     {
463         ccr0 &= ~MU_CCR0_BOOT_MASK;
464         ccr0 |= MU_CCR0_BOOT(bootMode);
465     }
466 #endif /* FSL_FEATURE_MU_HAS_BOOT */
467 
468 #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH))
469     ccr0 &= ~MU_CCR0_RSTH_MASK;
470     /* Don't need check whether the instance support hold reset, it is already
471      * checked at the begining of this function.
472      */
473     if (holdReset)
474     {
475         ccr0 |= MU_CCR0_RSTH_MASK;
476     }
477 #endif /* FSL_FEATURE_MU_HAS_RSTH */
478 
479 #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS))
480 #if !(defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && (FSL_FEATURE_MU_HAS_RESET_ASSERT_INT == 0))
481     /* Clean the reset assert pending flag. */
482     base->CSSR0 = MU_CSSR0_RAIP_MASK;
483 #endif
484 #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */
485 
486     /* Set CCR0[HR] to trigger hardware reset. */
487     base->CCR0 = ccr0 | MU_CCR0_HR_MASK;
488 
489     /* If wait the other core enters reset. */
490     if (waitReset)
491     {
492 #if !(defined(FSL_FEATURE_MU_NO_CORE_STATUS) && (0 != FSL_FEATURE_MU_NO_CORE_STATUS))
493 #if !(defined(FSL_FEATURE_MU_HAS_RESET_ASSERT_INT) && (FSL_FEATURE_MU_HAS_RESET_ASSERT_INT == 0))
494         /* Wait for the other core go to reset. */
495         while (0U == (base->CSSR0 & MU_CSSR0_RAIP_MASK))
496         {
497             ; /* Intentional empty while*/
498         }
499 #endif /* FSL_FEATURE_MU_HAS_RESET_ASSERT_INT */
500 #endif /* FSL_FEATURE_MU_NO_CORE_STATUS */
501 
502 #if !(defined(FSL_FEATURE_MU_HAS_RSTH) && (0 == FSL_FEATURE_MU_HAS_RSTH))
503         if (!holdReset)
504         {
505             /* Clear CCR[HR]. */
506             base->CCR0 = ccr0;
507         }
508 #endif /* FSL_FEATURE_MU_HAS_RSTH */
509     }
510 }
511 #endif /* FSL_FEATURE_MU_HAS_HR */
512