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