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