1 /*
2 * Copyright 2022-2024 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7 #include "fsl_cmc.h"
8
9 /* Component ID definition, used by tools. */
10 #ifndef FSL_COMPONENT_ID
11 #define FSL_COMPONENT_ID "platform.drivers.mcx_cmc"
12 #endif
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17
18 /*******************************************************************************
19 * Prototypes
20 ******************************************************************************/
21
22 /*******************************************************************************
23 * Variables
24 ******************************************************************************/
25 static uint32_t g_savedPrimask;
26
27 /*******************************************************************************
28 * Code
29 ******************************************************************************/
30
31 /*!
32 * brief Sets clock mode.
33 *
34 * This function configs the amount of clock gating when the core asserts
35 * Sleeping due to WFI, WFE or SLEEPONEXIT.
36 *
37 * param base CMC peripheral base address.
38 * param mode System clock mode.
39 */
CMC_SetClockMode(CMC_Type * base,cmc_clock_mode_t mode)40 void CMC_SetClockMode(CMC_Type *base, cmc_clock_mode_t mode)
41 {
42 uint32_t reg;
43
44 reg = base->CKCTRL;
45 reg &= ~CMC_CKCTRL_CKMODE_MASK;
46 reg |= CMC_CKCTRL_CKMODE((mode));
47 base->CKCTRL = reg;
48 }
49
50 /*!
51 * brief Configures all power mode protection settings.
52 *
53 * This function configures the power mode protection settings for
54 * supported power modes. This should be done before setting the lowPower mode
55 * for each power doamin.
56 *
57 * The allowed lowpower modes are passed as bit map. For example, to allow
58 * Sleep and DeepSleep, use CMC_SetPowerModeProtection(CMC_base, kCMC_AllowSleepMode|kCMC_AllowDeepSleepMode).
59 * To allow all low power modes, use CMC_SetPowerModeProtection(CMC_base, kCMC_AllowAllLowPowerModes).
60 *
61 * param base CMC peripheral base address.
62 * param allowedModes Bitmaps of the allowed power modes.
63 */
CMC_SetPowerModeProtection(CMC_Type * base,uint32_t allowedModes)64 void CMC_SetPowerModeProtection(CMC_Type *base, uint32_t allowedModes)
65 {
66 uint32_t reg;
67
68 reg = base->PMPROT;
69 reg &= ~0xFUL;
70 reg |= allowedModes;
71
72 base->PMPROT = reg;
73 }
74
75 /*!
76 * brief Configure reset pin.
77 *
78 * This function configures reset pin. When enabled, the low power filter is enabled in both
79 * Active and Low power modes, the reset filter is only enabled in Active mode. When both filers
80 * are enabled, they operate in series.
81 *
82 * param base CMC peripheral base address.
83 * param config Pointer to the reset pin config structure.
84 */
CMC_ConfigResetPin(CMC_Type * base,const cmc_reset_pin_config_t * config)85 void CMC_ConfigResetPin(CMC_Type *base, const cmc_reset_pin_config_t *config)
86 {
87 assert(config != NULL);
88
89 uint32_t reg = base->RPC;
90
91 if (config->lowpowerFilterEnable)
92 {
93 reg |= CMC_RPC_LPFEN_MASK;
94 }
95 else
96 {
97 reg &= ~CMC_RPC_LPFEN_MASK;
98 }
99 if (config->resetFilterEnable)
100 {
101 reg |= (CMC_RPC_FILTEN_MASK | CMC_RPC_FILTCFG(config->resetFilterWidth));
102 }
103 else
104 {
105 reg &= ~(CMC_RPC_FILTEN_MASK | CMC_RPC_FILTCFG_MASK);
106 }
107 base->RPC = reg;
108 }
109
110 #if (defined(FSL_FEATURE_MCX_CMC_HAS_SRAM_DIS_REG) && FSL_FEATURE_MCX_CMC_HAS_SRAM_DIS_REG)
111 /*!
112 * brief Power off the selected system SRAM always.
113 *
114 * This function powers off the selected system SRAM always. The SRAM arrays should
115 * not be accessed while they are shut down. SRAM array contents are not retained
116 * if they are powered off.
117 *
118 * param base CMC peripheral base address.
119 * param mask Bitmap of the SRAM arrays to be powered off all modes.
120 */
CMC_PowerOffSRAMAllMode(CMC_Type * base,uint32_t mask)121 void CMC_PowerOffSRAMAllMode(CMC_Type *base, uint32_t mask)
122 {
123 uint32_t reg = base->SRAMDIS[0];
124 uint32_t maskToSet = mask & ((uint32_t)kCMC_AllSramArrays);
125
126 reg &= ~((uint32_t)kCMC_AllSramArrays);
127 reg |= CMC_SRAMDIS_DIS(maskToSet);
128 base->SRAMDIS[0] = reg;
129 }
130
131 /*!
132 * brief Power off the selected system SRAm during low power mode only.
133 *
134 * This function powers off the selected system SRAM only during low power mode.
135 * SRAM array contents are not retained if they are power off.
136 *
137 * param base CMC peripheral base address.
138 * param mask Bitmap of the SRAM arrays to be power off during low power mode only.
139 */
CMC_PowerOffSRAMLowPowerOnly(CMC_Type * base,uint32_t mask)140 void CMC_PowerOffSRAMLowPowerOnly(CMC_Type *base, uint32_t mask)
141 {
142 uint32_t reg = base->SRAMRET[0];
143 uint32_t maskToSet = mask & ((uint32_t)kCMC_AllSramArrays);
144
145 reg &= ~((uint32_t)kCMC_AllSramArrays);
146 reg |= CMC_SRAMRET_RET(maskToSet);
147 base->SRAMRET[0] = reg;
148 }
149 #endif /* FSL_FEATURE_MCX_CMC_HAS_SRAM_DIS_REG */
150
151 #if (defined(FSL_FEATURE_MCX_CMC_HAS_NO_FLASHCR_WAKE) && FSL_FEATURE_MCX_CMC_HAS_NO_FLASHCR_WAKE)
152 /*!
153 * brief Configs the low power mode of the on-chip flash memory.
154 *
155 * This function configs the low power mode of the on-chip flash memory.
156 *
157 * param base CMC peripheral base address.
158 * param doze true: Flash is disabled while core is sleeping
159 * false: No effect.
160 * param disable true: Flash memory is placed in low power state.
161 * false: No effect.
162 */
CMC_ConfigFlashMode(CMC_Type * base,bool doze,bool disable)163 void CMC_ConfigFlashMode(CMC_Type *base, bool doze, bool disable)
164 {
165 uint32_t reg = 0UL;
166
167 reg |= (disable ? CMC_FLASHCR_FLASHDIS(1U) : CMC_FLASHCR_FLASHDIS(0U)) |
168 (doze ? CMC_FLASHCR_FLASHDOZE(1U) : CMC_FLASHCR_FLASHDOZE(0U));
169 base->FLASHCR = reg;
170 }
171 #else
172 /*!
173 * brief Configs the low power mode of the on-chip flash memory.
174 *
175 * This function config the low power mode of the on-chip flash memory.
176 *
177 * param base CMC peripheral base address.
178 * param wake
179 * true - Flash will exit low power state during the flash memory accesses.
180 * false - No effect.
181 * param doze
182 * true - Flash is disabled while core is sleeping
183 * false - No effect.
184 * param disable
185 * true - Flash memory is placed in low power state.
186 * false - No effect.
187 */
CMC_ConfigFlashMode(CMC_Type * base,bool wake,bool doze,bool disable)188 void CMC_ConfigFlashMode(CMC_Type *base, bool wake, bool doze, bool disable)
189 {
190 uint32_t reg = 0UL;
191
192 reg |= (disable ? CMC_FLASHCR_FLASHDIS(1U) : CMC_FLASHCR_FLASHDIS(0U)) |
193 (doze ? CMC_FLASHCR_FLASHDOZE(1U) : CMC_FLASHCR_FLASHDOZE(0U)) |
194 (wake ? CMC_FLASHCR_FLASHWAKE(1U) : CMC_FLASHCR_FLASHWAKE(0U));
195 base->FLASHCR = reg;
196 }
197 #endif /* FSL_FEATURE_MCX_CMC_HAS_NO_FLASHCR_WAKE */
198
199 /*!
200 * brief Prepares to enter stop modes.
201 *
202 * This function should be called before entering low power modes.
203 *
204 */
CMC_PreEnterLowPowerMode(void)205 void CMC_PreEnterLowPowerMode(void)
206 {
207 g_savedPrimask = DisableGlobalIRQ();
208 __ISB();
209 }
210
211 /*!
212 * brief Recovers after wake up from stop modes.
213 *
214 * This function should be called after waking up from low power modes.
215 * This function should be used with CMC_PreEnterLowPowerMode()
216 *
217 */
CMC_PostExitLowPowerMode(void)218 void CMC_PostExitLowPowerMode(void)
219 {
220 EnableGlobalIRQ(g_savedPrimask);
221 __ISB();
222 }
223
224 /*!
225 * brief Configs the entry into the same low power mode for each power domains.
226 *
227 * This function provides the feature to entry into the same low power mode for each power
228 * domains. Before invoking this function, please ensure the selected power mode have been allowed.
229 *
230 * param base CMC peripheral base address.
231 * param lowPowerMode The low power mode to be entered. See @ref cmc_low_power_mode_t for the details.
232 *
233 */
CMC_GlobalEnterLowPowerMode(CMC_Type * base,cmc_low_power_mode_t lowPowerMode)234 void CMC_GlobalEnterLowPowerMode(CMC_Type *base, cmc_low_power_mode_t lowPowerMode)
235 {
236 /* Note: unlock the CKCTRL register if this API will be reinvoked later. */
237 CMC_SetClockMode(base, kCMC_GateAllSystemClocksEnterLowPowerMode);
238 CMC_SetGlobalPowerMode(base, lowPowerMode);
239 /* Before executing WFI instruction read back the last register to
240 * ensure all registers writes have completed. */
241 (void)base->GPMCTRL;
242 /* Set the core into DeepSleep mode. */
243 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
244 __DSB();
245 __WFI();
246 __ISB();
247 }
248
249 /*!
250 * brief Configs the entry into different low power modes for each of the power domains.
251 *
252 * This function provides the feature to entry into different low power modes for
253 * each power domains. Before invoking this function please ensure the selected
254 * modes are allowed.
255 *
256 * param base CMC peripheral base address.
257 * param base config Pointer to the cmc_power_domain_config_t structure.
258 */
CMC_EnterLowPowerMode(CMC_Type * base,const cmc_power_domain_config_t * config)259 void CMC_EnterLowPowerMode(CMC_Type *base, const cmc_power_domain_config_t *config)
260 {
261 assert(config != NULL);
262
263 #if (CMC_PMCTRL_COUNT > 1U)
264 /* The WAKE domain must never be configured to a lower power mode compared with main power mode. */
265 assert(config->wake_domain <= config->main_domain);
266 #endif /* (CMC_PMCTRL_COUNT > 1U) */
267
268 if (config->clock_mode < kCMC_GateAllSystemClocksEnterLowPowerMode)
269 {
270 /* In This case the power domain doesn't need to be placed in low power state. */
271 /* Note: unlock the register if this API will be reinvoked later. */
272 CMC_SetClockMode(base, config->clock_mode);
273
274 CMC_SetMAINPowerMode(base, kCMC_ActiveOrSleepMode);
275 #if (CMC_PMCTRL_COUNT > 1U)
276 CMC_SetWAKEPowerMode(base, kCMC_ActiveOrSleepMode);
277 #endif /* (CMC_PMCTRL_COUNT > 1U) */
278
279 /* Before executing WFI instruction read back the last register to
280 * ensure all registers writes have completed. */
281 (void)base->CKCTRL;
282 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
283 __DSB();
284 __WFI();
285 __ISB();
286 }
287 else
288 {
289 /* Note: unlock the register if this API will be reinvoked later. */
290 CMC_SetClockMode(base, kCMC_GateAllSystemClocksEnterLowPowerMode);
291 CMC_SetMAINPowerMode(base, config->main_domain);
292 #if (CMC_PMCTRL_COUNT > 1U)
293 CMC_SetWAKEPowerMode(base, config->wake_domain);
294 #endif /* (CMC_PMCTRL_COUNT > 1U) */
295
296 /* Before execute WFI instruction read back the last register to
297 * ensure all registers writes have completed. */
298 #if (CMC_PMCTRL_COUNT > 1U)
299 if ((CMC_GetWAKEPowerMode(base) == config->wake_domain) && (CMC_GetMAINPowerMode(base) == config->main_domain))
300 {
301 #endif /* (CMC_PMCTRL_COUNT > 1U) */
302 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
303 __DSB();
304 __WFI();
305 __ISB();
306 #if (CMC_PMCTRL_COUNT > 1U)
307 }
308 #endif /* (CMC_PMCTRL_COUNT > 1U) */
309 }
310 }
311