From e4251f29227c47073ecfb7ea7a41a28f76e97181 Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Wed, 11 Jun 2025 14:08:43 +0530 Subject: [PATCH 1/7] dts: arm: nxp_imx95_m7: add pm node added wait/stop/suspend pm node for imx95 m7 Signed-off-by: Yongxu Wang --- dts/arm/nxp/nxp_imx95_m7.dtsi | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dts/arm/nxp/nxp_imx95_m7.dtsi b/dts/arm/nxp/nxp_imx95_m7.dtsi index a5b6cdb1837d4..0bef43499e473 100644 --- a/dts/arm/nxp/nxp_imx95_m7.dtsi +++ b/dts/arm/nxp/nxp_imx95_m7.dtsi @@ -15,9 +15,10 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m7"; + cpu-power-states = <&wait &stop &suspend>; reg = <0>; #address-cells = <1>; @@ -27,6 +28,30 @@ compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; }; + + }; + + power-states { + wait: power-state-wait { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <100>; + exit-latency-us = <50>; + }; + + stop: power-state-stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000>; + exit-latency-us = <200>; + }; + + suspend: power-state-suspend { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <5000>; + exit-latency-us = <1000>; + }; }; }; From da58d7cd20bea78ec4e3f5acd874c44ac271997e Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Wed, 11 Jun 2025 14:09:42 +0530 Subject: [PATCH 2/7] soc: nxp: imx9: add basic pm process for i.MX95 M7 add basic pm_state_set and pm_state_exit_post_ops Signed-off-by: Yongxu Wang --- soc/nxp/imx/imx9/imx95/Kconfig | 1 + .../imx9/imx95/Kconfig.defconfig.mimx95.m7 | 6 ++ soc/nxp/imx/imx9/imx95/m7/soc.c | 58 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/soc/nxp/imx/imx9/imx95/Kconfig b/soc/nxp/imx/imx9/imx95/Kconfig index 60d1f424b0a5a..ca5e78253bf15 100644 --- a/soc/nxp/imx/imx9/imx95/Kconfig +++ b/soc/nxp/imx/imx9/imx95/Kconfig @@ -13,6 +13,7 @@ config SOC_MIMX9596_M7 select SOC_LATE_INIT_HOOK select HAS_MCUX select HAS_MCUX_CACHE + select HAS_PM config SOC_MIMX9596_A55 select ARM64 diff --git a/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.m7 b/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.m7 index ee356a0ead0d4..64ba81caf7d43 100644 --- a/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.m7 +++ b/soc/nxp/imx/imx9/imx95/Kconfig.defconfig.mimx95.m7 @@ -50,5 +50,11 @@ config CACHE_MANAGEMENT config ETH_NXP_IMX_MSGINTR default 2 +if PM +# 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 endif # SOC_MIMX9596_M7 diff --git a/soc/nxp/imx/imx9/imx95/m7/soc.c b/soc/nxp/imx/imx9/imx95/m7/soc.c index db60e45170eab..5b190835c3399 100644 --- a/soc/nxp/imx/imx9/imx95/m7/soc.c +++ b/soc/nxp/imx/imx9/imx95/m7/soc.c @@ -88,6 +88,64 @@ static int soc_init(void) return ret; } +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + struct scmi_cpu_sleep_mode_config cpu_cfg = {0}; + + /* iMX95 M7 core is based on ARMv7-M architecture. For this architecture, + * the current implementation of arch_irq_lock of zephyr is based on BASEPRI, + * which will only retain abnormal interrupts such as NMI, + * and all other interrupts from the CPU(including systemtick) will be masked, + * which makes the CORE unable to be woken up from WFI. + * Set PRIMASK as workaround, Shield the CPU from responding to interrupts, + * the CPU will not jump to the interrupt service routine (ISR). + */ + __disable_irq(); + /* Set BASEPRI to 0 */ + irq_unlock(0); + + switch (state) { + case PM_STATE_RUNTIME_IDLE: + cpu_cfg.cpu_id = CPU_IDX_M7P; + cpu_cfg.sleep_mode = CPU_SLEEP_MODE_WAIT; + scmi_cpu_sleep_mode_set(&cpu_cfg); + __DSB(); + __WFI(); + break; + case PM_STATE_SUSPEND_TO_IDLE: + cpu_cfg.cpu_id = CPU_IDX_M7P; + cpu_cfg.sleep_mode = CPU_SLEEP_MODE_STOP; + scmi_cpu_sleep_mode_set(&cpu_cfg); + __DSB(); + __WFI(); + break; + case PM_STATE_STANDBY: + cpu_cfg.cpu_id = CPU_IDX_M7P; + cpu_cfg.sleep_mode = CPU_SLEEP_MODE_SUSPEND; + scmi_cpu_sleep_mode_set(&cpu_cfg); + __DSB(); + __WFI(); + break; + default: + break; + } +} + +/* Handle SOC specific activity after Low Power Mode Exit */ +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + + struct scmi_cpu_sleep_mode_config cpu_cfg = {0}; + /* restore M7 core state into ACTIVE. */ + cpu_cfg.cpu_id = CPU_IDX_M7P; + cpu_cfg.sleep_mode = CPU_SLEEP_MODE_RUN; + scmi_cpu_sleep_mode_set(&cpu_cfg); + + /* Clear PRIMASK */ + __enable_irq(); +} + /* * Because platform is using ARM SCMI, drivers like scmi, mbox etc. are * initialized during PRE_KERNEL_1. Common init hooks is not able to use. From 0c59458981bc639b915fd0f4e8f97d61e0044847 Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Wed, 11 Jun 2025 14:11:13 +0530 Subject: [PATCH 3/7] pm: power_mgmt_soc: add imx95_evk m7 into test case yml enable imx95_evk m7 for this power_mgmt_soc test case Signed-off-by: Yongxu Wang --- tests/subsys/pm/power_mgmt_soc/testcase.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/subsys/pm/power_mgmt_soc/testcase.yaml b/tests/subsys/pm/power_mgmt_soc/testcase.yaml index c6a14a3b582cc..2e455a3928560 100644 --- a/tests/subsys/pm/power_mgmt_soc/testcase.yaml +++ b/tests/subsys/pm/power_mgmt_soc/testcase.yaml @@ -17,6 +17,7 @@ tests: - max32690evkit/max32690/m4 - max32655evkit/max32655/m4 - max32655fthr/max32655/m4 + - imx95_evk/mimx9596/m7 tags: pm integration_platforms: - mec15xxevb_assy6853 From 88ba10ae24afc549deeac029393b81741383b9d1 Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Wed, 11 Jun 2025 14:12:10 +0530 Subject: [PATCH 4/7] drivers: scmi: add pre_kernel flag into scmi_send_message SCMI now supports both polling and interrupt modes to determine message completion. By default, polling is used during the pre-kernel phase, while interrupts are used post-kernel. However, for certain SCMI APIs related to power management (PM), although they are invoked post-kernel, using interrupt mode may cause unintended CPU wakeups. To prevent this, polling mode should be used instead. This patch extends the scmi_send_message() interface by adding a 'pre_kernel' parameter, allowing callers to explicitly indicate the desired behavior based on context, rather than relying on internal kernel state detection. Signed-off-by: Yongxu Wang --- drivers/firmware/scmi/clk.c | 13 +++++++------ drivers/firmware/scmi/core.c | 4 ++-- drivers/firmware/scmi/nxp/cpu.c | 3 ++- drivers/firmware/scmi/pinctrl.c | 3 ++- drivers/firmware/scmi/power.c | 5 +++-- include/zephyr/drivers/firmware/scmi/protocol.h | 4 +++- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/scmi/clk.c b/drivers/firmware/scmi/clk.c index 1abd04f1c49a0..514772572efba 100644 --- a/drivers/firmware/scmi/clk.c +++ b/drivers/firmware/scmi/clk.c @@ -6,6 +6,7 @@ #include #include +#include /* TODO: if extended attributes are supported this should be moved * to the header file so that users will have access to it. @@ -57,7 +58,7 @@ int scmi_clock_rate_get(struct scmi_protocol *proto, reply.len = sizeof(reply_buffer); reply.content = &reply_buffer; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -98,7 +99,7 @@ int scmi_clock_rate_set(struct scmi_protocol *proto, struct scmi_clock_rate_conf reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -134,7 +135,7 @@ int scmi_clock_parent_get(struct scmi_protocol *proto, uint32_t clk_id, uint32_t reply.len = sizeof(reply_buffer); reply.content = &reply_buffer; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -172,7 +173,7 @@ int scmi_clock_parent_set(struct scmi_protocol *proto, uint32_t clk_id, uint32_t reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -223,7 +224,7 @@ int scmi_clock_config_set(struct scmi_protocol *proto, reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -260,7 +261,7 @@ int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attrib reply.len = sizeof(reply_buffer); reply.content = &reply_buffer; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } diff --git a/drivers/firmware/scmi/core.c b/drivers/firmware/scmi/core.c index 58e354485ee51..22bb14222f6ef 100644 --- a/drivers/firmware/scmi/core.c +++ b/drivers/firmware/scmi/core.c @@ -159,7 +159,7 @@ static int scmi_send_message_post_kernel(struct scmi_protocol *proto, } int scmi_send_message(struct scmi_protocol *proto, struct scmi_message *msg, - struct scmi_message *reply) + struct scmi_message *reply, bool pre_kernel) { if (!proto->tx) { return -ENODEV; @@ -169,7 +169,7 @@ int scmi_send_message(struct scmi_protocol *proto, struct scmi_message *msg, return -EINVAL; } - if (k_is_pre_kernel()) { + if (pre_kernel) { return scmi_send_message_pre_kernel(proto, msg, reply); } else { return scmi_send_message_post_kernel(proto, msg, reply); diff --git a/drivers/firmware/scmi/nxp/cpu.c b/drivers/firmware/scmi/nxp/cpu.c index 6c3aaa0982247..61a1ef950dc4e 100644 --- a/drivers/firmware/scmi/nxp/cpu.c +++ b/drivers/firmware/scmi/nxp/cpu.c @@ -6,6 +6,7 @@ #include #include +#include DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, nxp_scmi_cpu), NULL); @@ -33,7 +34,7 @@ int scmi_cpu_sleep_mode_set(struct scmi_cpu_sleep_mode_config *cfg) reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, true); if (ret < 0) { return ret; } diff --git a/drivers/firmware/scmi/pinctrl.c b/drivers/firmware/scmi/pinctrl.c index fd0ef80d2ad58..b0600956a27b0 100644 --- a/drivers/firmware/scmi/pinctrl.c +++ b/drivers/firmware/scmi/pinctrl.c @@ -5,6 +5,7 @@ */ #include +#include DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, arm_scmi_pinctrl), NULL); @@ -50,7 +51,7 @@ int scmi_pinctrl_settings_configure(struct scmi_pinctrl_settings *settings) reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } diff --git a/drivers/firmware/scmi/power.c b/drivers/firmware/scmi/power.c index e2c639a03fc36..f7f5e74a8777a 100644 --- a/drivers/firmware/scmi/power.c +++ b/drivers/firmware/scmi/power.c @@ -6,6 +6,7 @@ #include #include +#include DT_SCMI_PROTOCOL_DEFINE_NODEV(DT_INST(0, arm_scmi_power), NULL); @@ -39,7 +40,7 @@ int scmi_power_state_get(uint32_t domain_id, uint32_t *power_state) reply.len = sizeof(reply_buffer); reply.content = &reply_buffer; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } @@ -82,7 +83,7 @@ int scmi_power_state_set(struct scmi_power_state_config *cfg) reply.len = sizeof(status); reply.content = &status; - ret = scmi_send_message(proto, &msg, &reply); + ret = scmi_send_message(proto, &msg, &reply, k_is_pre_kernel()); if (ret < 0) { return ret; } diff --git a/include/zephyr/drivers/firmware/scmi/protocol.h b/include/zephyr/drivers/firmware/scmi/protocol.h index 13ac8ba248c00..89f17330135b5 100644 --- a/include/zephyr/drivers/firmware/scmi/protocol.h +++ b/include/zephyr/drivers/firmware/scmi/protocol.h @@ -115,8 +115,10 @@ int scmi_status_to_errno(int scmi_status); * * @retval 0 if successful * @retval negative errno if failure + * @param pre_kernel current kernel state */ int scmi_send_message(struct scmi_protocol *proto, - struct scmi_message *msg, struct scmi_message *reply); + struct scmi_message *msg, struct scmi_message *reply, + bool pre_kernel); #endif /* _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_PROTOCOL_H_ */ From 94f3ca1ce32aa4325fcaaf248110c17b68bfdb68 Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Thu, 26 Jun 2025 14:49:40 +0530 Subject: [PATCH 5/7] drivers: scmi: disable peer core interrupt when use pre kernel process in pre kernel scmi send message process, it should use poll to receive system manager core notification, add disable and re-enable completion interrupt in this flow. Signed-off-by: Yongxu Wang --- drivers/firmware/scmi/core.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/firmware/scmi/core.c b/drivers/firmware/scmi/core.c index 22bb14222f6ef..7b18315ffcd5e 100644 --- a/drivers/firmware/scmi/core.c +++ b/drivers/firmware/scmi/core.c @@ -8,6 +8,7 @@ #include #include #include +#include "mailbox.h" LOG_MODULE_REGISTER(scmi_core); @@ -87,12 +88,34 @@ static int scmi_core_setup_chan(const struct device *transport, return 0; } +static int scmi_interrupt_enable(struct scmi_channel *chan, bool enable) +{ + struct scmi_mbox_channel *mbox_chan; + struct mbox_dt_spec *tx_reply; + bool compInt; + + mbox_chan = chan->data; + compInt = enable ? SCMI_SHMEM_CHAN_FLAG_IRQ_BIT : 0; + + if (mbox_chan->tx_reply.dev) { + tx_reply = &mbox_chan->tx_reply; + } else { + tx_reply = &mbox_chan->tx; + } + + /* re-set completion interrupt */ + scmi_shmem_update_flags(mbox_chan->shmem, SCMI_SHMEM_CHAN_FLAG_IRQ_BIT, compInt); + + return mbox_set_enabled_dt(tx_reply, enable); +} + static int scmi_send_message_pre_kernel(struct scmi_protocol *proto, struct scmi_message *msg, struct scmi_message *reply) { int ret; + scmi_interrupt_enable(proto->tx, false); ret = scmi_transport_send_message(proto->transport, proto->tx, msg); if (ret < 0) { return ret; @@ -113,6 +136,7 @@ static int scmi_send_message_pre_kernel(struct scmi_protocol *proto, return ret; } + scmi_interrupt_enable(proto->tx, true); return ret; } From 3c10388c0b38e234936f960eaf73b62e437cbeeb Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Tue, 22 Jul 2025 13:07:54 +0800 Subject: [PATCH 6/7] drivers: scmi: add cpu lpm interface api add scmi_cpu_pd_lpm_set api for nxp imx scmi interface Signed-off-by: Yongxu Wang --- drivers/firmware/scmi/nxp/cpu.c | 36 +++++++++++++++++++ .../zephyr/drivers/firmware/scmi/nxp/cpu.h | 29 +++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/drivers/firmware/scmi/nxp/cpu.c b/drivers/firmware/scmi/nxp/cpu.c index 61a1ef950dc4e..caead1904e3f3 100644 --- a/drivers/firmware/scmi/nxp/cpu.c +++ b/drivers/firmware/scmi/nxp/cpu.c @@ -45,3 +45,39 @@ int scmi_cpu_sleep_mode_set(struct scmi_cpu_sleep_mode_config *cfg) return 0; } + +int scmi_cpu_pd_lpm_set(struct scmi_cpu_pd_lpm_config *cfg) +{ + struct scmi_protocol *proto = &SCMI_PROTOCOL_NAME(SCMI_PROTOCOL_CPU_DOMAIN); + struct scmi_message msg, reply; + int status, ret; + + /* sanity checks */ + if (!proto || !cfg) { + return -EINVAL; + } + + if (proto->id != SCMI_PROTOCOL_CPU_DOMAIN) { + return -EINVAL; + } + + msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CPU_DOMAIN_MSG_CPU_PD_LPM_CONFIG_SET, SCMI_COMMAND, + proto->id, 0x0); + msg.len = sizeof(*cfg); + msg.content = cfg; + + reply.hdr = msg.hdr; + reply.len = sizeof(status); + reply.content = &status; + + ret = scmi_send_message(proto, &msg, &reply, true); + if (ret < 0) { + return ret; + } + + if (status != SCMI_SUCCESS) { + return scmi_status_to_errno(status); + } + + return 0; +} diff --git a/include/zephyr/drivers/firmware/scmi/nxp/cpu.h b/include/zephyr/drivers/firmware/scmi/nxp/cpu.h index 687175912ec30..fcb81dd6bcb9d 100644 --- a/include/zephyr/drivers/firmware/scmi/nxp/cpu.h +++ b/include/zephyr/drivers/firmware/scmi/nxp/cpu.h @@ -21,6 +21,8 @@ #define SCMI_PROTOCOL_CPU_DOMAIN 130 +#define SCMI_CPU_MAX_PDCONFIGS_T 7U + /** * @struct scmi_cpu_sleep_mode_config * @@ -33,6 +35,23 @@ struct scmi_cpu_sleep_mode_config { uint32_t sleep_mode; }; +struct scmi_pd_lpm_settings { + uint32_t domainId; + uint32_t lpmSetting; + uint32_t retMask; +}; + +/** + * @struct scmi_cpu_pd_lpm_config + * + * @brief Describes cpu power domain low power mode setting + */ +struct scmi_cpu_pd_lpm_config { + uint32_t cpu_id; + uint32_t num_cfg; + struct scmi_pd_lpm_settings cfgs[SCMI_CPU_MAX_PDCONFIGS_T]; +}; + /** * @brief CPU domain protocol command message IDs */ @@ -64,4 +83,14 @@ enum scmi_cpu_domain_message { */ int scmi_cpu_sleep_mode_set(struct scmi_cpu_sleep_mode_config *cfg); +/** + * @brief Send the SCMI_CPU_DOMAIN_MSG_CPU_PD_LPM_CONFIG_SET command and get its reply + * + * @param cfg pointer to structure containing configuration + * to be set + * + * @retval 0 if successful + * @retval negative errno if failure + */ +int scmi_cpu_pd_lpm_set(struct scmi_cpu_pd_lpm_config *cfg); #endif /* _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_CPU_H_ */ From 138eef8e9398667fa0af4e513b7eb5e80d0065a9 Mon Sep 17 00:00:00 2001 From: Yongxu Wang Date: Tue, 22 Jul 2025 13:09:11 +0800 Subject: [PATCH 7/7] soc: nxp: imx95: setup m7mix and wakeupmix power on in suspend mode wakeupmix keep power on state is essential for system suspend mode, because of console uart locate in it. temporarily set the M7 mix to power on, further optimization will be carried out later Signed-off-by: Yongxu Wang --- soc/nxp/imx/imx9/imx95/m7/soc.c | 31 ++++++++++ soc/nxp/imx/imx9/imx95/scmi_cpu_soc.h | 81 +++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/soc/nxp/imx/imx9/imx95/m7/soc.c b/soc/nxp/imx/imx9/imx95/m7/soc.c index 5b190835c3399..b93a85f638c7c 100644 --- a/soc/nxp/imx/imx9/imx95/m7/soc.c +++ b/soc/nxp/imx/imx9/imx95/m7/soc.c @@ -88,10 +88,41 @@ static int soc_init(void) return ret; } +void pm_state_before(void) +{ + struct scmi_cpu_pd_lpm_config cpu_pd_lpm_cfg; + + /* + * 1. Set M7 mix as power on state in suspend mode + * 2. Keep wakeupmix power on whatever low power mode, as lpuart3(console) in there. + * To do: in order to reduce power consumption, the M7 core in the i.MX95 + * should be powered down during suspend. + * However, after being woken up by a wakeup source, the M7 CPU will restart + * execution from the vector table address, which is not the desired behavior. + * Instead, the vector value should be set to the address where the CPU + * was before entering suspend, and the CPU state should be restored to + * what it was prior to suspend. + */ + + cpu_pd_lpm_cfg.cpu_id = CPU_IDX_M7P; + cpu_pd_lpm_cfg.num_cfg = 2; + cpu_pd_lpm_cfg.cfgs[0].domainId = PWR_MIX_SLICE_IDX_M7; + cpu_pd_lpm_cfg.cfgs[0].lpmSetting = SCMI_CPU_LPM_SETTING_ON_ALWAYS; + cpu_pd_lpm_cfg.cfgs[0].retMask = 1U << PWR_MEM_SLICE_IDX_M7; + cpu_pd_lpm_cfg.cfgs[1].domainId = PWR_MIX_SLICE_IDX_WAKEUP; + cpu_pd_lpm_cfg.cfgs[1].lpmSetting = SCMI_CPU_LPM_SETTING_ON_ALWAYS; + cpu_pd_lpm_cfg.cfgs[1].retMask = 0; + + scmi_cpu_pd_lpm_set(&cpu_pd_lpm_cfg); +} + + void pm_state_set(enum pm_state state, uint8_t substate_id) { struct scmi_cpu_sleep_mode_config cpu_cfg = {0}; + pm_state_before(); + /* iMX95 M7 core is based on ARMv7-M architecture. For this architecture, * the current implementation of arch_irq_lock of zephyr is based on BASEPRI, * which will only retain abnormal interrupts such as NMI, diff --git a/soc/nxp/imx/imx9/imx95/scmi_cpu_soc.h b/soc/nxp/imx/imx9/imx95/scmi_cpu_soc.h index ac23b1fd8b9a6..8afa9f2f370be 100644 --- a/soc/nxp/imx/imx9/imx95/scmi_cpu_soc.h +++ b/soc/nxp/imx/imx9/imx95/scmi_cpu_soc.h @@ -23,4 +23,85 @@ #define CPU_SLEEP_MODE_STOP 2U #define CPU_SLEEP_MODE_SUSPEND 3U +/*! + * @name SCMI CPU LPM settings + */ +#define SCMI_CPU_LPM_SETTING_ON_NEVER 0U +#define SCMI_CPU_LPM_SETTING_ON_RUN 1U +#define SCMI_CPU_LPM_SETTING_ON_RUN_WAIT 2U +#define SCMI_CPU_LPM_SETTING_ON_RUN_WAIT_STOP 3U +#define SCMI_CPU_LPM_SETTING_ON_ALWAYS 4U + +#define CPU_PER_LPI_IDX_GPIO1 0U +#define CPU_PER_LPI_IDX_GPIO2 1U +#define CPU_PER_LPI_IDX_GPIO3 2U +#define CPU_PER_LPI_IDX_GPIO4 3U +#define CPU_PER_LPI_IDX_GPIO5 4U +#define CPU_PER_LPI_IDX_CAN1 5U +#define CPU_PER_LPI_IDX_CAN2 6U +#define CPU_PER_LPI_IDX_CAN3 7U +#define CPU_PER_LPI_IDX_CAN4 8U +#define CPU_PER_LPI_IDX_CAN5 9U +#define CPU_PER_LPI_IDX_LPUART1 10U +#define CPU_PER_LPI_IDX_LPUART2 11U +#define CPU_PER_LPI_IDX_LPUART3 12U +#define CPU_PER_LPI_IDX_LPUART4 13U +#define CPU_PER_LPI_IDX_LPUART5 14U +#define CPU_PER_LPI_IDX_LPUART6 15U +#define CPU_PER_LPI_IDX_LPUART7 16U +#define CPU_PER_LPI_IDX_LPUART8 17U +#define CPU_PER_LPI_IDX_WDOG3 18U +#define CPU_PER_LPI_IDX_WDOG4 19U +#define CPU_PER_LPI_IDX_WDOG5 20U + + +/* MIX definitions */ +#define PWR_NUM_MIX_SLICE 23U + +#define PWR_MIX_SLICE_IDX_ANA 0U +#define PWR_MIX_SLICE_IDX_AON 1U +#define PWR_MIX_SLICE_IDX_BBSM 2U +#define PWR_MIX_SLICE_IDX_CAMERA 3U +#define PWR_MIX_SLICE_IDX_CCMSRCGPC 4U +#define PWR_MIX_SLICE_IDX_A55C0 5U +#define PWR_MIX_SLICE_IDX_A55C1 6U +#define PWR_MIX_SLICE_IDX_A55C2 7U +#define PWR_MIX_SLICE_IDX_A55C3 8U +#define PWR_MIX_SLICE_IDX_A55C4 9U +#define PWR_MIX_SLICE_IDX_A55C5 10U +#define PWR_MIX_SLICE_IDX_A55P 11U +#define PWR_MIX_SLICE_IDX_DDR 12U +#define PWR_MIX_SLICE_IDX_DISPLAY 13U +#define PWR_MIX_SLICE_IDX_GPU 14U +#define PWR_MIX_SLICE_IDX_HSIO_TOP 15U +#define PWR_MIX_SLICE_IDX_HSIO_WAON 16U +#define PWR_MIX_SLICE_IDX_M7 17U +#define PWR_MIX_SLICE_IDX_NETC 18U +#define PWR_MIX_SLICE_IDX_NOC 19U +#define PWR_MIX_SLICE_IDX_NPU 20U +#define PWR_MIX_SLICE_IDX_VPU 21U +#define PWR_MIX_SLICE_IDX_WAKEUP 22U + +#define PWR_MEM_SLICE_IDX_AON 0U +#define PWR_MEM_SLICE_IDX_CAMERA 1U +#define PWR_MEM_SLICE_IDX_A55C0 2U +#define PWR_MEM_SLICE_IDX_A55C1 3U +#define PWR_MEM_SLICE_IDX_A55C2 4U +#define PWR_MEM_SLICE_IDX_A55C3 5U +#define PWR_MEM_SLICE_IDX_A55C4 6U +#define PWR_MEM_SLICE_IDX_A55C5 7U +#define PWR_MEM_SLICE_IDX_A55P 8U +#define PWR_MEM_SLICE_IDX_A55L3 9U +#define PWR_MEM_SLICE_IDX_DDR 10U +#define PWR_MEM_SLICE_IDX_DISPLAY 11U +#define PWR_MEM_SLICE_IDX_GPU 12U +#define PWR_MEM_SLICE_IDX_HSIO 13U +#define PWR_MEM_SLICE_IDX_M7 14U +#define PWR_MEM_SLICE_IDX_NETC 15U +#define PWR_MEM_SLICE_IDX_NOC1 16U +#define PWR_MEM_SLICE_IDX_NOC2 17U +#define PWR_MEM_SLICE_IDX_NPU 18U +#define PWR_MEM_SLICE_IDX_VPU 19U +#define PWR_MEM_SLICE_IDX_WAKEUP 20U + #endif /* ZEPHYR_NXP_IMX95_SCMI_CPU_SOC_H_ */