From f7a7eb9ee3f6f48d488a1a822e338afa4c7199ab Mon Sep 17 00:00:00 2001 From: zhuyanlin Date: Tue, 21 Dec 2021 15:38:38 +0800 Subject: [PATCH] power/PM: add domain inner update power state feature In some scenarios, We need to update state information internally. Instead of use idle-task to drive the checkstate and change state function. Signed-off-by: zhuyanlin --- drivers/power/Make.defs | 2 +- drivers/power/activity_governor.c | 9 +-- drivers/power/pm.h | 27 +++++++ drivers/power/pm_activity.c | 8 ++ drivers/power/pm_autoupdate.c | 117 ++++++++++++++++++++++++++++++ include/nuttx/power/pm.h | 18 +++++ 6 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 drivers/power/pm_autoupdate.c diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs index 39636dcb9d..c0b79367ee 100644 --- a/drivers/power/Make.defs +++ b/drivers/power/Make.defs @@ -23,7 +23,7 @@ ifeq ($(CONFIG_PM),y) CSRCS += pm_initialize.c pm_activity.c pm_changestate.c pm_checkstate.c -CSRCS += pm_register.c pm_unregister.c +CSRCS += pm_register.c pm_unregister.c pm_autoupdate.c # Governor implementations diff --git a/drivers/power/activity_governor.c b/drivers/power/activity_governor.c index 75ef9f7760..8ab9c5b1fb 100644 --- a/drivers/power/activity_governor.c +++ b/drivers/power/activity_governor.c @@ -534,11 +534,7 @@ static void governor_statechanged(int domain, enum pm_state_e newstate) static void governor_timer_cb(wdparm_t arg) { - /* Do nothing here, cause we only need TIMER ISR to wake up PM, - * for deceasing PM state. - */ - - UNUSED(arg); + pm_auto_updatestate((int)arg); } /**************************************************************************** @@ -586,7 +582,8 @@ static void governor_timer(int domain) if (!WDOG_ISACTIVE(&pdomstate->wdog) || abs(delay - left) > PM_TIMER_GAP) { - wd_start(&pdomstate->wdog, delay, governor_timer_cb, 0); + wd_start(&pdomstate->wdog, delay, governor_timer_cb, + (wdparm_t)domain); } } else diff --git a/drivers/power/pm.h b/drivers/power/pm.h index 876663c253..1f73e78025 100644 --- a/drivers/power/pm.h +++ b/drivers/power/pm.h @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_PM @@ -78,6 +79,16 @@ struct pm_domain_s /* The power state lock count */ uint16_t stay[PM_COUNT]; + + /* Auto update or not */ + + bool auto_update; + +#if defined(CONFIG_SCHED_WORKQUEUE) + /* The worker of update callback */ + + struct work_s update_work; +#endif }; /* This structure encapsulates all of the global data used by the PM system */ @@ -127,6 +138,22 @@ EXTERN struct pm_global_s g_pmglobals; * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: pm_auto_updatestate + * + * Description: + * This function update the domain state and notify the power system. + * + * Input Parameters: + * domain - The PM domain to check + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void pm_auto_updatestate(int domain); + #undef EXTERN #if defined(__cplusplus) } diff --git a/drivers/power/pm_activity.c b/drivers/power/pm_activity.c index 93529b82e1..641b578d0d 100644 --- a/drivers/power/pm_activity.c +++ b/drivers/power/pm_activity.c @@ -69,10 +69,14 @@ void pm_activity(int domain, int priority) { + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + if (g_pmglobals.governor->activity) { g_pmglobals.governor->activity(domain, priority); } + + pm_auto_updatestate(domain); } /**************************************************************************** @@ -112,6 +116,8 @@ void pm_stay(int domain, enum pm_state_e state) DEBUGASSERT(pdom->stay[state] < UINT16_MAX); pdom->stay[state]++; leave_critical_section(flags); + + pm_auto_updatestate(domain); } /**************************************************************************** @@ -150,6 +156,8 @@ void pm_relax(int domain, enum pm_state_e state) DEBUGASSERT(pdom->stay[state] > 0); pdom->stay[state]--; leave_critical_section(flags); + + pm_auto_updatestate(domain); } /**************************************************************************** diff --git a/drivers/power/pm_autoupdate.c b/drivers/power/pm_autoupdate.c new file mode 100644 index 0000000000..b0d7601af7 --- /dev/null +++ b/drivers/power/pm_autoupdate.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * drivers/power/pm_autoupdate.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include "pm.h" + +#if defined(CONFIG_PM) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void pm_auto_updatestate_cb(FAR void *arg) +{ + int domain = (uintptr_t)arg; + enum pm_state_e newstate; + + newstate = pm_checkstate(domain); + pm_changestate(domain, newstate); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pm_auto_updatestate + * + * Description: + * This function update the domain state and notify the power system. + * + * Input Parameters: + * domain - The PM domain to check + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void pm_auto_updatestate(int domain) +{ + FAR struct pm_domain_s *pdom; + pdom = &g_pmglobals.domain[domain]; + + if (pdom->auto_update) + { +#if defined(CONFIG_SCHED_WORKQUEUE) + if (up_interrupt_context()) + { + work_queue(HPWORK, &pdom->update_work, + pm_auto_updatestate_cb, (FAR void *)domain, 0); + } + else +#endif + { + pm_auto_updatestate_cb((FAR void *)domain); + } + } +} + +/**************************************************************************** + * Name: pm_auto_update + * + * Description: + * This function set the domain with assign mode. + * + * Input Parameters: + * domain - The PM domain to check + * auto_update - The PM domain auto update or not + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void pm_auto_update(int domain, bool auto_update) +{ + FAR struct pm_domain_s *pdom; + irqstate_t flags; + + DEBUGASSERT(domain >= 0 && domain < CONFIG_PM_NDOMAINS); + pdom = &g_pmglobals.domain[domain]; + + flags = enter_critical_section(); + pdom->auto_update = auto_update; + leave_critical_section(flags); +} + +#endif /* CONFIG_PM */ diff --git a/include/nuttx/power/pm.h b/include/nuttx/power/pm.h index 1b5d163246..2339d49683 100644 --- a/include/nuttx/power/pm.h +++ b/include/nuttx/power/pm.h @@ -55,6 +55,7 @@ #include +#include #include #ifdef CONFIG_PM @@ -312,6 +313,23 @@ extern "C" void pm_initialize(void); +/**************************************************************************** + * Name: pm_auto_update + * + * Description: + * This function set the domain with assign update mode. + * + * Input Parameters: + * domain - The PM domain to check + * auto_update - The PM domain auto update or not + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void pm_auto_update(int domain, bool auto_update); + /**************************************************************************** * Name: pm_register *