diff --git a/dts/arm/nxp/nxp_mcxw7x_common.dtsi b/dts/arm/nxp/nxp_mcxw7x_common.dtsi index ff52ac2c2da2c..f8650c65df6a8 100644 --- a/dts/arm/nxp/nxp_mcxw7x_common.dtsi +++ b/dts/arm/nxp/nxp_mcxw7x_common.dtsi @@ -32,6 +32,7 @@ cpu0: cpu@0 { compatible = "arm,cortex-m33f"; reg = <0>; + cpu-power-states = <&sleep &sleep_optimized &deep_sleep>; #address-cells = <1>; #size-cells = <1>; @@ -40,6 +41,28 @@ reg = <0xe000ed90 0x40>; }; }; + + power-states { + sleep: sleep { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <100>; + exit-latency-us = <0>; + }; + sleep_optimized: sleep-optimized { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + substate-id = <0>; + min-residency-us = <500>; + exit-latency-us = <10>; + }; + deep_sleep: deep-sleep { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <1000>; + exit-latency-us = <11>; + }; + }; }; soc { @@ -114,6 +137,24 @@ #address-cells = <1>; #size-cells = <1>; + cmc: system-modules@1000 { + compatible = "nxp,cmc"; + reg = <0x1000 0x1000>; + interrupts = <1 0>; + }; + + spc: system-modules@16000 { + compatible = "nxp,spc"; + reg = <0x16000 0x1000>; + interrupts = <21 0>; + }; + + wuu: system-modules@19000 { + compatible = "nxp,wuu"; + reg = <0x19000 0x1000>; + interrupts = <22 0>; + }; + scg: clock-controller@1e000 { compatible = "nxp,scg-k4"; reg = <0x1e000 0x404>; @@ -248,6 +289,7 @@ }; vbat: vbat@2b000 { + compatible = "nxp,vbat"; reg = <0x2b000 0x33c>; interrupts = <74 0>; }; diff --git a/dts/bindings/power/nxp,cmc.yaml b/dts/bindings/power/nxp,cmc.yaml new file mode 100644 index 0000000000000..cf744b59e36e8 --- /dev/null +++ b/dts/bindings/power/nxp,cmc.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Core Mode Controller (CMC) + +compatible: "nxp,cmc" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/power/nxp,spc.yaml b/dts/bindings/power/nxp,spc.yaml new file mode 100644 index 0000000000000..466ca6085ab27 --- /dev/null +++ b/dts/bindings/power/nxp,spc.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP System Power Control (SPC) + +compatible: "nxp,spc" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/power/nxp,vbat.yaml b/dts/bindings/power/nxp,vbat.yaml new file mode 100644 index 0000000000000..11c06457c79e5 --- /dev/null +++ b/dts/bindings/power/nxp,vbat.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Smart Power Switch (VBAT) + +compatible: "nxp,vbat" + +include: base.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/power/nxp,wuu.yaml b/dts/bindings/power/nxp,wuu.yaml new file mode 100644 index 0000000000000..8f752b6b38e2a --- /dev/null +++ b/dts/bindings/power/nxp,wuu.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Wakeup Unit (WUU) + +compatible: "nxp,wuu" + +include: base.yaml + +properties: + reg: + required: true diff --git a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake index 455c9823b8ad6..41005dc92ef0a 100644 --- a/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake +++ b/modules/hal_nxp/mcux/mcux-sdk-ng/drivers/drivers.cmake @@ -108,6 +108,10 @@ set_variable_ifdef(CONFIG_UART_MCUX_IUART CONFIG_MCUX_COMPONENT_driver.iua set_variable_ifdef(CONFIG_ADC_MCUX_12B1MSPS_SAR CONFIG_MCUX_COMPONENT_driver.adc_12b1msps_sar) set_variable_ifdef(CONFIG_HWINFO_MCUX_MCX_CMC CONFIG_MCUX_COMPONENT_driver.mcx_cmc) set_variable_ifdef(CONFIG_HWINFO_MCUX_SRC CONFIG_MCUX_COMPONENT_driver.src) +set_variable_ifdef(CONFIG_DT_HAS_NXP_SPC_ENABLED CONFIG_MCUX_COMPONENT_driver.spc) +set_variable_ifdef(CONFIG_DT_HAS_NXP_CMC_ENABLED CONFIG_MCUX_COMPONENT_driver.cmc) +set_variable_ifdef(CONFIG_DT_HAS_NXP_VBAT_ENABLED CONFIG_MCUX_COMPONENT_driver.vbat) +set_variable_ifdef(CONFIG_DT_HAS_NXP_WUU_ENABLED CONFIG_MCUX_COMPONENT_driver.wuu) set_variable_ifdef(CONFIG_HWINFO_MCUX_SIM CONFIG_MCUX_COMPONENT_driver.sim) set_variable_ifdef(CONFIG_HWINFO_MCUX_RCM CONFIG_MCUX_COMPONENT_driver.rcm) set_variable_ifdef(CONFIG_IPM_MCUX CONFIG_MCUX_COMPONENT_driver.mailbox) @@ -185,10 +189,6 @@ if(CONFIG_SOC_FAMILY_MCXN OR CONFIG_SOC_FAMILY_MCXA) set(CONFIG_MCUX_COMPONENT_driver.mcx_spc ON) endif() -if(CONFIG_BT_NXP AND CONFIG_SOC_FAMILY_MCXW OR CONFIG_IEEE802154_MCXW) - set(CONFIG_MCUX_COMPONENT_driver.spc ON) -endif() - if(((${MCUX_DEVICE} MATCHES "MIMXRT1[0-9][0-9][0-9]") AND (NOT (CONFIG_SOC_MIMXRT1166_CM4 OR CONFIG_SOC_MIMXRT1176_CM4 OR CONFIG_SOC_MIMXRT1189_CM33))) OR ((${MCUX_DEVICE} MATCHES "MIMX9596") AND CONFIG_SOC_MIMX9596_M7)) set_variable_ifdef(CONFIG_HAS_MCUX_CACHE CONFIG_MCUX_COMPONENT_driver.cache_armv7_m7) diff --git a/soc/nxp/mcx/mcxw/Kconfig b/soc/nxp/mcx/mcxw/Kconfig index 7213ae60bbb9c..c636539f4ec5f 100644 --- a/soc/nxp/mcx/mcxw/Kconfig +++ b/soc/nxp/mcx/mcxw/Kconfig @@ -18,3 +18,4 @@ config SOC_FAMILY_MCXW select SOC_EARLY_INIT_HOOK select CLOCK_CONTROL select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM diff --git a/soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt b/soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt index 207cdf6e38893..e2971b55304b1 100644 --- a/soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt +++ b/soc/nxp/mcx/mcxw/mcxw7xx/CMakeLists.txt @@ -10,6 +10,8 @@ zephyr_sources_ifdef(CONFIG_NXP_NBU ../../../common/nxp_nbu.c ) +zephyr_sources_ifdef(CONFIG_PM power.c) + zephyr_include_directories(./) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig b/soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig index 83c4905b5494d..bb9ac4125d888 100644 --- a/soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig +++ b/soc/nxp/mcx/mcxw/mcxw7xx/Kconfig.defconfig @@ -8,8 +8,13 @@ config NUM_IRQS default 77 if SOC_MCXW727C default 75 +config MCUX_LPTMR_TIMER + default y if PM + +DT_LPTMR_PATH := $(dt_nodelabel_path,lptmr0) config SYS_CLOCK_HW_CYCLES_PER_SEC default 96000000 if CORTEX_M_SYSTICK + default $(dt_node_int_prop_int,$(DT_LPTMR_PATH),clock-frequency) if MCUX_LPTMR_TIMER config MCUX_FLASH_K4_API default y diff --git a/soc/nxp/mcx/mcxw/mcxw7xx/power.c b/soc/nxp/mcx/mcxw/mcxw7xx/power.c new file mode 100644 index 0000000000000..95864eb2d0dc2 --- /dev/null +++ b/soc/nxp/mcx/mcxw/mcxw7xx/power.c @@ -0,0 +1,202 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "fsl_cmc.h" +#include "fsl_spc.h" +#include "fsl_vbat.h" + +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +#define WUU_WAKEUP_LPTMR_IDX 0 + +/* + * 1. Set power mode protection + * 2. Disable low power mode debug + * 3. Enable Flash Doze mode. + */ +static void set_cmc_configuration(void) +{ + CMC_SetPowerModeProtection(CMC0, kCMC_AllowAllLowPowerModes); + CMC_LockPowerModeProtectionSetting(CMC0); + CMC_EnableDebugOperation(CMC0, IS_ENABLED(CONFIG_DEBUG)); + CMC_ConfigFlashMode(CMC0, false, false, false); +} + +/* + * Disable Backup SRAM regulator, FRO16K and Bandgap which + * locates in VBAT power domain for most of power modes. + * + */ +static void deinit_vbat(void) +{ + VBAT_EnableBackupSRAMRegulator(VBAT0, false); + VBAT_EnableFRO16k(VBAT0, false); + while (VBAT_CheckFRO16kEnabled(VBAT0)) { + }; + VBAT_EnableBandgap(VBAT0, false); + while (VBAT_CheckBandgapEnabled(VBAT0)) { + }; +} + +/* Invoke Low Power/System Off specific Tasks */ +__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + /* Set PRIMASK */ + __disable_irq(); + /* Set BASEPRI to 0 */ + irq_unlock(0); + + if (state == PM_STATE_RUNTIME_IDLE) { + k_cpu_idle(); + return; + } + + set_cmc_configuration(); + deinit_vbat(); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + cmc_power_domain_config_t config; + + if (substate_id == 0) { + /* Set NBU into Sleep Mode */ + RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & + (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) | + RFMC_RF2P4GHZ_CTRL_LP_MODE(0x1); + RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK; + + /* Set MAIN_CORE and MAIN_WAKE power domain into sleep mode. */ + config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode; + config.main_domain = kCMC_SleepMode; + config.wake_domain = kCMC_SleepMode; + CMC_EnterLowPowerMode(CMC0, &config); + } else if (substate_id == 1) { + } else { + /* Nothing to do */ + } + break; + case PM_STATE_STANDBY: + /* Enable CORE VDD Voltage scaling. */ + SPC_EnableLowPowerModeCoreVDDInternalVoltageScaling(SPC0, true); + + /* Set NBU into Deep Sleep Mode */ + RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)) | + RFMC_RF2P4GHZ_CTRL_LP_MODE(0x3); + RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK; + + /* Set MAIN_CORE and MAIN_WAKE power domain into Deep Sleep Mode. */ + config.clock_mode = kCMC_GateAllSystemClocksEnterLowPowerMode; + config.main_domain = kCMC_DeepSleepMode; + config.wake_domain = kCMC_DeepSleepMode; + + CMC_EnterLowPowerMode(CMC0, &config); + + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + /* Clear PRIMASK */ + __enable_irq(); + + if (state == PM_STATE_RUNTIME_IDLE) { + return; + } + + if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain0)) { + SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain0); + } + if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain1)) { + SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain1); + } + if (SPC_CheckPowerDomainLowPowerRequest(SPC0, kSPC_PowerDomain2)) { + RFMC->RF2P4GHZ_CTRL = (RFMC->RF2P4GHZ_CTRL & (~RFMC_RF2P4GHZ_CTRL_LP_MODE_MASK)); + RFMC->RF2P4GHZ_CTRL &= ~RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK; + SPC_ClearPowerDomainLowPowerRequestFlag(SPC0, kSPC_PowerDomain2); + } + SPC_ClearLowPowerRequest(SPC0); +} + +/* + * In active mode, all HVDs/LVDs are disabled. + * DCDC regulated to 1.8V, Core LDO regulated to 1.1V; + * In low power modes, all HVDs/LVDs are disabled. + * Bandgap is disabled, DCDC regulated to 1.25V, Core LDO regulated to 1.05V. + */ +__weak void set_spc_configuration(void) +{ + /* Disable LVDs and HVDs in Active mode. */ + SPC_EnableActiveModeCoreHighVoltageDetect(SPC0, false); + SPC_EnableActiveModeCoreLowVoltageDetect(SPC0, false); + SPC_EnableActiveModeSystemHighVoltageDetect(SPC0, false); + SPC_EnableActiveModeSystemLowVoltageDetect(SPC0, false); + SPC_EnableActiveModeIOHighVoltageDetect(SPC0, false); + SPC_EnableActiveModeIOLowVoltageDetect(SPC0, false); + while (SPC_GetBusyStatusFlag(SPC0)) { + } + + spc_active_mode_regulators_config_t active_mode_regulator; + + active_mode_regulator.bandgapMode = kSPC_BandgapEnabledBufferDisabled; + active_mode_regulator.lpBuff = false; + /* DCDC regulate to 1.8V. */ + active_mode_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_SafeModeVoltage; + active_mode_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_NormalDriveStrength; + active_mode_regulator.SysLDOOption.SysLDOVoltage = kSPC_SysLDO_NormalVoltage; + active_mode_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_NormalDriveStrength; + /* Core LDO regulate to 1.1V. */ + active_mode_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage; +#if defined(FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS) && FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS + active_mode_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_NormalDriveStrength; +#endif /* FSL_FEATURE_SPC_HAS_CORELDO_VDD_DS */ + + SPC_SetActiveModeDCDCRegulatorConfig(SPC0, &active_mode_regulator.DCDCOption); + + while (SPC_GetBusyStatusFlag(SPC0)) { + } + + SPC_SetActiveModeSystemLDORegulatorConfig(SPC0, &active_mode_regulator.SysLDOOption); + + SPC_SetActiveModeBandgapModeConfig(SPC0, active_mode_regulator.bandgapMode); + + SPC_SetActiveModeCoreLDORegulatorConfig(SPC0, &active_mode_regulator.CoreLDOOption); + + SPC_EnableActiveModeCMPBandgapBuffer(SPC0, active_mode_regulator.lpBuff); + + spc_lowpower_mode_regulators_config_t low_power_regulator; + + low_power_regulator.lpIREF = false; + low_power_regulator.bandgapMode = kSPC_BandgapDisabled; + low_power_regulator.lpBuff = false; + low_power_regulator.CoreIVS = false; + low_power_regulator.DCDCOption.DCDCVoltage = kSPC_DCDC_LowUnderVoltage; + low_power_regulator.DCDCOption.DCDCDriveStrength = kSPC_DCDC_LowDriveStrength; + low_power_regulator.SysLDOOption.SysLDODriveStrength = kSPC_SysLDO_LowDriveStrength; + low_power_regulator.CoreLDOOption.CoreLDOVoltage = kSPC_CoreLDO_MidDriveVoltage; + low_power_regulator.CoreLDOOption.CoreLDODriveStrength = kSPC_CoreLDO_LowDriveStrength; + + SPC_SetLowPowerModeRegulatorsConfig(SPC0, &low_power_regulator); + + SPC_SetLowPowerWakeUpDelay(SPC0, 0xFFFFU); +} + +void nxp_mcxw7x_power_init(void) +{ + set_spc_configuration(); + /* Enable LPTMR0 as wakeup source */ + NXP_ENABLE_WAKEUP_SIGNAL(WUU_WAKEUP_LPTMR_IDX); +} diff --git a/soc/nxp/mcx/mcxw/mcxw7xx/soc.c b/soc/nxp/mcx/mcxw/mcxw7xx/soc.c index d9fba8016c205..1673396ad357c 100644 --- a/soc/nxp/mcx/mcxw/mcxw7xx/soc.c +++ b/soc/nxp/mcx/mcxw/mcxw7xx/soc.c @@ -15,10 +15,16 @@ #include #include #include +#include extern uint32_t SystemCoreClock; extern void nxp_nbu_init(void); +void mcxw7xx_set_wakeup(int32_t sig) +{ + WUU_SetInternalWakeUpModulesConfig(WUU0, sig, kWUU_InternalModuleInterrupt); +} + __weak void clock_init(void) { /* Unlock Reference Clock Status Registers to allow writes */ @@ -234,6 +240,10 @@ void soc_early_init_hook(void) /* Smart power switch initialization */ vbat_init(); +#if CONFIG_PM + nxp_mcxw7x_power_init(); +#endif + /* restore interrupt state */ irq_unlock(oldLevel); diff --git a/soc/nxp/mcx/mcxw/mcxw7xx/soc.h b/soc/nxp/mcx/mcxw/mcxw7xx/soc.h index b2aa5c92ca93b..d31b9e4cd8021 100644 --- a/soc/nxp/mcx/mcxw/mcxw7xx/soc.h +++ b/soc/nxp/mcx/mcxw/mcxw7xx/soc.h @@ -13,4 +13,12 @@ #define nbu_handler RF_IMU0_IRQHandler +#undef NXP_ENABLE_WAKEUP_SIGNAL +extern void mcxw7xx_set_wakeup(int32_t sig); +#define NXP_ENABLE_WAKEUP_SIGNAL(sig) mcxw7xx_set_wakeup(sig) + +#if CONFIG_PM +extern void nxp_mcxw7x_power_init(void); +#endif + #endif /* _SOC__H_ */