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