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