From 19bb8e2ec84a3bc90a5ba644b5abe5f5a6313f01 Mon Sep 17 00:00:00 2001 From: Daniel DeGrasse Date: Tue, 7 Dec 2021 18:23:04 -0600 Subject: [PATCH] soc: rt11xx: Enable power management for RT11xx series SOCs Enables basic power management for the RT11xx series SOCs. The following power saving measures are currently implemented: - system reduces core voltage during sleep - core clock can be gated in deep sleep Signed-off-by: Daniel DeGrasse --- dts/arm/nxp/nxp_rt11xx.dtsi | 4 +- include/dt-bindings/pm/imx_spc.h | 118 +++++++++++ soc/arm/nxp_imx/rt/CMakeLists.txt | 4 + soc/arm/nxp_imx/rt/power_rt11xx.c | 331 ++++++++++++++++++++++++++++++ soc/arm/nxp_imx/rt/power_rt11xx.h | 179 ++++++++++++++++ 5 files changed, 634 insertions(+), 2 deletions(-) create mode 100644 include/dt-bindings/pm/imx_spc.h create mode 100644 soc/arm/nxp_imx/rt/power_rt11xx.c create mode 100644 soc/arm/nxp_imx/rt/power_rt11xx.h diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index edfc6d9967e..8b30b434b43 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -15,7 +15,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; @@ -29,7 +29,7 @@ arm,num-mpu-regions = <16>; }; }; - cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <1>; diff --git a/include/dt-bindings/pm/imx_spc.h b/include/dt-bindings/pm/imx_spc.h new file mode 100644 index 00000000000..5eb045435be --- /dev/null +++ b/include/dt-bindings/pm/imx_spc.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/* + * Setpoint definitions for IMX Set point controller. The SPC uses a series + * of set points to determine the clock speeds and states of cores, as well + * as which peripherals to gate clocks to. Higher values correspond to more + * power saving. See your SOC's datasheet for specifics of what peripherals + * have their clocks gated at each set point. + * + * Set point control is implemented at the soc level (see pm_power_state_set()) + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PM_IMX_SPC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PM_IMX_SPC_H_ + +#define IMX_GPC_RUN 0x0 +#define IMX_GPC_WAIT 0x1 +#define IMX_GPC_STOP 0x2 +#define IMX_GPC_SUSPEND 0x3 + + +#define IMX_SPC_MASK 0xF0 +#define IMX_SPC_SHIFT 4 +#define IMX_GPC_MODE_MASK 0xF + +#define IMX_SPC(x) ((x & IMX_SPC_MASK) >> IMX_SPC_SHIFT) +#define IMX_GPC_MODE(x) (x & IMX_GPC_MODE_MASK) + +#define IMX_SPC_0 0x00 +#define IMX_SPC_1 0x10 +#define IMX_SPC_2 0x20 +#define IMX_SPC_3 0x30 +#define IMX_SPC_4 0x40 +#define IMX_SPC_5 0x50 +#define IMX_SPC_6 0x60 +#define IMX_SPC_7 0x70 +#define IMX_SPC_8 0x80 +#define IMX_SPC_9 0x90 +#define IMX_SPC_10 0xA0 +#define IMX_SPC_11 0xB0 +#define IMX_SPC_12 0xC0 +#define IMX_SPC_13 0xD0 +#define IMX_SPC_14 0xE0 +#define IMX_SPC_15 0xF0 + + +#define IMX_SPC_SET_POINT_0_RUN (IMX_SPC_0 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_0_WAIT (IMX_SPC_0 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_0_STOP (IMX_SPC_0 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_0_SUSPEND (IMX_SPC_0 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_1_RUN (IMX_SPC_1 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_1_WAIT (IMX_SPC_1 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_1_STOP (IMX_SPC_1 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_1_SUSPEND (IMX_SPC_1 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_2_RUN (IMX_SPC_2 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_2_WAIT (IMX_SPC_2 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_2_STOP (IMX_SPC_2 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_2_SUSPEND (IMX_SPC_2 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_3_RUN (IMX_SPC_3 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_3_WAIT (IMX_SPC_3 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_3_STOP (IMX_SPC_3 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_3_SUSPEND (IMX_SPC_3 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_4_RUN (IMX_SPC_4 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_4_WAIT (IMX_SPC_4 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_4_STOP (IMX_SPC_4 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_4_SUSPEND (IMX_SPC_4 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_5_RUN (IMX_SPC_5 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_5_WAIT (IMX_SPC_5 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_5_STOP (IMX_SPC_5 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_5_SUSPEND (IMX_SPC_5 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_6_RUN (IMX_SPC_6 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_6_WAIT (IMX_SPC_6 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_6_STOP (IMX_SPC_6 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_6_SUSPEND (IMX_SPC_6 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_7_RUN (IMX_SPC_7 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_7_WAIT (IMX_SPC_7 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_7_STOP (IMX_SPC_7 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_7_SUSPEND (IMX_SPC_7 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_8_RUN (IMX_SPC_8 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_8_WAIT (IMX_SPC_8 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_8_STOP (IMX_SPC_8 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_8_SUSPEND (IMX_SPC_8 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_9_RUN (IMX_SPC_9 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_9_WAIT (IMX_SPC_9 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_9_STOP (IMX_SPC_9 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_9_SUSPEND (IMX_SPC_9 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_10_RUN (IMX_SPC_10 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_10_WAIT (IMX_SPC_10 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_10_STOP (IMX_SPC_10 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_10_SUSPEND (IMX_SPC_10 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_11_RUN (IMX_SPC_11 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_11_WAIT (IMX_SPC_11 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_11_STOP (IMX_SPC_11 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_11_SUSPEND (IMX_SPC_11 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_12_RUN (IMX_SPC_12 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_12_WAIT (IMX_SPC_12 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_12_STOP (IMX_SPC_12 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_12_SUSPEND (IMX_SPC_12 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_13_RUN (IMX_SPC_13 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_13_WAIT (IMX_SPC_13 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_13_STOP (IMX_SPC_13 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_13_SUSPEND (IMX_SPC_13 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_14_RUN (IMX_SPC_14 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_14_WAIT (IMX_SPC_14 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_14_STOP (IMX_SPC_14 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_14_SUSPEND (IMX_SPC_14 | IMX_GPC_SUSPEND) +#define IMX_SPC_SET_POINT_15_RUN (IMX_SPC_15 | IMX_GPC_RUN) +#define IMX_SPC_SET_POINT_15_WAIT (IMX_SPC_15 | IMX_GPC_WAIT) +#define IMX_SPC_SET_POINT_15_STOP (IMX_SPC_15 | IMX_GPC_STOP) +#define IMX_SPC_SET_POINT_15_SUSPEND (IMX_SPC_15 | IMX_GPC_SUSPEND) + + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PM_IMX_SPC_H_ */ diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index dd85c46f741..9849882e765 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -21,6 +21,10 @@ if(CONFIG_DEVICE_CONFIGURATION_DATA) set(boot_hdr_dcd_data_section ".boot_hdr.dcd_data") endif() +if(CONFIG_PM) +zephyr_sources_ifdef(CONFIG_SOC_SERIES_IMX_RT11XX power_rt11xx.c) +endif() + zephyr_linker_section_configure( SECTION .rom_start INPUT ".boot_hdr.ivt" diff --git a/soc/arm/nxp_imx/rt/power_rt11xx.c b/soc/arm/nxp_imx/rt/power_rt11xx.c new file mode 100644 index 00000000000..4aaffc218ca --- /dev/null +++ b/soc/arm/nxp_imx/rt/power_rt11xx.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2021, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include "power_rt11xx.h" + +#include +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +/* + * NOTE: When multicore support in RT1170/1160 is properly implemented, + * power saving will improve when both cores request a transition to a low + * power mode + */ + +#ifdef CONFIG_CPU_CORTEX_M7 +#define GPC_CPU_MODE_CTRL GPC_CPU_MODE_CTRL_0 +#elif CONFIG_CPU_CORTEX_M4 +#define GPC_CPU_MODE_CTRL GPC_CPU_MODE_CTRL_1 +#else +#error "RT11xx power code supports M4 and M7 cores only" +#endif + +/* Configure the set point mappings for Cortex M4 and M7 cores */ +static void gpc_set_core_mappings(void) +{ + uint8_t i, j; + uint32_t tmp; + +#ifdef CONFIG_CPU_CORTEX_M7 + uint8_t mapping[SET_POINT_COUNT][SET_POINT_COUNT] = CPU0_COMPATIBLE_SP_TABLE; +#elif CONFIG_CPU_CORTEX_M4 + uint8_t mapping[SET_POINT_COUNT][SET_POINT_COUNT] = CPU1_COMPATIBLE_SP_TABLE; +#else +#error "RT11xx power code supports M4 and M7 cores only" +#endif + /* Cortex Set point mappings */ + for (i = 0; i < SET_POINT_COUNT; i++) { + tmp = 0x0; + for (j = 0; j < SET_POINT_COUNT; j++) { + tmp |= mapping[i][j] << mapping[0][j]; + } + GPC_CM_SetSetPointMapping(GPC_CPU_MODE_CTRL, mapping[i][0], tmp); + } +} + +/* Configure GPC transition steps to enabled */ +static void gpc_set_transition_flow(void) +{ + gpc_tran_step_config_t step_cfg; + + step_cfg.enableStep = true; + step_cfg.cntMode = kGPC_StepCounterDisableMode; + + /* Cortex M7 */ + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepSsar, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepLpcg, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepPll, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepIso, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepReset, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_SleepPower, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupPower, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupReset, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupIso, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupPll, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupLpcg, &step_cfg); + GPC_CM_ConfigCpuModeTransitionStep(GPC_CPU_MODE_CTRL, + kGPC_CM_WakeupSsar, &step_cfg); + + /* Enable all steps in flow of set point transition */ + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_SsarSave, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_LpcgOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_GroupDown, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_RootDown, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_PllOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_IsoOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_ResetEarly, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_PowerOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_BiasOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_BandgapPllLdoOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_LdoPre, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_DcdcDown, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_DcdcUp, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_LdoPost, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_BandgapPllLdoOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_BiasOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_PowerOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_ResetLate, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_IsoOff, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_PllOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_RootUp, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_GroupUp, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_LpcgOn, &step_cfg); + GPC_SP_ConfigSetPointTransitionStep(GPC_SET_POINT_CTRL, + kGPC_SP_SsarRestore, &step_cfg); + + /* Enable all steps in standby transition */ + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_LpcgIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PllIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_BiasIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PldoIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_BandgapIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_LdoIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_DcdcIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PmicIn, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PmicOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_DcdcOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_LdoOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_BandgapOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PldoOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_BiasOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_PllOut, &step_cfg); + GPC_STBY_ConfigStandbyTransitionStep(GPC_STBY_CTRL, + kGPC_STBY_LpcgOut, &step_cfg); +} + +static void gpc_configure_interrupts(void) +{ + uint8_t i; + uint32_t irq = DT_IRQN(DT_INST(0, nxp_gpt_hw_timer)); + + /* Disable all GPC interrupt sources */ + for (i = 0; i < GPC_CPU_MODE_CTRL_CM_IRQ_WAKEUP_MASK_COUNT; i++) { + GPC_CPU_MODE_CTRL->CM_IRQ_WAKEUP_MASK[i] |= 0xFFFFFFFF; + } + + /* Enable GPT interrupt source for GPC- this is system timer */ + GPC_CM_EnableIrqWakeup(GPC_CPU_MODE_CTRL, irq, true); +} + +/* Initializes configuration for the GPC */ +static void gpc_init(void) +{ + /* Setup GPC set point mappings */ + gpc_set_core_mappings(); + /* Setup GPC set point transition flow */ + gpc_set_transition_flow(); + /* Allow GPC to disable ROSC */ + GPC_SET_POINT_CTRL->SP_ROSC_CTRL = ~OSC_RC_16M_STBY_VAL; + /* Setup GPC interrupts */ + gpc_configure_interrupts(); +} + +/* Initializes DCDC converter with power saving settings */ +static void dcdc_init(void) +{ + dcdc_config_t dcdc_config; + dcdc_setpoint_config_t dcdc_setpoint_config; + + dcdc_buck_mode_1P8_target_vol_t buck1_8_voltage[16] = + DCDC_1P8_BUCK_MODE_CONFIGURATION_TABLE; + dcdc_buck_mode_1P0_target_vol_t buck1_0_voltage[16] = + DCDC_1P0_BUCK_MODE_CONFIGURATION_TABLE; + dcdc_standby_mode_1P8_target_vol_t standby1_8_voltage[16] = + DCDC_1P8_STANDBY_MODE_CONFIGURATION_TABLE; + dcdc_standby_mode_1P0_target_vol_t standby1_0_voltage[16] = + DCDC_1P0_STANDBY_MODE_CONFIGURATION_TABLE; + + + DCDC_BootIntoDCM(DCDC); + + dcdc_setpoint_config.enableDCDCMap = DCDC_ONOFF_SP_VAL; + dcdc_setpoint_config.enableDigLogicMap = DCDC_DIG_ONOFF_SP_VAL; + dcdc_setpoint_config.lowpowerMap = DCDC_LP_MODE_SP_VAL; + dcdc_setpoint_config.standbyMap = DCDC_ONOFF_STBY_VAL; + dcdc_setpoint_config.standbyLowpowerMap = DCDC_LP_MODE_STBY_VAL; + dcdc_setpoint_config.buckVDD1P8TargetVoltage = buck1_8_voltage; + dcdc_setpoint_config.buckVDD1P0TargetVoltage = buck1_0_voltage; + dcdc_setpoint_config.standbyVDD1P8TargetVoltage = standby1_8_voltage; + dcdc_setpoint_config.standbyVDD1P0TargetVoltage = standby1_0_voltage; + DCDC_SetPointInit(DCDC, &dcdc_setpoint_config); + + DCDC_GetDefaultConfig(&dcdc_config); + dcdc_config.controlMode = kDCDC_SetPointControl; + DCDC_Init(DCDC, &dcdc_config); +} + +static void system_enter_sleep(gpc_cpu_mode_t gpc_mode) +{ + __ASSERT_NO_MSG(gpc_mode != kGPC_RunMode); + + if (gpc_mode == kGPC_WaitMode) { + /* Clear SLEEPDEEP bit to enter WAIT mode*/ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + } else { + /* Set SLEEPDEEP bit to enter STOP mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + } + /* When this function is entered the Kernel has disabled + * interrupts using BASEPRI register. We will clear BASEPRI, and use PRIMASK + * to disable interrupts, so that the WFI instruction works correctly. + */ + + /* Set PRIMASK */ + __disable_irq(); + /* Set BASEPRI to 0 */ + irq_unlock(0); + + /* WFI instruction will start entry into WAIT/STOP mode */ + LOG_DBG("Entering LPM via WFI"); + __WFI(); +} + +void cpu_mode_transition(gpc_cpu_mode_t mode, bool enable_standby) +{ + GPC_CM_SetNextCpuMode(GPC_CPU_MODE_CTRL, mode); + GPC_CM_EnableCpuSleepHold(GPC_CPU_MODE_CTRL, true); + + /* Mask debugger wakeup */ + GPC_CPU_MODE_CTRL->CM_NON_IRQ_WAKEUP_MASK |= + GPC_CPU_MODE_CTRL_CM_NON_IRQ_WAKEUP_MASK_EVENT_WAKEUP_MASK_MASK | + GPC_CPU_MODE_CTRL_CM_NON_IRQ_WAKEUP_MASK_DEBUG_WAKEUP_MASK_MASK; + + if (enable_standby) { + /* Set standby request */ + GPC_CM_RequestStandbyMode(GPC_CPU_MODE_CTRL, mode); + } else { + /* Clear standby request */ + GPC_CM_ClearStandbyModeRequest(GPC_CPU_MODE_CTRL, mode); + } + + /* Execute WFI- GPC will receive sleep request from CPU */ + system_enter_sleep(mode); +} + +/** + * SOC specific low power mode implementation + * Drop to lowest power state possible given system's request + */ +__weak void pm_power_state_set(struct pm_state_info info) +{ + /* Extract set point and GPC mode from the substate ID */ + uint8_t set_point = IMX_SPC(info.substate_id); + gpc_cpu_mode_t gpc_mode = IMX_GPC_MODE(info.substate_id); + uint8_t current_set_point = GPC_SP_GetCurrentSetPoint(GPC_SET_POINT_CTRL); + + LOG_DBG("Switch to Set Point %d, GPC Mode %d requested", set_point, gpc_mode); + if (gpc_mode != kGPC_RunMode && (current_set_point != set_point)) { + /* Request set point transition at sleep */ + GPC_CM_RequestSleepModeSetPointTransition(GPC_CPU_MODE_CTRL, + set_point, set_point, kGPC_CM_RequestPreviousSetpoint); + cpu_mode_transition(gpc_mode, true); + } else if (gpc_mode != kGPC_RunMode) { + /* Request CPU mode transition without set mode transition */ + GPC_CM_RequestRunModeSetPointTransition(GPC_CPU_MODE_CTRL, + current_set_point); + cpu_mode_transition(gpc_mode, true); + } +} + +__weak void pm_power_state_exit_post_ops(struct pm_state_info info) +{ + ARG_UNUSED(info); + /* Clear PRIMASK */ + __enable_irq(); + LOG_DBG("Exiting LPM"); + LOG_DBG("CM7 mode was %d", GPC_CM_GetPreviousCpuMode(GPC_CPU_MODE_CTRL_0)); + LOG_DBG("CM4 mode was %d", GPC_CM_GetPreviousCpuMode(GPC_CPU_MODE_CTRL_1)); + LOG_DBG("Previous set point was %d", GPC_SP_GetPreviousSetPoint(GPC_SET_POINT_CTRL)); +} + +/* Initialize RT11xx Power */ +static int rt11xx_power_init(const struct device *dev) +{ + ARG_UNUSED(dev); + /* Drop SOC target voltage to 1.0 V */ + DCDC_SetVDD1P0BuckModeTargetVoltage(DCDC, kDCDC_1P0BuckTarget1P0V); + /* Initialize general power controller */ + gpc_init(); + /* Initialize dcdc */ + dcdc_init(); + return 0; +} + +SYS_INIT(rt11xx_power_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/nxp_imx/rt/power_rt11xx.h b/soc/arm/nxp_imx/rt/power_rt11xx.h new file mode 100644 index 00000000000..b3da3e74ee1 --- /dev/null +++ b/soc/arm/nxp_imx/rt/power_rt11xx.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2021, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef _SOC_ARM_NXP_IMX_RT_POWER_RT11XX_H_ +#define _SOC_ARM_NXP_IMX_RT_POWER_RT11XX_H_ + +/* + * Set point configurations. These are kept in a seprate file for readability. + */ + +#define SP0 0 +#define SP1 1 +#define SP2 2 +#define SP3 3 +#define SP4 4 +#define SP5 5 +#define SP6 6 +#define SP7 7 +#define SP8 8 +#define SP9 9 +#define SP10 10 +#define SP11 11 +#define SP12 12 +#define SP13 13 +#define SP14 14 +#define SP15 15 + + +/* ================= GPC configuration ==================== */ + +#define SET_POINT_COUNT 16 + +/* + * SOC set point mappings + * This matrix defines what set points are allowed for a given core. + * For example, when SP2 is requested, SP1 or SP2 are allowed set points + */ +#define CPU0_COMPATIBLE_SP_TABLE \ +/* NA, SP1, SP2, SP3, SP0, SP4, SP5, SP6, SP7, SP8, SP9, SP10, SP11, SP12, SP13, SP14, SP15 */ \ +/* SP1*/{{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP2 */{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP3 */{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP0 */{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP4 */{ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP5 */{ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP6 */{ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP7 */{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP8 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP9 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, \ +/* SP10 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, \ +/* SP11 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, \ +/* SP12 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, \ +/* SP13 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, \ +/* SP14 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, \ +/* SP15 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}} + +#define CPU1_COMPATIBLE_SP_TABLE \ +/* NA, SP1, SP2, SP3, SP0, SP4, SP5, SP6, SP7, SP8, SP9, SP10, SP11, SP12, SP13, SP14, SP15 */ \ +/* SP1*/{{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP2 */{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP3 */{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP0 */{ 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ +/* SP4 */{ 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP5 */{ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP6 */{ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP7 */{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP8 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP9 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0}, \ +/* SP10 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, \ +/* SP11 */{ 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, \ +/* SP12 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0}, \ +/* SP13 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, \ +/* SP14 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, \ +/* SP15 */{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}} + +/* Allows GPC to control RC16M on/off */ +#define OSC_RC_16M_STBY_VAL 0x0000 + + +/* ================== DCDC configuration ======================= */ +#define PD_WKUP_SP_VAL 0xf800 /* Off at SP11 - SP 15 */ + +#define DCDC_ONOFF_SP_VAL (~PD_WKUP_SP_VAL) +#define DCDC_DIG_ONOFF_SP_VAL DCDC_ONOFF_SP_VAL +#define DCDC_LP_MODE_SP_VAL 0x0000 +#define DCDC_ONOFF_STBY_VAL DCDC_ONOFF_SP_VAL +#define DCDC_LP_MODE_STBY_VAL 0x0000 + + +/* DCDC 1.8V buck mode target voltage in set points 0-15 */ +#define DCDC_1P8_BUCK_MODE_CONFIGURATION_TABLE \ +{ \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ + kDCDC_1P8BuckTarget1P8V, \ +} + +/* DCDC 1.0V buck mode target voltage in set points 0-15 */ +#define DCDC_1P0_BUCK_MODE_CONFIGURATION_TABLE \ +{ \ + kDCDC_1P0BuckTarget1P0V, \ + kDCDC_1P0BuckTarget1P1V, \ + kDCDC_1P0BuckTarget1P1V, \ + kDCDC_1P0BuckTarget1P1V, \ + kDCDC_1P0BuckTarget1P0V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P8V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ + kDCDC_1P0BuckTarget0P9V, \ +} + + +/* DCDC 1.8V standby mode target voltage in set points 0-15 */ +#define DCDC_1P8_STANDBY_MODE_CONFIGURATION_TABLE \ +{ \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ + kDCDC_1P8StbyTarget1P8V, \ +} + +/* DCDC 1.0V standby mode target voltage in set points 0-15 */ +#define DCDC_1P0_STANDBY_MODE_CONFIGURATION_TABLE \ +{ \ + kDCDC_1P0StbyTarget1P0V, \ + kDCDC_1P0StbyTarget1P1V, \ + kDCDC_1P0StbyTarget1P1V, \ + kDCDC_1P0StbyTarget1P1V, \ + kDCDC_1P0StbyTarget1P0V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P8V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ + kDCDC_1P0StbyTarget0P9V, \ +} + +#endif /* _SOC_ARM_NXP_IMX_RT_POWER_RT11XX_H_ */