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