18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * rmobile power management support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2012  Renesas Solutions Corp.
68c2ecf20Sopenharmony_ci * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
78c2ecf20Sopenharmony_ci * Copyright (C) 2014  Glider bvba
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * based on pm-sh7372.c
108c2ecf20Sopenharmony_ci *  Copyright (C) 2011 Magnus Damm
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#include <linux/clk/renesas.h>
138c2ecf20Sopenharmony_ci#include <linux/console.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_address.h>
178c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/pm.h>
208c2ecf20Sopenharmony_ci#include <linux/pm_clock.h>
218c2ecf20Sopenharmony_ci#include <linux/pm_domain.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <asm/io.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* SYSC */
278c2ecf20Sopenharmony_ci#define SPDCR		0x08	/* SYS Power Down Control Register */
288c2ecf20Sopenharmony_ci#define SWUCR		0x14	/* SYS Wakeup Control Register */
298c2ecf20Sopenharmony_ci#define PSTR		0x80	/* Power Status Register */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define PSTR_RETRIES	100
328c2ecf20Sopenharmony_ci#define PSTR_DELAY_US	10
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct rmobile_pm_domain {
358c2ecf20Sopenharmony_ci	struct generic_pm_domain genpd;
368c2ecf20Sopenharmony_ci	struct dev_power_governor *gov;
378c2ecf20Sopenharmony_ci	int (*suspend)(void);
388c2ecf20Sopenharmony_ci	void __iomem *base;
398c2ecf20Sopenharmony_ci	unsigned int bit_shift;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline
438c2ecf20Sopenharmony_cistruct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return container_of(d, struct rmobile_pm_domain, genpd);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int rmobile_pd_power_down(struct generic_pm_domain *genpd)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
518c2ecf20Sopenharmony_ci	unsigned int mask = BIT(rmobile_pd->bit_shift);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (rmobile_pd->suspend) {
548c2ecf20Sopenharmony_ci		int ret = rmobile_pd->suspend();
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		if (ret)
578c2ecf20Sopenharmony_ci			return ret;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (__raw_readl(rmobile_pd->base + PSTR) & mask) {
618c2ecf20Sopenharmony_ci		unsigned int retry_count;
628c2ecf20Sopenharmony_ci		__raw_writel(mask, rmobile_pd->base + SPDCR);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
658c2ecf20Sopenharmony_ci			if (!(__raw_readl(rmobile_pd->base + SPDCR) & mask))
668c2ecf20Sopenharmony_ci				break;
678c2ecf20Sopenharmony_ci			cpu_relax();
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask,
728c2ecf20Sopenharmony_ci		 __raw_readl(rmobile_pd->base + PSTR));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	unsigned int mask = BIT(rmobile_pd->bit_shift);
808c2ecf20Sopenharmony_ci	unsigned int retry_count;
818c2ecf20Sopenharmony_ci	int ret = 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (__raw_readl(rmobile_pd->base + PSTR) & mask)
848c2ecf20Sopenharmony_ci		return ret;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	__raw_writel(mask, rmobile_pd->base + SWUCR);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
898c2ecf20Sopenharmony_ci		if (!(__raw_readl(rmobile_pd->base + SWUCR) & mask))
908c2ecf20Sopenharmony_ci			break;
918c2ecf20Sopenharmony_ci		if (retry_count > PSTR_RETRIES)
928c2ecf20Sopenharmony_ci			udelay(PSTR_DELAY_US);
938c2ecf20Sopenharmony_ci		else
948c2ecf20Sopenharmony_ci			cpu_relax();
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	if (!retry_count)
978c2ecf20Sopenharmony_ci		ret = -EIO;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
1008c2ecf20Sopenharmony_ci		 rmobile_pd->genpd.name, mask,
1018c2ecf20Sopenharmony_ci		 __raw_readl(rmobile_pd->base + PSTR));
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return ret;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int rmobile_pd_power_up(struct generic_pm_domain *genpd)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	return __rmobile_pd_power_up(to_rmobile_pd(genpd));
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct generic_pm_domain *genpd = &rmobile_pd->genpd;
1148c2ecf20Sopenharmony_ci	struct dev_power_governor *gov = rmobile_pd->gov;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
1178c2ecf20Sopenharmony_ci	genpd->attach_dev = cpg_mstp_attach_dev;
1188c2ecf20Sopenharmony_ci	genpd->detach_dev = cpg_mstp_detach_dev;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) {
1218c2ecf20Sopenharmony_ci		genpd->power_off = rmobile_pd_power_down;
1228c2ecf20Sopenharmony_ci		genpd->power_on = rmobile_pd_power_up;
1238c2ecf20Sopenharmony_ci		__rmobile_pd_power_up(rmobile_pd);
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int rmobile_pd_suspend_console(void)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * Serial consoles make use of SCIF hardware located in this domain,
1338c2ecf20Sopenharmony_ci	 * hence keep the power domain on if "no_console_suspend" is set.
1348c2ecf20Sopenharmony_ci	 */
1358c2ecf20Sopenharmony_ci	return console_suspend_enabled ? 0 : -EBUSY;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cienum pd_types {
1398c2ecf20Sopenharmony_ci	PD_NORMAL,
1408c2ecf20Sopenharmony_ci	PD_CPU,
1418c2ecf20Sopenharmony_ci	PD_CONSOLE,
1428c2ecf20Sopenharmony_ci	PD_DEBUG,
1438c2ecf20Sopenharmony_ci	PD_MEMCTL,
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define MAX_NUM_SPECIAL_PDS	16
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic struct special_pd {
1498c2ecf20Sopenharmony_ci	struct device_node *pd;
1508c2ecf20Sopenharmony_ci	enum pd_types type;
1518c2ecf20Sopenharmony_ci} special_pds[MAX_NUM_SPECIAL_PDS] __initdata;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic unsigned int num_special_pds __initdata;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic const struct of_device_id special_ids[] __initconst = {
1568c2ecf20Sopenharmony_ci	{ .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG },
1578c2ecf20Sopenharmony_ci	{ .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, },
1588c2ecf20Sopenharmony_ci	{ .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, },
1598c2ecf20Sopenharmony_ci	{ .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, },
1608c2ecf20Sopenharmony_ci	{ /* sentinel */ },
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void __init add_special_pd(struct device_node *np, enum pd_types type)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	unsigned int i;
1668c2ecf20Sopenharmony_ci	struct device_node *pd;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	pd = of_parse_phandle(np, "power-domains", 0);
1698c2ecf20Sopenharmony_ci	if (!pd)
1708c2ecf20Sopenharmony_ci		return;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	for (i = 0; i < num_special_pds; i++)
1738c2ecf20Sopenharmony_ci		if (pd == special_pds[i].pd && type == special_pds[i].type) {
1748c2ecf20Sopenharmony_ci			of_node_put(pd);
1758c2ecf20Sopenharmony_ci			return;
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if (num_special_pds == ARRAY_SIZE(special_pds)) {
1798c2ecf20Sopenharmony_ci		pr_warn("Too many special PM domains\n");
1808c2ecf20Sopenharmony_ci		of_node_put(pd);
1818c2ecf20Sopenharmony_ci		return;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	special_pds[num_special_pds].pd = pd;
1878c2ecf20Sopenharmony_ci	special_pds[num_special_pds].type = type;
1888c2ecf20Sopenharmony_ci	num_special_pds++;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void __init get_special_pds(void)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct device_node *np;
1948c2ecf20Sopenharmony_ci	const struct of_device_id *id;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* PM domains containing CPUs */
1978c2ecf20Sopenharmony_ci	for_each_of_cpu_node(np)
1988c2ecf20Sopenharmony_ci		add_special_pd(np, PD_CPU);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* PM domain containing console */
2018c2ecf20Sopenharmony_ci	if (of_stdout)
2028c2ecf20Sopenharmony_ci		add_special_pd(of_stdout, PD_CONSOLE);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* PM domains containing other special devices */
2058c2ecf20Sopenharmony_ci	for_each_matching_node_and_match(np, special_ids, &id)
2068c2ecf20Sopenharmony_ci		add_special_pd(np, (enum pd_types)id->data);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void __init put_special_pds(void)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	unsigned int i;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	for (i = 0; i < num_special_pds; i++)
2148c2ecf20Sopenharmony_ci		of_node_put(special_pds[i].pd);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic enum pd_types __init pd_type(const struct device_node *pd)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	unsigned int i;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	for (i = 0; i < num_special_pds; i++)
2228c2ecf20Sopenharmony_ci		if (pd == special_pds[i].pd)
2238c2ecf20Sopenharmony_ci			return special_pds[i].type;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return PD_NORMAL;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void __init rmobile_setup_pm_domain(struct device_node *np,
2298c2ecf20Sopenharmony_ci					   struct rmobile_pm_domain *pd)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	const char *name = pd->genpd.name;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	switch (pd_type(np)) {
2348c2ecf20Sopenharmony_ci	case PD_CPU:
2358c2ecf20Sopenharmony_ci		/*
2368c2ecf20Sopenharmony_ci		 * This domain contains the CPU core and therefore it should
2378c2ecf20Sopenharmony_ci		 * only be turned off if the CPU is not in use.
2388c2ecf20Sopenharmony_ci		 */
2398c2ecf20Sopenharmony_ci		pr_debug("PM domain %s contains CPU\n", name);
2408c2ecf20Sopenharmony_ci		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
2418c2ecf20Sopenharmony_ci		break;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	case PD_CONSOLE:
2448c2ecf20Sopenharmony_ci		pr_debug("PM domain %s contains serial console\n", name);
2458c2ecf20Sopenharmony_ci		pd->gov = &pm_domain_always_on_gov;
2468c2ecf20Sopenharmony_ci		pd->suspend = rmobile_pd_suspend_console;
2478c2ecf20Sopenharmony_ci		break;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	case PD_DEBUG:
2508c2ecf20Sopenharmony_ci		/*
2518c2ecf20Sopenharmony_ci		 * This domain contains the Coresight-ETM hardware block and
2528c2ecf20Sopenharmony_ci		 * therefore it should only be turned off if the debug module
2538c2ecf20Sopenharmony_ci		 * is not in use.
2548c2ecf20Sopenharmony_ci		 */
2558c2ecf20Sopenharmony_ci		pr_debug("PM domain %s contains Coresight-ETM\n", name);
2568c2ecf20Sopenharmony_ci		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
2578c2ecf20Sopenharmony_ci		break;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	case PD_MEMCTL:
2608c2ecf20Sopenharmony_ci		/*
2618c2ecf20Sopenharmony_ci		 * This domain contains a memory-controller and therefore it
2628c2ecf20Sopenharmony_ci		 * should only be turned off if memory is not in use.
2638c2ecf20Sopenharmony_ci		 */
2648c2ecf20Sopenharmony_ci		pr_debug("PM domain %s contains MEMCTL\n", name);
2658c2ecf20Sopenharmony_ci		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	case PD_NORMAL:
2698c2ecf20Sopenharmony_ci		if (pd->bit_shift == ~0) {
2708c2ecf20Sopenharmony_ci			/* Top-level always-on domain */
2718c2ecf20Sopenharmony_ci			pr_debug("PM domain %s is always-on domain\n", name);
2728c2ecf20Sopenharmony_ci			pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		break;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	rmobile_init_pm_domain(pd);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic int __init rmobile_add_pm_domains(void __iomem *base,
2818c2ecf20Sopenharmony_ci					 struct device_node *parent,
2828c2ecf20Sopenharmony_ci					 struct generic_pm_domain *genpd_parent)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct device_node *np;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for_each_child_of_node(parent, np) {
2878c2ecf20Sopenharmony_ci		struct rmobile_pm_domain *pd;
2888c2ecf20Sopenharmony_ci		u32 idx = ~0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		if (of_property_read_u32(np, "reg", &idx)) {
2918c2ecf20Sopenharmony_ci			/* always-on domain */
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
2958c2ecf20Sopenharmony_ci		if (!pd) {
2968c2ecf20Sopenharmony_ci			of_node_put(np);
2978c2ecf20Sopenharmony_ci			return -ENOMEM;
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		pd->genpd.name = np->name;
3018c2ecf20Sopenharmony_ci		pd->base = base;
3028c2ecf20Sopenharmony_ci		pd->bit_shift = idx;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		rmobile_setup_pm_domain(np, pd);
3058c2ecf20Sopenharmony_ci		if (genpd_parent)
3068c2ecf20Sopenharmony_ci			pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
3078c2ecf20Sopenharmony_ci		of_genpd_add_provider_simple(np, &pd->genpd);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		rmobile_add_pm_domains(base, np, &pd->genpd);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int __init rmobile_init_pm_domains(void)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct device_node *np, *pmd;
3178c2ecf20Sopenharmony_ci	bool scanned = false;
3188c2ecf20Sopenharmony_ci	void __iomem *base;
3198c2ecf20Sopenharmony_ci	int ret = 0;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
3228c2ecf20Sopenharmony_ci		base = of_iomap(np, 0);
3238c2ecf20Sopenharmony_ci		if (!base) {
3248c2ecf20Sopenharmony_ci			pr_warn("%pOF cannot map reg 0\n", np);
3258c2ecf20Sopenharmony_ci			continue;
3268c2ecf20Sopenharmony_ci		}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		pmd = of_get_child_by_name(np, "pm-domains");
3298c2ecf20Sopenharmony_ci		if (!pmd) {
3308c2ecf20Sopenharmony_ci			iounmap(base);
3318c2ecf20Sopenharmony_ci			pr_warn("%pOF lacks pm-domains node\n", np);
3328c2ecf20Sopenharmony_ci			continue;
3338c2ecf20Sopenharmony_ci		}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci		if (!scanned) {
3368c2ecf20Sopenharmony_ci			/* Find PM domains containing special blocks */
3378c2ecf20Sopenharmony_ci			get_special_pds();
3388c2ecf20Sopenharmony_ci			scanned = true;
3398c2ecf20Sopenharmony_ci		}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		ret = rmobile_add_pm_domains(base, pmd, NULL);
3428c2ecf20Sopenharmony_ci		of_node_put(pmd);
3438c2ecf20Sopenharmony_ci		if (ret) {
3448c2ecf20Sopenharmony_ci			of_node_put(np);
3458c2ecf20Sopenharmony_ci			break;
3468c2ecf20Sopenharmony_ci		}
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	put_special_pds();
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return ret;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cicore_initcall(rmobile_init_pm_domains);
355