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