-
Notifications
You must be signed in to change notification settings - Fork 8k
mcxw7x: Add Power Management support #96891
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
69dda9d
to
e3a628e
Compare
dts/arm/nxp/nxp_mcxw7x_common.dtsi
Outdated
/* This is corresponding to entering the "sleep" mode | ||
* of the MCXW without any futher configurations. This is most simple | ||
* state and is just entered by doing WFI mostly. | ||
*/ | ||
sleep: sleep { | ||
compatible = "zephyr,power-state"; | ||
power-state-name = "runtime-idle"; | ||
min-residency-us = <100>; | ||
exit-latency-us = <0>; | ||
}; | ||
/* This is corresponding to "sleep mode" with extra | ||
* optimization by gating the clocks of certain peripherals, | ||
* also the subdomains voltage levels could be configured differently | ||
* Note it is "suspend-to-idle" for zephyr due to some peripherals may | ||
* lose operation if their clock is gated, even though it is same | ||
* hardware power mode. | ||
*/ | ||
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>; | ||
}; | ||
/* It is possible to do more configuring of the hardware in addition | ||
* to just enter deep sleep, the peripherals in core domain | ||
* can be power gated instead of just low power retention, | ||
* and different peripheral in wakeup domain can be put in low power | ||
* instead of remaining operational. So this is "standby" due to | ||
* allowing configure of power gating peripherals which could lose state | ||
*/ | ||
deep_sleep_optimized: deep-sleep-optimized { | ||
compatible = "zephyr,power-state"; | ||
power-state-name = "standby"; | ||
min-residency-us = <1000>; | ||
exit-latency-us = <11>; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to align about these states, the comments i provided you internally that you seem to have kept here were just brainstorms, this "optimized" state idea , is not complete yet without domains and device runtime PM enablement of the device on this platform, the idea was about system configuration per app, to show that a zephyr PM state doesnt need to map 1:1 with hardware SOC modes
zephyr_sources_ifdef(CONFIG_PM | ||
power.c | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, do on one line
default 96000000 if CORTEX_M_SYSTICK | ||
default $(dt_node_int_prop_int,$(DT_LPTMR_PATH),clock-frequency) if MCUX_LPTMR_TIMER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you sure it's getting set right, I thought the first value will take precedence here, and I don't see wheere would "CORTEX_M_SYSTICK" be unset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CORTEX_M_SYSTICK
is disabled when LPTMR is enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does that happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
soc/nxp/mcx/mcxw/mcxw7xx/power.c
Outdated
#ifdef CONFIG_DEBUG | ||
CMC_EnableDebugOperation(CMC0, true); | ||
#else | ||
CMC_EnableDebugOperation(CMC0, false); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifdef CONFIG_DEBUG | |
CMC_EnableDebugOperation(CMC0, true); | |
#else | |
CMC_EnableDebugOperation(CMC0, false); | |
#endif | |
CMC_EnableDebugOperation(CMC0, IS_ENABLED(CONFIG_DEBUG)); |
soc/nxp/mcx/mcxw/mcxw7xx/soc.c
Outdated
|
||
#if CONFIG_PM | ||
nxp_mcxw7x_power_init(); | ||
set_spc_configuration(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function i dont see why it wouldnt just be called or even just put inline in the power init function, don't know why it is going in soc.c
void nxp_mcxw7x_power_init(void) | ||
{ | ||
/* Enable LPTMR0 as wakeup source */ | ||
NXP_ENABLE_WAKEUP_SIGNAL(0); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like the SPC code can just go in here
soc/nxp/mcx/mcxw/mcxw7xx/soc.c
Outdated
} | ||
#endif | ||
|
||
extern void nxp_mcxw7x_power_init(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be declared in soc.h with a mock ie #else #define nxp_mcxw7x_power_init(...) #endif
soc/nxp/mcx/mcxw/mcxw7xx/soc.h
Outdated
#include <fsl_wuu.h> | ||
|
||
#define PORT_MUX_GPIO kPORT_MuxAsGpio | ||
|
||
#define nbu_handler RF_IMU0_IRQHandler | ||
|
||
#undef NXP_ENABLE_WAKEUP_SIGNAL | ||
#define NXP_ENABLE_WAKEUP_SIGNAL(sig) WUU_SetInternalWakeUpModulesConfig(WUU0,\ | ||
sig, kWUU_InternalModuleInterrupt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as discussed previously, we should not be adding hal headers into soc.h anymore, instead this macro should evaluate to a wrapper function declared in this file and defined in power.c
/* Set PRIMASK */ | ||
__disable_irq(); | ||
/* Set BASEPRI to 0 */ | ||
irq_unlock(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not be necessary, already done by arch code last time I checked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is needed. We can discuss where you see this implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 51 in 4ef1163
(void) arch_irq_lock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
soc/nxp/mcx/mcxw/mcxw7xx/soc.h
Outdated
|
||
#undef NXP_ENABLE_WAKEUP_SIGNAL | ||
#define NXP_ENABLE_WAKEUP_SIGNAL(sig) WUU_SetInternalWakeUpModulesConfig(WUU0,\ | ||
sig, kWUU_InternalModuleInterrupt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @bjarki-andreasen, it seems that the management of wakeup sources in zephyr is currently quite fragmented? Some wakeup sources are managed through device drivers, while others are managed at the SoC level (soc.c/.h). I would like to ask the power management maintainer if there are any plans to introduce a standardized/systematized wakeup source management system. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ZhaoxiangJin it was a discussion a lot the last few years. but what you should know here is in our case that we intend to manage all of them by device driver. this soc.h define idea is to have a common api across all nxp platform that the nxp driver can call. but yes, this approach is just how nxp does it, but I think it will work for us, and is not exposed actually to client code. issue only would arise if NXP platform for some reason used some non-nxp driver for an soc peripheral or vice versa (which, is not impossible, since some IP can come from third party designer that is on many different vendor SOC, but usually still there are changes and they write their own driver pretending it's not third party is what I have noticed)
the way that is common in all of zephyr to declare/configure if something is a wakeup is by putting the wakeup-source
property on it's node in DT.
soc/nxp/mcx/mcxw/mcxw7xx/power.c
Outdated
void nxp_mcxw7x_power_init(void) | ||
{ | ||
/* Enable LPTMR0 as wakeup source */ | ||
NXP_ENABLE_WAKEUP_SIGNAL(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mcxw7x has many wakeup sources. Users may need GPIO wake up, RTC wake up, or LPTMR wake up. However, based on the current approach, users cannot configure them. They can only refer to the SDK implementation or the SoC RM to know how to enable the wakeup sources they need here. Does this go against the Zephyr concept of configure hardware features based on the devicetree?
Currently, Zephyr does not have a wakeup source management subsystem. My view is that we need to describe the WUU information in the wakup source peripheral node, and then configure the WUU in the driver based on the information in the device tree.
As a SoC vendor, we need to enable all these wakeup sources in SoC.dts and driver. The user can use /delete-property/ is-wakeup-source;
to remove wakeup sources they don't need in the board.dts or application.dts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mcxw7x has many wakeup sources. Users may need GPIO wake up, RTC wake up, or LPTMR wake up. However, based on the current approach, users cannot configure them. They can only refer to the SDK implementation or the SoC RM to know how to enable the wakeup sources they need here. Does this go against the Zephyr concept of configure hardware features based on the devicetree?
I think the reason mahesh put this here is because the lptmr in this case is chosen as the kernel timer when CONFIG_PM=y (hence building this function), so it is a system requirement that it should be a wakeup source, otherwise the system doesn't function. So it should not be left up to user configurability in this case. The LPTMR though can also be used just as a normal counter (not system timer) and in that case the wakeup-source
property for configuration would be relevant and the counter driver should be responsible to call this macro to configure the wakeup source conditionally. But for system timer, it is not conditional, it is mandatory.
But, speaking of this line, @mmahadevan108 , this 0 is a magic number, is there not some identifier from the SDK that can mean LPTMR0 wakeup signal?
Currently, Zephyr does not have a wakeup source management subsystem. My view is that we need to describe the WUU information in the wakup source peripheral node, and then configure the WUU in the driver based on the information in the device tree. As a SoC vendor, we need to enable all these wakeup sources in SoC.dts and driver. The user can use
/delete-property/ is-wakeup-source;
to remove wakeup sources they don't need in the board.dts or application.dts.
No, I don't agree to this approach, nothing should be a wakeup by default, except the system timer. User should be explicit about what causes wakeup for their system, not try to figure out all the ones they need to disable, that is just annoying.
As for the discussion about how to do generic wakeup sources in zephyr, I think the current paradigm is well understood enough and sufficient , and we should avoid over architecting and causing churn across the whole project unless we really decide its actually needed, not just for pedantic reasons. But in an ideal world, probably each node would be putting some controller+data style info using phandle arrays in DT similar to the resets
and interrupts
and clocks
property, about how to configure the wakeups
, especially if one device can have different wakeup sources. But I think we should cross that bridge when we come to it, not just for the sake of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can move this to the driver level. I have created PR #96996 for such cases where the wakeup signal is not mapped to the interrupt number.
5ea2df0
to
1c69397
Compare
void mcxw7xx_set_wakeup(int32_t sig) | ||
{ | ||
WUU_SetInternalWakeUpModulesConfig(WUU0, sig, kWUU_InternalModuleInterrupt); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should go in power.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Power.c gets compiled only when PM is enabled. This could get called without PM enabled as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would you be configuring wake up from low power modes if you don't enter them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some drivers may not have CONFIG_PM wrapper added. I don't see a negative to putting this in soc.c
#if CONFIG_PM | ||
extern void nxp_mcxw7x_power_init(void); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not what extern is for, remove that, and declare a mock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whats wrong with having an extern?
#define nbu_handler RF_IMU0_IRQHandler | ||
|
||
#undef NXP_ENABLE_WAKEUP_SIGNAL | ||
extern void mcxw7xx_set_wakeup(int32_t sig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extern is redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was seeing warning without it, so seems needed.
#if CONFIG_PM | ||
nxp_mcxw7x_power_init(); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove #if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a discussion with @DerekSnell about this and we felt it best we make the changes to power only for PM as we want some of the voltage detects to stay enabled and the low voltage config is needed only for low power modes.
default 96000000 if CORTEX_M_SYSTICK | ||
default $(dt_node_int_prop_int,$(DT_LPTMR_PATH),clock-frequency) if MCUX_LPTMR_TIMER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does that happen?
/* Set PRIMASK */ | ||
__disable_irq(); | ||
/* Set BASEPRI to 0 */ | ||
irq_unlock(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 51 in 4ef1163
(void) arch_irq_lock(); |
/* 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should not be setting domain states in the SOC power driver, this is backwards. the state of the domains should be handled by domain drivers and the result will affect what actual SOC state is selected in the first place based on device runtime PM constraints. cc @bjarki-andreasen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimally the devicetree would contain the power domains which manage the main and wake domains, if anything needs them to be resumed, the power domains would be resumed directly (thus not in sleep mode) and the sleep mode which can only be entered if they are suspended, would have been blocked by the drivers/power domains with pm_policy_state_lock_get()
or similar.
That said, some hardware is just quirky, it may make no sense to manage these power domains independently, which is maybe hinted at by the CMC_EnterLowPowerMode(CMC0, &config); taking one config which configures all of them together, so this may just be the way to enter one particular sleep mode.
Add support for power management states Signed-off-by: Mahesh Mahadevan <[email protected]>
Add bindings for the power related modules. Use the bindings Kconfig to pull in SDK drivers for cmc, spc, vbat and wuu. Signed-off-by: Mahesh Mahadevan <[email protected]>
Add PM support for MCXW SoC's Signed-off-by: Mahesh Mahadevan <[email protected]>
1c69397
to
924806f
Compare
|
Add support for power management states
Signed-off-by: Mahesh Mahadevan [email protected]