Skip to content

Commit 1e492e8

Browse files
mmahadevan108kartben
authored andcommitted
soc: nxp_rw6xx: Add support for Power Mode 3
This maps to Zephyr power state Standby. In this power state the OS Timer cannot be used as a wakeup source as it will be powered off. Hence the counter is enabled and RTC is used to keep track of system ticks and wakeup the system. Signed-off-by: Mahesh Mahadevan <[email protected]>
1 parent 15d8fd2 commit 1e492e8

File tree

2 files changed

+134
-2
lines changed

2 files changed

+134
-2
lines changed

soc/nxp/rw/Kconfig.defconfig

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,33 @@ if PM
6363
config SYS_CLOCK_TICKS_PER_SEC
6464
default 1000
6565
depends on $(dt_nodelabel_enabled,standby)
66-
endif
66+
67+
# Enable PM_DEVICE by default if STANDBY mode is enabled
68+
# as we use the TURN_OFF and TURN_ON actions to recover
69+
# from Standby mode (PM Mode 3)
70+
config PM_DEVICE
71+
default y
72+
depends on "$(dt_nodelabel_enabled,standby)"
73+
74+
# Enable PM_POLICY_DEVICE_CONSTRAINTS by default when doing PM_DEVICE.
75+
# This will allow support of device power states.
76+
config PM_POLICY_DEVICE_CONSTRAINTS
77+
default y if PM_DEVICE
78+
79+
# Enable the counter if STANDBY mode is enabled
80+
# RTC counter is the wakeup source from STANDBY mode
81+
config COUNTER
82+
default y
83+
depends on "$(dt_nodelabel_enabled,standby)"
84+
85+
config MCUX_OS_TIMER_PM_POWERED_OFF
86+
default y
87+
88+
# PM code that runs from the idle loop has a large
89+
# footprint. Hence increase the size when PM is enabled.
90+
config IDLE_STACK_SIZE
91+
default 640
92+
93+
endif # PM
6794

6895
endif # SOC_SERIES_RW6XX

soc/nxp/rw/power.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023, NXP
2+
* Copyright 2023-2025 NXP
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -11,6 +11,8 @@
1111
#include "fsl_power.h"
1212

1313
#include <zephyr/logging/log.h>
14+
#include <zephyr/drivers/timer/system_timer.h>
15+
1416
LOG_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+
2933
power_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

Comments
 (0)