Skip to content

Commit 5ea2df0

Browse files
committed
soc: mcxw: Add Power Management support
Add PM support for MCXW SoC's Signed-off-by: Mahesh Mahadevan <[email protected]>
1 parent e45954c commit 5ea2df0

File tree

6 files changed

+229
-0
lines changed

6 files changed

+229
-0
lines changed

soc/nxp/mcx/mcxw/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ config SOC_FAMILY_MCXW
1818
select SOC_EARLY_INIT_HOOK
1919
select CLOCK_CONTROL
2020
select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE
21+
select HAS_PM

soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ zephyr_sources_ifdef(CONFIG_NXP_NBU
1010
../../../common/nxp_nbu.c
1111
)
1212

13+
zephyr_sources_ifdef(CONFIG_PM power.c)
14+
1315
zephyr_include_directories(./)
1416

1517
set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "")

soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ config NUM_IRQS
88
default 77 if SOC_MCXW727C
99
default 75
1010

11+
config MCUX_LPTMR_TIMER
12+
default y if PM
13+
14+
DT_LPTMR_PATH := $(dt_nodelabel_path,lptmr0)
1115
config SYS_CLOCK_HW_CYCLES_PER_SEC
1216
default 96000000 if CORTEX_M_SYSTICK
17+
default $(dt_node_int_prop_int,$(DT_LPTMR_PATH),clock-frequency) if MCUX_LPTMR_TIMER
1318

1419
config MCUX_FLASH_K4_API
1520
default y

soc/nxp/mcx/mcxw/mcxw7xx/power.c

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <zephyr/kernel.h>
7+
#include <zephyr/pm/pm.h>
8+
#include "fsl_cmc.h"
9+
#include "fsl_spc.h"
10+
#include "fsl_vbat.h"
11+
12+
#include <zephyr/logging/log.h>
13+
14+
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
15+
16+
#define WUU_WAKEUP_LPTMR_IDX 0
17+
18+
/*
19+
* 1. Set power mode protection
20+
* 2. Disable low power mode debug
21+
* 3. Enable Flash Doze mode.
22+
*/
23+
static void set_cmc_configuration(void)
24+
{
25+
CMC_SetPowerModeProtection(CMC0, kCMC_AllowAllLowPowerModes);
26+
CMC_LockPowerModeProtectionSetting(CMC0);
27+
CMC_EnableDebugOperation(CMC0, IS_ENABLED(CONFIG_DEBUG));
28+
CMC_ConfigFlashMode(CMC0, false, false, false);
29+
}
30+
31+
/*
32+
* Disable Backup SRAM regulator, FRO16K and Bandgap which
33+
* locates in VBAT power domain for most of power modes.
34+
*
35+
*/
36+
static void deinit_vbat(void)
37+
{
38+
VBAT_EnableBackupSRAMRegulator(VBAT0, false);
39+
VBAT_EnableFRO16k(VBAT0, false);
40+
while (VBAT_CheckFRO16kEnabled(VBAT0)) {
41+
};
42+
VBAT_EnableBandgap(VBAT0, false);
43+
while (VBAT_CheckBandgapEnabled(VBAT0)) {
44+
};
45+
}
46+
47+
/* Invoke Low Power/System Off specific Tasks */
48+
__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
49+
{
50+
/* Set PRIMASK */
51+
__disable_irq();
52+
/* Set BASEPRI to 0 */
53+
irq_unlock(0);
54+
55+
if (state == PM_STATE_RUNTIME_IDLE) {
56+
k_cpu_idle();
57+
return;
58+
}
59+
60+
set_cmc_configuration();
61+
deinit_vbat();
62+
63+
switch (state) {
64+
case PM_STATE_SUSPEND_TO_IDLE:
65+
cmc_power_domain_config_t config;
66+
67+
if (substate_id == 0) {
68+
/* Set NBU into Sleep Mode */
69+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL &
70+
(~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
71+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x1);
72+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
73+
74+
/* Set MAIN_CORE and MAIN_WAKE power domain into sleep mode. */
75+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
76+
config.main_domain = kCMC_SleepMode;
77+
config.wake_domain = kCMC_SleepMode;
78+
CMC_EnterLowPowerMode(CMC0, &config);
79+
} else if (substate_id == 1) {
80+
} else {
81+
/* Nothing to do */
82+
}
83+
break;
84+
case PM_STATE_STANDBY:
85+
/* Enable CORE VDD Voltage scaling. */
86+
SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(SPC0, true);
87+
88+
/* Set NBU into Deep Sleep Mode */
89+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
90+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x3);
91+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
92+
93+
/* Set MAIN_CORE and MAIN_WAKE power domain into Deep Sleep Mode. */
94+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
95+
config.main_domain = kCMC_DeepSleepMode;
96+
config.wake_domain = kCMC_DeepSleepMode;
97+
98+
CMC_EnterLowPowerMode(CMC0, &config);
99+
100+
break;
101+
default:
102+
LOG_DBG("Unsupported power state %u", state);
103+
break;
104+
}
105+
}
106+
107+
/* Handle SOC specific activity after Low Power Mode Exit */
108+
__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
109+
{
110+
ARG_UNUSED(state);
111+
ARG_UNUSED(substate_id);
112+
113+
/* Clear PRIMASK */
114+
__enable_irq();
115+
116+
if (state == PM_STATE_RUNTIME_IDLE) {
117+
return;
118+
}
119+
120+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain0)) {
121+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain0);
122+
}
123+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain1)) {
124+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain1);
125+
}
126+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain2)) {
127+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK));
128+
RFMC->RF2P4GHZ_CTRL &= ~RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
129+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain2);
130+
}
131+
SPC_ClearLowPowerRequest(SPC0);
132+
}
133+
134+
/*
135+
* In active mode, all HVDs/LVDs are disabled.
136+
* DCDC regulated to 1.8V, Core LDO regulated to 1.1V;
137+
* In low power modes, all HVDs/LVDs are disabled.
138+
* Bandgap is disabled, DCDC regulated to 1.25V, Core LDO regulated to 1.05V.
139+
*/
140+
__weak void set_spc_configuration(void)
141+
{
142+
/* Disable LVDs and HVDs in Active mode. */
143+
SPC_EnableActiveModeCoreHighVoltageDetect(SPC0, false);
144+
SPC_EnableActiveModeCoreLowVoltageDetect(SPC0, false);
145+
SPC_EnableActiveModeSystemHighVoltageDetect(SPC0, false);
146+
SPC_EnableActiveModeSystemLowVoltageDetect(SPC0, false);
147+
SPC_EnableActiveModeIOHighVoltageDetect(SPC0, false);
148+
SPC_EnableActiveModeIOLowVoltageDetect(SPC0, false);
149+
while (SPC_GetBusyStatusFlag(SPC0)) {
150+
}
151+
152+
spc_active_mode_regulators_config_t active_mode_regulator;
153+
154+
active_mode_regulator.bandgapMode = kSPC_BandgapEnabledBufferDisabled;
155+
active_mode_regulator.lpBuff = false;
156+
/* DCDC regulate to 1.8V. */
157+
active_mode_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_SafeModeVoltage;
158+
active_mode_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength;
159+
active_mode_regulator.SysLDOOption.SysLDOVoltage = kSPC_SysLDO_NormalVoltage;
160+
active_mode_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_NormalDriveStrength;
161+
/* Core LDO regulate to 1.1V. */
162+
active_mode_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
163+
#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
164+
active_mode_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
165+
#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
166+
167+
SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &active_mode_regulator.DCDCOption);
168+
169+
while (SPC_GetBusyStatusFlag(SPC0)) {
170+
}
171+
172+
SPC_SetActiveModeSystemLDORegulatorConfig(SPC0, &active_mode_regulator.SysLDOOption);
173+
174+
SPC_SetActiveModeBandgapModeConfig(SPC0, active_mode_regulator.bandgapMode);
175+
176+
SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &active_mode_regulator.CoreLDOOption);
177+
178+
SPC_EnableActiveModeCMPBandgapBuffer(SPC0, active_mode_regulator.lpBuff);
179+
180+
spc_lowpower_mode_regulators_config_t low_power_regulator;
181+
182+
low_power_regulator.lpIREF = false;
183+
low_power_regulator.bandgapMode = kSPC_BandgapDisabled;
184+
low_power_regulator.lpBuff = false;
185+
low_power_regulator.CoreIVS = false;
186+
low_power_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_LowUnderVoltage;
187+
low_power_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_LowDriveStrength;
188+
low_power_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_LowDriveStrength;
189+
low_power_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
190+
low_power_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_LowDriveStrength;
191+
192+
SPC_SetLowPowerModeRegulatorsConfig(SPC0, &low_power_regulator);
193+
194+
SPC_SetLowPowerWakeUpDelay(SPC0, 0xFFFFU);
195+
}
196+
197+
void nxp_mcxw7x_power_init(void)
198+
{
199+
set_spc_configuration();
200+
/* Enable LPTMR0 as wakeup source */
201+
NXP_ENABLE_WAKEUP_SIGNAL(WUU_WAKEUP_LPTMR_IDX);
202+
}

soc/nxp/mcx/mcxw/mcxw7xx/soc.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,17 @@
1515
#include <fsl_ccm32k.h>
1616
#include <fsl_common.h>
1717
#include <fsl_clock.h>
18+
#include <fsl_spc.h>
19+
#include <fsl_wuu.h>
1820

1921
extern uint32_t SystemCoreClock;
2022
extern void nxp_nbu_init(void);
2123

24+
void mcxw7xx_set_wakeup(int32_t sig)
25+
{
26+
WUU_SetInternalWakeUpModulesConfig(WUU0, sig, kWUU_InternalModuleInterrupt);
27+
}
28+
2229
__weak void clock_init(void)
2330
{
2431
/* Unlock Reference Clock Status Registers to allow writes */
@@ -234,6 +241,10 @@ void soc_early_init_hook(void)
234241
/* Smart power switch initialization */
235242
vbat_init();
236243

244+
#if CONFIG_PM
245+
nxp_mcxw7x_power_init();
246+
#endif
247+
237248
/* restore interrupt state */
238249
irq_unlock(oldLevel);
239250

soc/nxp/mcx/mcxw/mcxw7xx/soc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@
1313

1414
#define nbu_handler RF_IMU0_IRQHandler
1515

16+
#undef NXP_ENABLE_WAKEUP_SIGNAL
17+
extern void mcxw7xx_set_wakeup(int32_t sig);
18+
#define NXP_ENABLE_WAKEUP_SIGNAL(sig) mcxw7xx_set_wakeup(sig)
19+
20+
#if CONFIG_PM
21+
extern void nxp_mcxw7x_power_init(void);
22+
#endif
23+
1624
#endif /* _SOC__H_ */

0 commit comments

Comments
 (0)