diff --git a/drivers/soc/imx/pm-domains.c b/drivers/soc/imx/pm-domains.c index be52e35e2cd94e309f9f2006337eea290509b3e5..9b743ee94646f72d08107b7f2572a8be63891a6b 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; }