Skip to content

Commit 69dda9d

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 6e10236 commit 69dda9d

File tree

6 files changed

+226
-0
lines changed

6 files changed

+226
-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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ zephyr_sources_ifdef(CONFIG_NXP_NBU
1010
../../../common/nxp_nbu.c
1111
)
1212

13+
zephyr_sources_ifdef(CONFIG_PM
14+
power.c
15+
)
16+
1317
zephyr_include_directories(./)
1418

1519
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: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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+
/*
17+
* 1. Set power mode protection
18+
* 2. Disable low power mode debug
19+
* 3. Enable Flash Doze mode.
20+
*/
21+
static void set_cmc_configuration(void)
22+
{
23+
CMC_SetPowerModeProtection(CMC0, kCMC_AllowAllLowPowerModes);
24+
CMC_LockPowerModeProtectionSetting(CMC0);
25+
#ifdef CONFIG_DEBUG
26+
CMC_EnableDebugOperation(CMC0, true);
27+
#else
28+
CMC_EnableDebugOperation(CMC0, false);
29+
#endif
30+
CMC_ConfigFlashMode(CMC0, false, false, false);
31+
}
32+
33+
/*
34+
* Disable Backup SRAM regulator, FRO16K and Bandgap which
35+
* locates in VBAT power domain for most of power modes.
36+
*
37+
*/
38+
static void deinit_vbat(void)
39+
{
40+
VBAT_EnableBackupSRAMRegulator(VBAT0, false);
41+
VBAT_EnableFRO16k(VBAT0, false);
42+
while (VBAT_CheckFRO16kEnabled(VBAT0)) {
43+
};
44+
VBAT_EnableBandgap(VBAT0, false);
45+
while (VBAT_CheckBandgapEnabled(VBAT0)) {
46+
};
47+
}
48+
49+
/* Invoke Low Power/System Off specific Tasks */
50+
__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
51+
{
52+
/* Set PRIMASK */
53+
__disable_irq();
54+
/* Set BASEPRI to 0 */
55+
irq_unlock(0);
56+
57+
if (state == PM_STATE_RUNTIME_IDLE) {
58+
k_cpu_idle();
59+
return;
60+
}
61+
62+
set_cmc_configuration();
63+
deinit_vbat();
64+
65+
switch (state) {
66+
case PM_STATE_SUSPEND_TO_IDLE:
67+
cmc_power_domain_config_t config;
68+
69+
if (substate_id == 0) {
70+
/* Set NBU into Sleep Mode */
71+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
72+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x1);
73+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
74+
75+
/* Set MAIN_CORE and MAIN_WAKE power domain into sleep mode. */
76+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
77+
config.main_domain = kCMC_SleepMode;
78+
config.wake_domain = kCMC_SleepMode;
79+
CMC_EnterLowPowerMode(CMC0, &config);
80+
} else if (substate_id == 1) {
81+
} else {
82+
/* Nothing to do */
83+
}
84+
break;
85+
case PM_STATE_STANDBY:
86+
/* Enable CORE VDD Voltage scaling. */
87+
SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(SPC0, true);
88+
89+
/* Set NBU into Deep Sleep Mode */
90+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) |
91+
RFMC_RF2P4GHZ_CTRL_LP_MODE(0x3);
92+
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
93+
94+
/* Set MAIN_CORE and MAIN_WAKE power domain into Deep Sleep Mode. */
95+
config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode;
96+
config.main_domain = kCMC_DeepSleepMode;
97+
config.wake_domain = kCMC_DeepSleepMode;
98+
99+
CMC_EnterLowPowerMode(CMC0, &config);
100+
101+
break;
102+
default:
103+
LOG_DBG("Unsupported power state %u", state);
104+
break;
105+
}
106+
}
107+
108+
/* Handle SOC specific activity after Low Power Mode Exit */
109+
__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
110+
{
111+
ARG_UNUSED(state);
112+
ARG_UNUSED(substate_id);
113+
114+
/* Clear PRIMASK */
115+
__enable_irq();
116+
117+
if (state == PM_STATE_RUNTIME_IDLE) {
118+
return;
119+
}
120+
121+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain0)) {
122+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain0);
123+
}
124+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain1)) {
125+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain1);
126+
}
127+
if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain2)) {
128+
RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK));
129+
RFMC->RF2P4GHZ_CTRL &= ~RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK;
130+
SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain2);
131+
}
132+
SPC_ClearLowPowerRequest(SPC0);
133+
}
134+
135+
void nxp_mcxw7x_power_init(void)
136+
{
137+
/* Enable LPTMR0 as wakeup source */
138+
NXP_ENABLE_WAKEUP_SIGNAL(0);
139+
}

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <fsl_ccm32k.h>
1616
#include <fsl_common.h>
1717
#include <fsl_clock.h>
18+
#include "fsl_spc.h"
1819

1920
extern uint32_t SystemCoreClock;
2021
extern void nxp_nbu_init(void);
@@ -221,6 +222,73 @@ static void vbat_init(void)
221222
base->STATUSA |= VBAT_STATUSA_POR_DET_MASK;
222223
};
223224

225+
#if CONFIG_PM
226+
/*
227+
* In active mode, all HVDs/LVDs are disabled.
228+
* DCDC regulated to 1.8V, Core LDO regulated to 1.1V;
229+
* In low power modes, all HVDs/LVDs are disabled.
230+
* Bandgap is disabled, DCDC regulated to 1.25V, Core LDO regulated to 1.05V.
231+
*/
232+
233+
__weak void set_spc_configuration(void)
234+
{
235+
/* Disable LVDs and HVDs in Active mode. */
236+
SPC_EnableActiveModeCoreHighVoltageDetect(SPC0, false);
237+
SPC_EnableActiveModeCoreLowVoltageDetect(SPC0, false);
238+
SPC_EnableActiveModeSystemHighVoltageDetect(SPC0, false);
239+
SPC_EnableActiveModeSystemLowVoltageDetect(SPC0, false);
240+
SPC_EnableActiveModeIOHighVoltageDetect(SPC0, false);
241+
SPC_EnableActiveModeIOLowVoltageDetect(SPC0, false);
242+
243+
while (SPC_GetBusyStatusFlag(SPC0)) {
244+
}
245+
246+
spc_active_mode_regulators_config_t active_mode_regulator;
247+
active_mode_regulator.bandgapMode = kSPC_BandgapEnabledBufferDisabled;
248+
active_mode_regulator.lpBuff = false;
249+
/* DCDC regulate to 1.8V. */
250+
active_mode_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_SafeModeVoltage;
251+
active_mode_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength;
252+
active_mode_regulator.SysLDOOption.SysLDOVoltage = kSPC_SysLDO_NormalVoltage;
253+
active_mode_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_NormalDriveStrength;
254+
/* Core LDO regulate to 1.1V. */
255+
active_mode_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
256+
#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS
257+
active_mode_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength;
258+
#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */
259+
260+
SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &active_mode_regulator.DCDCOption);
261+
262+
while (SPC_GetBusyStatusFlag(SPC0)) {
263+
}
264+
265+
SPC_SetActiveModeSystemLDORegulatorConfig(SPC0, &active_mode_regulator.SysLDOOption);
266+
267+
SPC_SetActiveModeBandgapModeConfig(SPC0, active_mode_regulator.bandgapMode);
268+
269+
SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &active_mode_regulator.CoreLDOOption);
270+
271+
SPC_EnableActiveModeCMPBandgapBuffer(SPC0, active_mode_regulator.lpBuff);
272+
273+
spc_lowpower_mode_regulators_config_t low_power_regulator;
274+
low_power_regulator.lpIREF = false;
275+
low_power_regulator.bandgapMode = kSPC_BandgapDisabled;
276+
low_power_regulator.lpBuff = false;
277+
low_power_regulator.CoreIVS = false;
278+
low_power_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_LowUnderVoltage;
279+
low_power_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_LowDriveStrength;
280+
low_power_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_LowDriveStrength;
281+
low_power_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage;
282+
low_power_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_LowDriveStrength;
283+
284+
SPC_SetLowPowerModeRegulatorsConfig(SPC0, &low_power_regulator);
285+
286+
SPC_SetLowPowerWakeUpDelay(SPC0, 0xFFFFU);
287+
}
288+
#endif
289+
290+
extern void nxp_mcxw7x_power_init(void);
291+
224292
void soc_early_init_hook(void)
225293
{
226294
unsigned int oldLevel; /* old interrupt lock level */
@@ -234,6 +302,11 @@ void soc_early_init_hook(void)
234302
/* Smart power switch initialization */
235303
vbat_init();
236304

305+
#if CONFIG_PM
306+
nxp_mcxw7x_power_init();
307+
set_spc_configuration();
308+
#endif
309+
237310
/* restore interrupt state */
238311
irq_unlock(oldLevel);
239312

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

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

99
#include <fsl_port.h>
1010
#include <soc_common.h>
11+
#include <fsl_wuu.h>
1112

1213
#define PORT_MUX_GPIO kPORT_MuxAsGpio
1314

1415
#define nbu_handler RF_IMU0_IRQHandler
1516

17+
#undef NXP_ENABLE_WAKEUP_SIGNAL
18+
#define NXP_ENABLE_WAKEUP_SIGNAL(sig) WUU_SetInternalWakeUpModulesConfig(WUU0, sig, kWUU_InternalModuleInterrupt);
19+
1620
#endif /* _SOC__H_ */

0 commit comments

Comments
 (0)