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 <mahesh.mahadevan@nxp.com>
This commit is contained in:
parent
15d8fd2ad3
commit
1e492e8f91
2 changed files with 134 additions and 2 deletions
|
@ -63,6 +63,33 @@ if PM
|
||||||
config SYS_CLOCK_TICKS_PER_SEC
|
config SYS_CLOCK_TICKS_PER_SEC
|
||||||
default 1000
|
default 1000
|
||||||
depends on $(dt_nodelabel_enabled,standby)
|
depends on $(dt_nodelabel_enabled,standby)
|
||||||
endif
|
|
||||||
|
# Enable PM_DEVICE by default if STANDBY mode is enabled
|
||||||
|
# as we use the TURN_OFF and TURN_ON actions to recover
|
||||||
|
# from Standby mode (PM Mode 3)
|
||||||
|
config PM_DEVICE
|
||||||
|
default y
|
||||||
|
depends on "$(dt_nodelabel_enabled,standby)"
|
||||||
|
|
||||||
|
# Enable PM_POLICY_DEVICE_CONSTRAINTS by default when doing PM_DEVICE.
|
||||||
|
# This will allow support of device power states.
|
||||||
|
config PM_POLICY_DEVICE_CONSTRAINTS
|
||||||
|
default y if PM_DEVICE
|
||||||
|
|
||||||
|
# Enable the counter if STANDBY mode is enabled
|
||||||
|
# RTC counter is the wakeup source from STANDBY mode
|
||||||
|
config COUNTER
|
||||||
|
default y
|
||||||
|
depends on "$(dt_nodelabel_enabled,standby)"
|
||||||
|
|
||||||
|
config MCUX_OS_TIMER_PM_POWERED_OFF
|
||||||
|
default y
|
||||||
|
|
||||||
|
# PM code that runs from the idle loop has a large
|
||||||
|
# footprint. Hence increase the size when PM is enabled.
|
||||||
|
config IDLE_STACK_SIZE
|
||||||
|
default 640
|
||||||
|
|
||||||
|
endif # PM
|
||||||
|
|
||||||
endif # SOC_SERIES_RW6XX
|
endif # SOC_SERIES_RW6XX
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2023, NXP
|
* Copyright 2023-2025 NXP
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
#include "fsl_power.h"
|
#include "fsl_power.h"
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/drivers/timer/system_timer.h>
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
||||||
|
|
||||||
/* Active mode */
|
/* Active mode */
|
||||||
|
@ -26,6 +28,8 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
||||||
|
|
||||||
#define NODE_ID DT_INST(0, nxp_pdcfg_power)
|
#define NODE_ID DT_INST(0, nxp_pdcfg_power)
|
||||||
|
|
||||||
|
extern void clock_init(void);
|
||||||
|
|
||||||
power_sleep_config_t slp_cfg;
|
power_sleep_config_t slp_cfg;
|
||||||
|
|
||||||
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin0)) || DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(pin1))
|
#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)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
|
||||||
|
#define MPU_NUM_REGIONS 8
|
||||||
|
|
||||||
|
typedef struct mpu_conf {
|
||||||
|
uint32_t CTRL;
|
||||||
|
uint32_t RNR;
|
||||||
|
uint32_t RBAR[MPU_NUM_REGIONS];
|
||||||
|
uint32_t RLAR[MPU_NUM_REGIONS];
|
||||||
|
uint32_t RBAR_A1;
|
||||||
|
uint32_t RLAR_A1;
|
||||||
|
uint32_t RBAR_A2;
|
||||||
|
uint32_t RLAR_A2;
|
||||||
|
uint32_t RBAR_A3;
|
||||||
|
uint32_t RLAR_A3;
|
||||||
|
uint32_t MAIR0;
|
||||||
|
uint32_t MAIR1;
|
||||||
|
} mpu_conf;
|
||||||
|
mpu_conf saved_mpu_conf;
|
||||||
|
|
||||||
|
static void save_mpu_state(void)
|
||||||
|
{
|
||||||
|
uint32_t index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MPU is divided in `MPU_NUM_REGIONS` regions.
|
||||||
|
* Here we save those regions configuration to be restored after PM3 entry
|
||||||
|
*/
|
||||||
|
for (index = 0U; index < MPU_NUM_REGIONS; index++) {
|
||||||
|
MPU->RNR = index;
|
||||||
|
saved_mpu_conf.RBAR[index] = MPU->RBAR;
|
||||||
|
saved_mpu_conf.RLAR[index] = MPU->RLAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
saved_mpu_conf.CTRL = MPU->CTRL;
|
||||||
|
saved_mpu_conf.RNR = MPU->RNR;
|
||||||
|
saved_mpu_conf.RBAR_A1 = MPU->RBAR_A1;
|
||||||
|
saved_mpu_conf.RLAR_A1 = MPU->RLAR_A1;
|
||||||
|
saved_mpu_conf.RBAR_A2 = MPU->RBAR_A2;
|
||||||
|
saved_mpu_conf.RLAR_A2 = MPU->RLAR_A2;
|
||||||
|
saved_mpu_conf.RBAR_A3 = MPU->RBAR_A3;
|
||||||
|
saved_mpu_conf.RLAR_A3 = MPU->RLAR_A3;
|
||||||
|
saved_mpu_conf.MAIR0 = MPU->MAIR0;
|
||||||
|
saved_mpu_conf.MAIR1 = MPU->MAIR1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_mpu_state(void)
|
||||||
|
{
|
||||||
|
uint32_t index;
|
||||||
|
|
||||||
|
for (index = 0U; index < MPU_NUM_REGIONS; index++) {
|
||||||
|
MPU->RNR = index;
|
||||||
|
MPU->RBAR = saved_mpu_conf.RBAR[index];
|
||||||
|
MPU->RLAR = saved_mpu_conf.RLAR[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
MPU->RNR = saved_mpu_conf.RNR;
|
||||||
|
MPU->RBAR_A1 = saved_mpu_conf.RBAR_A1;
|
||||||
|
MPU->RLAR_A1 = saved_mpu_conf.RLAR_A1;
|
||||||
|
MPU->RBAR_A2 = saved_mpu_conf.RBAR_A2;
|
||||||
|
MPU->RLAR_A2 = saved_mpu_conf.RLAR_A2;
|
||||||
|
MPU->RBAR_A3 = saved_mpu_conf.RBAR_A3;
|
||||||
|
MPU->RLAR_A3 = saved_mpu_conf.RLAR_A3;
|
||||||
|
MPU->MAIR0 = saved_mpu_conf.MAIR0;
|
||||||
|
MPU->MAIR1 = saved_mpu_conf.MAIR1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CTRL register must be restored last in case MPU was enabled,
|
||||||
|
* because some MPU registers can't be programmed while the MPU is enabled
|
||||||
|
*/
|
||||||
|
MPU->CTRL = saved_mpu_conf.CTRL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_MPU */
|
||||||
|
|
||||||
/* Invoke Low Power/System Off specific Tasks */
|
/* Invoke Low Power/System Off specific Tasks */
|
||||||
__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
__weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
||||||
{
|
{
|
||||||
|
@ -92,6 +171,28 @@ __weak void pm_state_set(enum pm_state state, uint8_t substate_id)
|
||||||
break;
|
break;
|
||||||
case PM_STATE_SUSPEND_TO_IDLE:
|
case PM_STATE_SUSPEND_TO_IDLE:
|
||||||
POWER_EnterPowerMode(POWER_MODE2, &slp_cfg);
|
POWER_EnterPowerMode(POWER_MODE2, &slp_cfg);
|
||||||
|
break;
|
||||||
|
case PM_STATE_STANDBY:
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
/* Save MPU state before entering PM3 */
|
||||||
|
save_mpu_state();
|
||||||
|
#endif /* CONFIG_MPU */
|
||||||
|
|
||||||
|
POWER_EnableWakeup(DT_IRQN(DT_NODELABEL(rtc)));
|
||||||
|
if (POWER_EnterPowerMode(POWER_MODE3, &slp_cfg)) {
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
/* Restore MPU as is lost after PM3 exit*/
|
||||||
|
restore_mpu_state();
|
||||||
|
#endif /* CONFIG_MPU */
|
||||||
|
clock_init();
|
||||||
|
|
||||||
|
sys_clock_idle_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the RTC wakeup bits */
|
||||||
|
POWER_ClearWakeupStatus(DT_IRQN(DT_NODELABEL(rtc)));
|
||||||
|
POWER_DisableWakeup(DT_IRQN(DT_NODELABEL(rtc)));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_DBG("Unsupported power state %u", state);
|
LOG_DBG("Unsupported power state %u", state);
|
||||||
|
@ -142,4 +243,8 @@ void nxp_rw6xx_power_init(void)
|
||||||
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(pin1)), DT_IRQ(DT_NODELABEL(pin1), priority), pin1_isr,
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(pin1)), DT_IRQ(DT_NODELABEL(pin1), priority), pin1_isr,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Clear the RTC wakeup bits */
|
||||||
|
POWER_ClearWakeupStatus(DT_IRQN(DT_NODELABEL(rtc)));
|
||||||
|
POWER_DisableWakeup(DT_IRQN(DT_NODELABEL(rtc)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue