From dbc9abcf114bde0d7e4dd60d058a8b4abca92303 Mon Sep 17 00:00:00 2001 From: Anson Huang <Anson.Huang@nxp.com> Date: Wed, 27 Mar 2019 17:23:32 +0800 Subject: [PATCH] MLK-21287 soc: imx: keep resource power ON if subdomain is wakeup source The power mode operation ONLY checks whether the resource being powered OFF is a wakeup source, and skip power OFF operation if it is a wakeup source, but it does NOT consider the power tree status, if any of its children is a wakeup source, it needs to be kept powered ON for its children's wakeup capability. For example, on i.MX8QXP, CAN1 shares CAN0's power, if CAN1 is enabled as wakeup source, CAN0's power needs to be ON even it is NOT a wakeup source, this patch adds support for such scenario. As it uses recursion, to avoid overhead during runtime power management, introduce a variable to make sure this logic is ONLY enabled during suspend/resume. The generic power domain framework for handling device power according to wakeup status does NOT consider the virtual devices, e.g., if debug uart is enabled as wakeup source, the device wakeup capability check for uart device returns false, ONLY the ttydev has wakeup capability, that will cause resume_needed() return false and uart device power will be OFF even its child device "ttydev" is enabeld as wakeup source. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Tested-by: Joakim Zhang <qiangqing.zhang@nxp.com> Reviewed-by: Bai Ping <ping.bai@nxp.com> (cherry picked from commit 459db9c5f53735f33753a7a60232784b3d09d261) --- drivers/soc/imx/pm-domains.c | 46 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/drivers/soc/imx/pm-domains.c b/drivers/soc/imx/pm-domains.c index c09c2b49aafab2..0ea07ebf24051f 100644 --- a/drivers/soc/imx/pm-domains.c +++ b/drivers/soc/imx/pm-domains.c @@ -31,6 +31,7 @@ #include <linux/pm_clock.h> #include <linux/slab.h> #include <linux/syscore_ops.h> +#include <linux/suspend.h> #include <soc/imx/fsl_sip.h> #include <soc/imx8/sc/sci.h> @@ -43,6 +44,7 @@ static sc_rsrc_t rsrc_debug_console; #define IMX8_WU_MAX_IRQS (((SC_R_LAST + 31) / 32 ) * 32 ) static sc_rsrc_t irq2rsrc[IMX8_WU_MAX_IRQS]; static sc_rsrc_t wakeup_rsrc_id[IMX8_WU_MAX_IRQS / 32]; +static bool check_subdomain_wakeup; static DEFINE_SPINLOCK(imx8_wu_lock); static DEFINE_MUTEX(rsrc_pm_list_lock); @@ -57,6 +59,27 @@ struct clk_stat { unsigned long rate; }; +static bool is_resume_needed(struct generic_pm_domain *domain) +{ + struct gpd_link *link; + struct imx8_pm_domain *pd; + int ret; + + pd = container_of(domain, struct imx8_pm_domain, pd); + + /* keep resource power on if it is a wakeup source */ + if ((1 << pd->rsrc_id % 32) & wakeup_rsrc_id[pd->rsrc_id / 32]) + return true; + + list_for_each_entry(link, &domain->master_links, master_node) { + ret = is_resume_needed(link->slave); + if (ret) + return ret; + } + + return false; +} + static int imx8_pd_power(struct generic_pm_domain *domain, bool power_on) { struct imx8_pm_domain *pd; @@ -72,10 +95,9 @@ static int imx8_pd_power(struct generic_pm_domain *domain, bool power_on) !console_suspend_enabled && !power_on) return 0; - /* keep resource power on if it is a wakeup source */ - if (!power_on && ((1 << pd->rsrc_id % 32) & - wakeup_rsrc_id[pd->rsrc_id / 32])) - return 0; + if (!power_on && check_subdomain_wakeup) + if (is_resume_needed(domain)) + return 0; sci_err = sc_pm_set_resource_power_mode(pm_ipc_handle, pd->rsrc_id, (power_on) ? SC_PM_PW_MODE_ON : @@ -300,6 +322,21 @@ struct syscore_ops imx8_pm_domains_syscore_ops = { .suspend = imx8_pm_domains_suspend, }; +static int imx8_power_domain_pm_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + if (event == PM_SUSPEND_PREPARE) + check_subdomain_wakeup = true; + else if (event == PM_POST_SUSPEND) + check_subdomain_wakeup = false; + + return NOTIFY_OK; +} + +static struct notifier_block imx8_power_domain_pm_notifier = { + .notifier_call = imx8_power_domain_pm_notify, +}; + static void imx8_pd_setup(struct imx8_pm_domain *pd) { pd->pd.states = kzalloc(2 * sizeof(struct genpd_power_state), GFP_KERNEL); @@ -411,6 +448,7 @@ static int __init imx8_init_pm_domains(void) sci_err = sc_ipc_open(&pm_ipc_handle, mu_id); register_syscore_ops(&imx8_pm_domains_syscore_ops); + register_pm_notifier(&imx8_power_domain_pm_notifier); return 0; } -- GitLab