11/*
2- * Copyright 2023, NXP
2+ * Copyright 2023-2025 NXP
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 */
1111#include "fsl_power.h"
1212
1313#include <zephyr/logging/log.h>
14+ #include <zephyr/drivers/timer/system_timer.h>
15+
1416LOG_MODULE_DECLARE (soc , CONFIG_SOC_LOG_LEVEL );
1517
1618/* Active mode */
@@ -26,6 +28,8 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
2628
2729#define NODE_ID DT_INST(0, nxp_pdcfg_power)
2830
31+ extern void clock_init (void );
32+
2933power_sleep_config_t slp_cfg ;
3034
3135#if DT_NODE_HAS_STATUS_OKAY (DT_NODELABEL (pin0 )) || DT_NODE_HAS_STATUS_OKAY (DT_NODELABEL (pin1 ))
@@ -56,6 +60,81 @@ static void pin1_isr(const struct device *dev)
5660}
5761#endif
5862
63+ #ifdef CONFIG_MPU
64+
65+ #define MPU_NUM_REGIONS 8
66+
67+ typedef struct mpu_conf {
68+ uint32_t CTRL ;
69+ uint32_t RNR ;
70+ uint32_t RBAR [MPU_NUM_REGIONS ];
71+ uint32_t RLAR [MPU_NUM_REGIONS ];
72+ uint32_t RBAR_A1 ;
73+ uint32_t RLAR_A1 ;
74+ uint32_t RBAR_A2 ;
75+ uint32_t RLAR_A2 ;
76+ uint32_t RBAR_A3 ;
77+ uint32_t RLAR_A3 ;
78+ uint32_t MAIR0 ;
79+ uint32_t MAIR1 ;
80+ } mpu_conf ;
81+ mpu_conf saved_mpu_conf ;
82+
83+ static void save_mpu_state (void )
84+ {
85+ uint32_t index ;
86+
87+ /*
88+ * MPU is divided in `MPU_NUM_REGIONS` regions.
89+ * Here we save those regions configuration to be restored after PM3 entry
90+ */
91+ for (index = 0U ; index < MPU_NUM_REGIONS ; index ++ ) {
92+ MPU -> RNR = index ;
93+ saved_mpu_conf .RBAR [index ] = MPU -> RBAR ;
94+ saved_mpu_conf .RLAR [index ] = MPU -> RLAR ;
95+ }
96+
97+ saved_mpu_conf .CTRL = MPU -> CTRL ;
98+ saved_mpu_conf .RNR = MPU -> RNR ;
99+ saved_mpu_conf .RBAR_A1 = MPU -> RBAR_A1 ;
100+ saved_mpu_conf .RLAR_A1 = MPU -> RLAR_A1 ;
101+ saved_mpu_conf .RBAR_A2 = MPU -> RBAR_A2 ;
102+ saved_mpu_conf .RLAR_A2 = MPU -> RLAR_A2 ;
103+ saved_mpu_conf .RBAR_A3 = MPU -> RBAR_A3 ;
104+ saved_mpu_conf .RLAR_A3 = MPU -> RLAR_A3 ;
105+ saved_mpu_conf .MAIR0 = MPU -> MAIR0 ;
106+ saved_mpu_conf .MAIR1 = MPU -> MAIR1 ;
107+ }
108+
109+ static void restore_mpu_state (void )
110+ {
111+ uint32_t index ;
112+
113+ for (index = 0U ; index < MPU_NUM_REGIONS ; index ++ ) {
114+ MPU -> RNR = index ;
115+ MPU -> RBAR = saved_mpu_conf .RBAR [index ];
116+ MPU -> RLAR = saved_mpu_conf .RLAR [index ];
117+ }
118+
119+ MPU -> RNR = saved_mpu_conf .RNR ;
120+ MPU -> RBAR_A1 = saved_mpu_conf .RBAR_A1 ;
121+ MPU -> RLAR_A1 = saved_mpu_conf .RLAR_A1 ;
122+ MPU -> RBAR_A2 = saved_mpu_conf .RBAR_A2 ;
123+ MPU -> RLAR_A2 = saved_mpu_conf .RLAR_A2 ;
124+ MPU -> RBAR_A3 = saved_mpu_conf .RBAR_A3 ;
125+ MPU -> RLAR_A3 = saved_mpu_conf .RLAR_A3 ;
126+ MPU -> MAIR0 = saved_mpu_conf .MAIR0 ;
127+ MPU -> MAIR1 = saved_mpu_conf .MAIR1 ;
128+
129+ /*
130+ * CTRL register must be restored last in case MPU was enabled,
131+ * because some MPU registers can't be programmed while the MPU is enabled
132+ */
133+ MPU -> CTRL = saved_mpu_conf .CTRL ;
134+ }
135+
136+ #endif /* CONFIG_MPU */
137+
59138/* Invoke Low Power/System Off specific Tasks */
60139__weak void pm_state_set (enum pm_state state , uint8_t substate_id )
61140{
@@ -92,6 +171,28 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
92171 break ;
93172 case PM_STATE_SUSPEND_TO_IDLE :
94173 POWER_EnterPowerMode (POWER_MODE2 , & slp_cfg );
174+ break ;
175+ case PM_STATE_STANDBY :
176+ #ifdef CONFIG_MPU
177+ /* Save MPU state before entering PM3 */
178+ save_mpu_state ();
179+ #endif /* CONFIG_MPU */
180+
181+ POWER_EnableWakeup (DT_IRQN (DT_NODELABEL (rtc )));
182+ if (POWER_EnterPowerMode (POWER_MODE3 , & slp_cfg )) {
183+ #ifdef CONFIG_MPU
184+ /* Restore MPU as is lost after PM3 exit*/
185+ restore_mpu_state ();
186+ #endif /* CONFIG_MPU */
187+ clock_init ();
188+
189+ sys_clock_idle_exit ();
190+ }
191+
192+ /* Clear the RTC wakeup bits */
193+ POWER_ClearWakeupStatus (DT_IRQN (DT_NODELABEL (rtc )));
194+ POWER_DisableWakeup (DT_IRQN (DT_NODELABEL (rtc )));
195+
95196 break ;
96197 default :
97198 LOG_DBG ("Unsupported power state %u" , state );
@@ -142,4 +243,8 @@ void nxp_rw6xx_power_init(void)
142243 IRQ_CONNECT (DT_IRQN (DT_NODELABEL (pin1 )), DT_IRQ (DT_NODELABEL (pin1 ), priority ), pin1_isr ,
143244 NULL , 0 );
144245#endif
246+
247+ /* Clear the RTC wakeup bits */
248+ POWER_ClearWakeupStatus (DT_IRQN (DT_NODELABEL (rtc )));
249+ POWER_DisableWakeup (DT_IRQN (DT_NODELABEL (rtc )));
145250}
0 commit comments