-
Notifications
You must be signed in to change notification settings - Fork 7.7k
NXP imx95 add basic pm support #91410
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?
NXP imx95 add basic pm support #91410
Conversation
9ab89c6
to
44fd99b
Compare
hi @ceolin @bjarki-andreasen @yangbolu1991, @JiafeiPan , can you help review this pr when you time free? its basic pm support for imx95 m7 core, thanks |
drivers/firmware/scmi/core.c
Outdated
{ | ||
struct k_thread *current = k_current_get(); | ||
|
||
return strcmp(k_thread_name_get(current), "idle") == 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.
use z_is_idle_thread_object(current)
?
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 internal to kernel, but yep, this is better than check the name that depends on CONFIG_THREAD_NAME
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.
thanks, have updated
drivers/firmware/scmi/core.c
Outdated
@@ -158,6 +158,13 @@ static int scmi_send_message_post_kernel(struct scmi_protocol *proto, | |||
return ret; | |||
} | |||
|
|||
bool scmi_is_current_thread_idle(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.
static ?
drivers/firmware/scmi/core.c
Outdated
* the sm interrupt should be disabled in the soc low power phase. | ||
* In this case, the pre kernel is used instead of the post kernel. | ||
*/ | ||
use_pre_kernel_path = use_pre_kernel_path || scmi_is_current_thread_idle(); |
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.
use_pre_kernel_path |= scmi_is_current_thread_idle();
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.
thanks, updated
soc/nxp/imx/imx9/imx95/m7/soc.c
Outdated
irq_unlock(0); | ||
|
||
/* disabled system manager irq */ | ||
irq_disable(DT_IRQN(DT_NODELABEL(mu5))); |
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.
Would you please help me to understand why still need to disable SM irq as you have already called __disable_irq();
which should have disable all interrupt?
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 above code only mask irq to don't give reaction to interrupt, the capacity of wakeup Mcore from wfi is reserved, and the sm protocol use interrupt from scmi notification logic even though use scmi pre_kernel logic, so we need disabled mu5 now.
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 agree @JiafeiPan i still don't get why mu5 irq needs to be disabled if IRQ's are disabled already.
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 system manager will reply message in currently mechanism, so we need keep mu5 is be disabled to not wakeup m7 core from wfi after run scmi interface api.
- the _disable_irq is to set PRIMASK register, it will mask all regular peripheral interrupt responce for cpu(such as m7 core), it mean that m7 can't enter nvic irq handler in this side, but this will not shield the triggering of interrupts, which will cause the CPU to be awakened from WFI. So in low power use case, although we have already set _disable_irq, but the cpu still have recognize this MU interrupt and thus leave WFI.
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.
Isn't then the system design of system manager flawed? And needs reconsideration?
I think Linux uses the same mechanism using SCMI for PM does that work well then?
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.
in linux side, the low power flow is in atf side, the atf use another mu, the atf mu use polling mode and set non-interrupt in there, but it have not this distinguish in zephyr now, and this way is hard to dela with in zephyr as it need another MU hardware resource, I think we can set mu hardware interface into non-interrupt mode in per kernel send scmi message side, in this it can fix this issue from my understand.
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.
Yes putting SCMI into non-interrupt mode for PM makes sense. Then poll response after wake up, this doesn't do busy waiting. Then after wakeup put SCMI MU into interrupt mode.
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.
sure, have updated it, now in pre kernel process(include idle task pm case), it will disable shem completion interrupt and mu side interrupt, and resume it after send message done. please help review it again
soc/nxp/imx/imx9/imx95/m7/soc.c
Outdated
scmi_cpu_sleep_mode_set(&cpu_cfg); | ||
__DSB(); | ||
__WFI(); | ||
__ISB(); |
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.
whether need ISB after WFI
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.
updated. 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.
Don't know anything about SCMI, but at least some irq_disable() may be superfluous :)
soc/nxp/imx/imx9/imx95/m7/soc.c
Outdated
/* Set PRIMASK, 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); |
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.
when we get here, irqs are already disabled by PM, see
Line 51 in a626d86
(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.
Maybe because this arch using BASEPRI
instead of masking interruptions globally ? This is still confusing for me too.
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.
hi @ceolin @bjarki-andreasen , this is as imx95 m7 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. so we used primask rather than defaultly basepri in there
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.
is that a bug in the implementation of arch_irq_lock()
for this arch? arch_irq_lock()
is only supposed to block ISRs from being executed, not the CPU from waking up. Maybe a fix at arch level would be more fitting, or?
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.
if we want keep arch_irq_lock keep wakeup source capacity for all arch, it have some issue from my understand, its best to fix in top arch level, https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/arch/arm/cortex_m/exception.h#L53
drivers/firmware/scmi/core.c
Outdated
{ | ||
struct k_thread *current = k_current_get(); | ||
|
||
return strcmp(k_thread_name_get(current), "idle") == 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.
This is internal to kernel, but yep, this is better than check the name that depends on CONFIG_THREAD_NAME
dts/arm/nxp/nxp_imx95_m7.dtsi
Outdated
}; | ||
|
||
power-states { | ||
active: power-state-active { |
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.
What this state means ? Power states are used by the power management subsystem and are used only by the idle thread.
Since you don't have any special treatment for this state in pm_state_set
you can remove it. This way the power subsystem won't find a suitable state and will just sit idle (wfi
or wfe
).
If you keep it the idle thread will continuously loop issuing pm_state_set
and pm_state_exit_post_ops
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.
thanks reminder, have deleted it
soc/nxp/imx/imx9/imx95/m7/soc.c
Outdated
/* Set PRIMASK, 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); |
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.
Maybe because this arch using BASEPRI
instead of masking interruptions globally ? This is still confusing for me too.
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.
Could you verify if the systick is actually capable of waking up the core when doing wfi?
We've seen some issues with this, that other interrupts can wake the m7 but the systisck doesn't thus giving big delays.
44fd99b
to
d9fc857
Compare
hi @PetervdPerk-NXP , in my side, the system tick work fine on this patch |
d9fc857
to
4708bc7
Compare
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.
Regarding __disable_irq(), its soc dependent, so if it works, its fine. Regarding using internal kernel apis to check for idle thread context, that seems like a clear layering violation, and I have proposed a solution which seems to be more appropriate :)
4708bc7
to
c966036
Compare
added wait/stop/suspend pm node for imx95 m7 Signed-off-by: Yongxu Wang <[email protected]>
add basic pm_state_set and pm_state_exit_post_ops Signed-off-by: Yongxu Wang <[email protected]>
enable imx95_evk m7 for this power_mgmt_soc test case Signed-off-by: Yongxu Wang <[email protected]>
c966036
to
fe2807b
Compare
update this patch to re-name cpu into cpu0: cpu@0 in order to align pm test case, please help review this pr when time free, thanks a lot |
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 <[email protected]>
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 <[email protected]>
fe2807b
to
866dd58
Compare
add scmi_cpu_pd_lpm_set api for nxp imx scmi interface Signed-off-by: Yongxu Wang <[email protected]>
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 <[email protected]>
866dd58
to
138eef8
Compare
newly update:
|
|
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.
Nice work! looks clean :)
ping @ceolin |
added basic pm support for imx95 evk m7 board, verified it in power_mgmt_soc test case, based on this case, M7 can enter/exit wait/suspend mode as we expected.