1 /*
2 * Copyright 2019-2021, NXP
3 * All rights reserved.
4 *
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_pgmc.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.pgmc"
18 #endif
19
20 /*!
21 * @brief The structure of MIF signal.
22 */
23 typedef struct
24 {
25 __IO uint32_t SIGNAL; /*!< MIF MLPL control of each signal. */
26 __IO uint32_t DELAY; /*!< MIF Delay of each signal */
27 uint32_t RESERVED[2];
28 } PGMC_MIF_SIGNAL_Type;
29
30 /*******************************************************************************
31 * Variables
32 ******************************************************************************/
33
34 /*******************************************************************************
35 * Code
36 ******************************************************************************/
37
38 /*!
39 * brief Makes the BPC module controlled by the target CPU power mode(Such as Wait mode).
40 *
41 * This function makes the module controlled by four typical CPU power modes, It also configs the resource domain and
42 * set memory low power level.
43 *
44 * param base PGMC basic power controller base address.
45 * param mode Target CPU power mode.
46 * param option The pointer of @ref pgmc_bpc_cpu_power_mode_option_t structure.
47 */
PGMC_BPC_ControlPowerDomainByCpuPowerMode(PGMC_BPC_Type * base,pgmc_cpu_mode_t mode,const pgmc_bpc_cpu_power_mode_option_t * option)48 void PGMC_BPC_ControlPowerDomainByCpuPowerMode(PGMC_BPC_Type *base,
49 pgmc_cpu_mode_t mode,
50 const pgmc_bpc_cpu_power_mode_option_t *option)
51 {
52 assert(option != NULL);
53
54 uint32_t tmp32 = base->BPC_SSAR_SAVE_CTRL;
55
56 base->BPC_MODE = PGMC_BPC_BPC_MODE_DOMAIN_ASSIGN(option->assignDomain) |
57 PGMC_BPC_BPC_MODE_CTRL_MODE(kPGMC_ControlledByCpuPowerMode);
58 switch (mode)
59 {
60 case kPGMC_RunMode:
61 tmp32 |= PGMC_BPC_BPC_SSAR_SAVE_CTRL_SAVE_AT_RUN_MASK;
62 break;
63 case kPGMC_WaitMode:
64 if (option->powerOff)
65 {
66 base->BPC_POWER_CTRL |= PGMC_BPC_BPC_POWER_CTRL_PWR_OFF_AT_WAIT_MASK;
67 }
68 tmp32 |= PGMC_BPC_BPC_SSAR_SAVE_CTRL_SAVE_AT_WAIT_MASK;
69 break;
70 case kPGMC_StopMode:
71 if (option->powerOff)
72 {
73 base->BPC_POWER_CTRL |= PGMC_BPC_BPC_POWER_CTRL_PWR_OFF_AT_STOP_MASK;
74 }
75 tmp32 |= PGMC_BPC_BPC_SSAR_SAVE_CTRL_SAVE_AT_SUSPEND_MASK;
76 break;
77 case kPGMC_SuspendMode:
78 if (option->powerOff)
79 {
80 base->BPC_POWER_CTRL |= PGMC_BPC_BPC_POWER_CTRL_PWR_OFF_AT_SUSPEND_MASK;
81 }
82 tmp32 |= PGMC_BPC_BPC_SSAR_SAVE_CTRL_SAVE_AT_SUSPEND_MASK;
83 break;
84 default:
85 assert(false);
86 break;
87 }
88
89 if (option->stateSave)
90 {
91 base->BPC_SSAR_SAVE_CTRL = tmp32;
92 }
93 }
94
95 /*!
96 * brief Makes the BPC module controlled by the target set points.
97 *
98 * This function makes the module controlled by specific set point, It also supports set memory lowe power level.
99 *
100 * note When setting more than one set point, use "|" between the map values in @ref _pgmc_setpoint_map.
101 *
102 * param base PGMC basic power controller base address.
103 * param setPointMap Should be the OR'ed value of @ref _pgmc_setpoint_map.
104 * param option The pointer of @ref pgmc_bpc_setpoint_mode_option_t structure.
105 */
PGMC_BPC_ControlPowerDomainBySetPointMode(PGMC_BPC_Type * base,uint32_t setPointMap,const pgmc_bpc_setpoint_mode_option_t * option)106 void PGMC_BPC_ControlPowerDomainBySetPointMode(PGMC_BPC_Type *base,
107 uint32_t setPointMap,
108 const pgmc_bpc_setpoint_mode_option_t *option)
109 {
110 assert(option != NULL);
111
112 setPointMap &= 0xFFFFU;
113
114 base->BPC_MODE = PGMC_BPC_BPC_MODE_CTRL_MODE(kPGMC_ControlledBySetPoint);
115 if (option->powerOff)
116 {
117 base->BPC_POWER_CTRL |= PGMC_BPC_BPC_POWER_CTRL_PWR_OFF_AT_SP(setPointMap);
118 }
119
120 if (option->stateSave)
121 {
122 base->BPC_SSAR_SAVE_CTRL = PGMC_BPC_BPC_SSAR_SAVE_CTRL_SAVE_AT_SP(setPointMap);
123 }
124 }
125
126 /*!
127 * brief Controls the selected power domain by software mode.
128 *
129 * note The function is used to control power domain when the CPU is in RUN mode.
130 *
131 * param base PGMC basic power controller base address.
132 * param powerOff Power On/Off power domain in software mode.
133 * - \b true Power off the power domain in software mode.
134 * - \b false Power on the power domain in software mode.
135 */
PGMC_BPC_ControlPowerDomainBySoftwareMode(PGMC_BPC_Type * base,bool powerOff)136 void PGMC_BPC_ControlPowerDomainBySoftwareMode(PGMC_BPC_Type *base, bool powerOff)
137 {
138 if (powerOff)
139 {
140 base->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_OFF_SOFT_MASK | PGMC_BPC_BPC_POWER_CTRL_ISO_ON_SOFT_MASK);
141 }
142 else
143 {
144 base->BPC_POWER_CTRL |= (PGMC_BPC_BPC_POWER_CTRL_PSW_ON_SOFT_MASK | PGMC_BPC_BPC_POWER_CTRL_ISO_OFF_SOFT_MASK);
145 }
146 }
147
148 /*!
149 * brief Powers off the CPC core module by the target CPU power mode(Such as Wait mode).
150 *
151 * param base CPC CORE module base address.
152 * param mode Target CPU power mode.
153 */
PGMC_CPC_CORE_PowerOffByCpuPowerMode(PGMC_CPC_Type * base,pgmc_cpu_mode_t mode)154 void PGMC_CPC_CORE_PowerOffByCpuPowerMode(PGMC_CPC_Type *base, pgmc_cpu_mode_t mode)
155 {
156 base->CPC_CORE_MODE = PGMC_CPC_CPC_CORE_MODE_CTRL_MODE(kPGMC_ControlledByCpuPowerMode);
157 switch (mode)
158 {
159 case kPGMC_RunMode:
160 break;
161 case kPGMC_WaitMode:
162 base->CPC_CORE_POWER_CTRL |= PGMC_CPC_CPC_CORE_POWER_CTRL_PWR_OFF_AT_WAIT_MASK;
163 break;
164 case kPGMC_StopMode:
165 base->CPC_CORE_POWER_CTRL |= PGMC_CPC_CPC_CORE_POWER_CTRL_PWR_OFF_AT_STOP_MASK;
166 break;
167 case kPGMC_SuspendMode:
168 base->CPC_CORE_POWER_CTRL |= PGMC_CPC_CPC_CORE_POWER_CTRL_PWR_OFF_AT_SUSPEND_MASK;
169 break;
170 default:
171 assert(false);
172 break;
173 }
174 }
175
176 /*!
177 * brief Makes the CPC CACHE module controlled by the target CPU power mode(Such as Wait mode).
178 *
179 * This function makes the module controlled by four typical CPU power modes, it also can set memory low power level.
180 *
181 * param base CPC CACHE module base address.
182 * param mode Target CPU power mode.
183 * param memoryLowPowerLevel Memory low power level.
184 */
PGMC_CPC_CACHE_ControlByCpuPowerMode(PGMC_CPC_Type * base,pgmc_cpu_mode_t mode,pgmc_memory_low_power_level_t memoryLowPowerLevel)185 void PGMC_CPC_CACHE_ControlByCpuPowerMode(PGMC_CPC_Type *base,
186 pgmc_cpu_mode_t mode,
187 pgmc_memory_low_power_level_t memoryLowPowerLevel)
188 {
189 uint32_t temp32;
190
191 base->CPC_CACHE_MODE = PGMC_CPC_CPC_CACHE_MODE_CTRL_MODE(kPGMC_ControlledByCpuPowerMode);
192 temp32 = base->CPC_CACHE_CM_CTRL;
193 switch (mode)
194 {
195 case kPGMC_RunMode:
196 temp32 &= ~PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_RUN_MASK;
197 base->CPC_CACHE_CM_CTRL = temp32 | PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_RUN(memoryLowPowerLevel);
198 break;
199 case kPGMC_WaitMode:
200 temp32 &= ~PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_WAIT_MASK;
201 base->CPC_CACHE_CM_CTRL = temp32 | PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_WAIT(memoryLowPowerLevel);
202 break;
203 case kPGMC_StopMode:
204 temp32 &= ~PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_STOP_MASK;
205 base->CPC_CACHE_CM_CTRL = temp32 | PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_STOP(memoryLowPowerLevel);
206 break;
207 case kPGMC_SuspendMode:
208 temp32 &= ~PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_SUSPEND_MASK;
209 base->CPC_CACHE_CM_CTRL = temp32 | PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_AT_SUSPEND(memoryLowPowerLevel);
210 break;
211 default:
212 assert(false);
213 break;
214 }
215 }
216
217 /*!
218 * brief Makes the CPC CACHE module controlled by the target set points.
219 *
220 * This function makes the module controlled by specific set point, It also supports set memory lowe power level.
221 *
222 * note When setting more than one set point, use "|" between the map values in @ref _pgmc_setpoint_map.
223 *
224 * param base CPC CACHE module base address.
225 * param setPointMap Should be the OR'ed value of @ref _pgmc_setpoint_map.
226 * param memoryLowPowerLevel Memory low power level.
227 */
PGMC_CPC_CACHE_ControlBySetPointMode(PGMC_CPC_Type * base,uint32_t setPointMap,pgmc_memory_low_power_level_t memoryLowPowerLevel)228 void PGMC_CPC_CACHE_ControlBySetPointMode(PGMC_CPC_Type *base,
229 uint32_t setPointMap,
230 pgmc_memory_low_power_level_t memoryLowPowerLevel)
231 {
232 uint32_t setPointIndex = 0UL;
233 uint32_t tmp32 = 0UL;
234 uint32_t regIndex = 0UL;
235 volatile uint32_t *ptrMemSpCtrlReg = NULL;
236
237 setPointMap &= 0xFFFFU;
238
239 base->CPC_CACHE_MODE = PGMC_CPC_CPC_CACHE_MODE_CTRL_MODE(kPGMC_ControlledBySetPoint);
240
241 ptrMemSpCtrlReg = &(base->CPC_CACHE_SP_CTRL_0);
242 for (regIndex = 0UL; regIndex < 2UL; regIndex++)
243 {
244 ptrMemSpCtrlReg += regIndex;
245 tmp32 = *ptrMemSpCtrlReg;
246 for (setPointIndex = 0UL; setPointIndex < 8UL; setPointIndex++)
247 {
248 if (0UL != (setPointMap & (1UL << ((regIndex * 8UL) + setPointIndex))))
249 {
250 tmp32 &= ~((uint32_t)PGMC_CPC_CPC_CACHE_SP_CTRL_0_MLPL_AT_SP0_MASK << (setPointIndex * 4U));
251 tmp32 |= ((uint32_t)memoryLowPowerLevel << (setPointIndex * 4U));
252 }
253 }
254 *ptrMemSpCtrlReg = tmp32;
255 }
256 }
257
258 /*!
259 * brief Requests CPC cache module's memory low power level change by software mode.
260 *
261 * note If request memory low power level change, must wait the MLPL transition complete.
262 *
263 * param base CPC LMEM module base address.
264 */
PGMC_CPC_CACHE_TriggerMLPLSoftwareChange(PGMC_CPC_Type * base)265 void PGMC_CPC_CACHE_TriggerMLPLSoftwareChange(PGMC_CPC_Type *base)
266 {
267 base->CPC_CACHE_CM_CTRL |= PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_SOFT_MASK;
268
269 /* If request software change, check the MLPL transition status. */
270 while (0UL != ((base->CPC_CACHE_CM_CTRL) & PGMC_CPC_CPC_CACHE_CM_CTRL_MLPL_SOFT_MASK))
271 {
272 }
273 }
274
275 /*!
276 * brief Makes the CPC LMEM module controlled by the target CPU power mode(Such as Wait mode).
277 *
278 * This function makes the module controlled by four typical CPU power modes, it also can set memory low power level.
279 *
280 * param base CPC LMEM module base address.
281 * param mode Target CPU power mode.
282 * param memoryLowPowerLevel Memory low power level.
283 */
PGMC_CPC_LMEM_ControlByCpuPowerMode(PGMC_CPC_Type * base,pgmc_cpu_mode_t mode,pgmc_memory_low_power_level_t memoryLowPowerLevel)284 void PGMC_CPC_LMEM_ControlByCpuPowerMode(PGMC_CPC_Type *base,
285 pgmc_cpu_mode_t mode,
286 pgmc_memory_low_power_level_t memoryLowPowerLevel)
287 {
288 uint32_t temp32;
289
290 base->CPC_LMEM_MODE = PGMC_CPC_CPC_LMEM_MODE_CTRL_MODE(kPGMC_ControlledByCpuPowerMode);
291
292 temp32 = base->CPC_LMEM_CM_CTRL;
293 switch (mode)
294 {
295 case kPGMC_RunMode:
296 temp32 &= ~PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_RUN_MASK;
297 base->CPC_LMEM_CM_CTRL = temp32 | PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_RUN(memoryLowPowerLevel);
298 break;
299 case kPGMC_WaitMode:
300 temp32 &= ~PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_WAIT_MASK;
301 base->CPC_LMEM_CM_CTRL = temp32 | PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_WAIT(memoryLowPowerLevel);
302 break;
303 case kPGMC_StopMode:
304 temp32 &= ~PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_STOP_MASK;
305 base->CPC_LMEM_CM_CTRL = temp32 | PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_STOP(memoryLowPowerLevel);
306 break;
307 case kPGMC_SuspendMode:
308 temp32 &= ~PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_SUSPEND_MASK;
309 base->CPC_LMEM_CM_CTRL = temp32 | PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_AT_SUSPEND(memoryLowPowerLevel);
310 break;
311 default:
312 assert(false);
313 break;
314 }
315 }
316
317 /*!
318 * brief Makes the CPC LMEM module controlled by the target set points.
319 *
320 * This function makes the module controlled by specific set point, It also supports set memory lowe power level.
321 *
322 * note When setting more than one set point, use "|" between the map values in @ref _pgmc_setpoint_map.
323 *
324 * param base CPC LMEM module base address.
325 * param setPointMap Should be the OR'ed value of @ref _pgmc_setpoint_map.
326 * param memoryLowPowerLevel Memory low power level.
327 */
PGMC_CPC_LMEM_ControlBySetPointMode(PGMC_CPC_Type * base,uint32_t setPointMap,pgmc_memory_low_power_level_t memoryLowPowerLevel)328 void PGMC_CPC_LMEM_ControlBySetPointMode(PGMC_CPC_Type *base,
329 uint32_t setPointMap,
330 pgmc_memory_low_power_level_t memoryLowPowerLevel)
331 {
332 uint32_t setPointIndex = 0UL;
333 uint32_t tmp32 = 0UL;
334 uint32_t regIndex = 0UL;
335 volatile uint32_t *ptrMemSpCtrlReg = NULL;
336
337 setPointMap &= 0xFFFFU;
338
339 base->CPC_LMEM_MODE = PGMC_CPC_CPC_LMEM_MODE_CTRL_MODE(kPGMC_ControlledBySetPoint);
340
341 ptrMemSpCtrlReg = &(base->CPC_LMEM_SP_CTRL_0);
342 for (regIndex = 0UL; regIndex < 2UL; regIndex++)
343 {
344 ptrMemSpCtrlReg += regIndex;
345 tmp32 = *ptrMemSpCtrlReg;
346 for (setPointIndex = 0UL; setPointIndex < 8UL; setPointIndex++)
347 {
348 if (0UL != (setPointMap & (1UL << ((regIndex * 8UL) + setPointIndex))))
349 {
350 tmp32 &= ~((uint32_t)PGMC_CPC_CPC_LMEM_SP_CTRL_0_MLPL_AT_SP0_MASK << (setPointIndex * 4U));
351 tmp32 |= ((uint32_t)memoryLowPowerLevel << (setPointIndex * 4U));
352 }
353 }
354 *ptrMemSpCtrlReg = tmp32;
355 }
356 }
357
358 /*!
359 * brief Requests CPC LMEM module's memory low power level change in software mode.
360 *
361 * note If request memory low power level change, must wait the MLPL transition complete.
362 *
363 * param base CPC LMEM module base address.
364 */
PGMC_CPC_LMEM_TriggerMLPLSoftwareChange(PGMC_CPC_Type * base)365 void PGMC_CPC_LMEM_TriggerMLPLSoftwareChange(PGMC_CPC_Type *base)
366 {
367 base->CPC_LMEM_CM_CTRL |= PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_SOFT_MASK;
368
369 /* If request software change, check the MLPL transition status. */
370 while (0UL != ((base->CPC_LMEM_CM_CTRL) & PGMC_CPC_CPC_LMEM_CM_CTRL_MLPL_SOFT_MASK))
371 {
372 }
373 }
374
375 /*!
376 * brief Sets the behaviour of each signal(Such as Sleep signal) in MIF.
377 *
378 * note To control the memory low power operation, this function must be invoked after selecting the
379 * memory low power level.
380 * Use case:
381 * code
382 * PGMC_BPC_ControlPowerDomainByCpuPowerMode(PGMC_BPC0_BASE, kPGMC_WaitMode, kPGMC_CM7Core,
383 * kPGMC_MLPLSleep, false);
384 * PGMC_MIF_SetSignalBehaviour(PGMC_BPC0_MIF_BASE, kPGMC_MLPLSleep, kPGMC_AssertSleepSignal);
385 * endcode
386 *
387 * param base PGMC MIF peripheral base address.
388 * param memoryLevel The selected memory low power level. For details please refer to @ref
389 * pgmc_memory_low_power_level_t.
390 * param mask The mask of MIF signal behaviour. Should be the OR'ed value of @ref _pgmc_mif_signal_behaviour
391 */
PGMC_MIF_SetSignalBehaviour(PGMC_MIF_Type * base,pgmc_memory_low_power_level_t memoryLevel,uint32_t mask)392 void PGMC_MIF_SetSignalBehaviour(PGMC_MIF_Type *base, pgmc_memory_low_power_level_t memoryLevel, uint32_t mask)
393 {
394 uint8_t signalIndex = 0U;
395 uint32_t temp32 = 0U;
396 PGMC_MIF_SIGNAL_Type *MIF_SIG = (PGMC_MIF_SIGNAL_Type *)(uint32_t)(&(base->MIF_MLPL_SLEEP));
397
398 for (signalIndex = 0U; signalIndex < 11U; signalIndex++)
399 {
400 temp32 = MIF_SIG[signalIndex].SIGNAL;
401 temp32 &= ~(1UL << (uint32_t)memoryLevel);
402 temp32 |= ((uint32_t)(mask & (1UL << signalIndex)) << (uint32_t)memoryLevel);
403 MIF_SIG[signalIndex].SIGNAL = temp32;
404 }
405 }
406
407 /*!
408 * brief Makes the PMIC module controlled by the target CPU power mode(Such as Wait mode).
409 *
410 * param base PMIC module base address.
411 * param mode Target CPU power mode.
412 */
PGMC_PPC_ControlByCpuPowerMode(PGMC_PPC_Type * base,pgmc_cpu_mode_t mode)413 void PGMC_PPC_ControlByCpuPowerMode(PGMC_PPC_Type *base, pgmc_cpu_mode_t mode)
414 {
415 base->PPC_MODE = PGMC_PPC_PPC_MODE_CTRL_MODE(kPGMC_ControlledByCpuPowerMode);
416 switch (mode)
417 {
418 case kPGMC_RunMode:
419 break;
420 case kPGMC_WaitMode:
421 base->PPC_STBY_CM_CTRL |= PGMC_PPC_PPC_STBY_CM_CTRL_STBY_ON_AT_WAIT_MASK;
422 break;
423 case kPGMC_StopMode:
424 base->PPC_STBY_CM_CTRL |= PGMC_PPC_PPC_STBY_CM_CTRL_STBY_ON_AT_STOP_MASK;
425 break;
426 case kPGMC_SuspendMode:
427 base->PPC_STBY_CM_CTRL |= PGMC_PPC_PPC_STBY_CM_CTRL_STBY_ON_AT_SUSPEND_MASK;
428 break;
429 default:
430 assert(false);
431 break;
432 }
433 }
434
435 /*!
436 * brief Makes the PMIC module controlled by the target set points.
437 *
438 * This function makes the module controlled by specific set point, It also supports PMIC standby on.
439 *
440 * note When setting more than one set point, use "|" between the map values in @ref _pgmc_setpoint_map.
441 *
442 * param base PMIC module base address.
443 * param setPointMap Should be the OR'ed value of @ref _pgmc_setpoint_map.
444 * param enableStandby true: PMIC standby on when system enters set point number and system is in standby mode.
445 * false: PMIC standby on when system enters set point number
446 */
PGMC_PPC_ControlBySetPointMode(PGMC_PPC_Type * base,uint32_t setPointMap,bool enableStandby)447 void PGMC_PPC_ControlBySetPointMode(PGMC_PPC_Type *base, uint32_t setPointMap, bool enableStandby)
448 {
449 setPointMap &= 0xFFFFU;
450
451 base->PPC_MODE = PGMC_PPC_PPC_MODE_CTRL_MODE(kPGMC_ControlledBySetPoint);
452
453 if (enableStandby)
454 {
455 base->PPC_STBY_SP_CTRL = (setPointMap << PGMC_PPC_PPC_STBY_SP_CTRL_STBY_ON_AT_SP_SLEEP_SHIFT);
456 }
457 else
458 {
459 base->PPC_STBY_SP_CTRL = setPointMap;
460 }
461 }
462