1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * rmobile power management support
4  *
5  * Copyright (C) 2012  Renesas Solutions Corp.
6  * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7  * Copyright (C) 2014  Glider bvba
8  *
9  * based on pm-sh7372.c
10  *  Copyright (C) 2011 Magnus Damm
11  */
12 #include <linux/clk/renesas.h>
13 #include <linux/console.h>
14 #include <linux/delay.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/of_platform.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm.h>
20 #include <linux/pm_clock.h>
21 #include <linux/pm_domain.h>
22 #include <linux/slab.h>
23 
24 #include <asm/io.h>
25 
26 /* SYSC */
27 #define SPDCR		0x08	/* SYS Power Down Control Register */
28 #define SWUCR		0x14	/* SYS Wakeup Control Register */
29 #define PSTR		0x80	/* Power Status Register */
30 
31 #define PSTR_RETRIES	100
32 #define PSTR_DELAY_US	10
33 
34 struct rmobile_pm_domain {
35 	struct generic_pm_domain genpd;
36 	struct dev_power_governor *gov;
37 	int (*suspend)(void);
38 	void __iomem *base;
39 	unsigned int bit_shift;
40 };
41 
42 static inline
to_rmobile_pd(struct generic_pm_domain * d)43 struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
44 {
45 	return container_of(d, struct rmobile_pm_domain, genpd);
46 }
47 
rmobile_pd_power_down(struct generic_pm_domain * genpd)48 static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
49 {
50 	struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
51 	unsigned int mask = BIT(rmobile_pd->bit_shift);
52 
53 	if (rmobile_pd->suspend) {
54 		int ret = rmobile_pd->suspend();
55 
56 		if (ret)
57 			return ret;
58 	}
59 
60 	if (__raw_readl(rmobile_pd->base + PSTR) & mask) {
61 		unsigned int retry_count;
62 		__raw_writel(mask, rmobile_pd->base + SPDCR);
63 
64 		for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
65 			if (!(__raw_readl(rmobile_pd->base + SPDCR) & mask))
66 				break;
67 			cpu_relax();
68 		}
69 	}
70 
71 	pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask,
72 		 __raw_readl(rmobile_pd->base + PSTR));
73 
74 	return 0;
75 }
76 
__rmobile_pd_power_up(struct rmobile_pm_domain * rmobile_pd)77 static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd)
78 {
79 	unsigned int mask = BIT(rmobile_pd->bit_shift);
80 	unsigned int retry_count;
81 	int ret = 0;
82 
83 	if (__raw_readl(rmobile_pd->base + PSTR) & mask)
84 		return ret;
85 
86 	__raw_writel(mask, rmobile_pd->base + SWUCR);
87 
88 	for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
89 		if (!(__raw_readl(rmobile_pd->base + SWUCR) & mask))
90 			break;
91 		if (retry_count > PSTR_RETRIES)
92 			udelay(PSTR_DELAY_US);
93 		else
94 			cpu_relax();
95 	}
96 	if (!retry_count)
97 		ret = -EIO;
98 
99 	pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
100 		 rmobile_pd->genpd.name, mask,
101 		 __raw_readl(rmobile_pd->base + PSTR));
102 
103 	return ret;
104 }
105 
rmobile_pd_power_up(struct generic_pm_domain * genpd)106 static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
107 {
108 	return __rmobile_pd_power_up(to_rmobile_pd(genpd));
109 }
110 
rmobile_init_pm_domain(struct rmobile_pm_domain * rmobile_pd)111 static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
112 {
113 	struct generic_pm_domain *genpd = &rmobile_pd->genpd;
114 	struct dev_power_governor *gov = rmobile_pd->gov;
115 
116 	genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
117 	genpd->attach_dev = cpg_mstp_attach_dev;
118 	genpd->detach_dev = cpg_mstp_detach_dev;
119 
120 	if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) {
121 		genpd->power_off = rmobile_pd_power_down;
122 		genpd->power_on = rmobile_pd_power_up;
123 		__rmobile_pd_power_up(rmobile_pd);
124 	}
125 
126 	pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
127 }
128 
rmobile_pd_suspend_console(void)129 static int rmobile_pd_suspend_console(void)
130 {
131 	/*
132 	 * Serial consoles make use of SCIF hardware located in this domain,
133 	 * hence keep the power domain on if "no_console_suspend" is set.
134 	 */
135 	return console_suspend_enabled ? 0 : -EBUSY;
136 }
137 
138 enum pd_types {
139 	PD_NORMAL,
140 	PD_CPU,
141 	PD_CONSOLE,
142 	PD_DEBUG,
143 	PD_MEMCTL,
144 };
145 
146 #define MAX_NUM_SPECIAL_PDS	16
147 
148 static struct special_pd {
149 	struct device_node *pd;
150 	enum pd_types type;
151 } special_pds[MAX_NUM_SPECIAL_PDS] __initdata;
152 
153 static unsigned int num_special_pds __initdata;
154 
155 static const struct of_device_id special_ids[] __initconst = {
156 	{ .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG },
157 	{ .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, },
158 	{ .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, },
159 	{ .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, },
160 	{ /* sentinel */ },
161 };
162 
add_special_pd(struct device_node * np,enum pd_types type)163 static void __init add_special_pd(struct device_node *np, enum pd_types type)
164 {
165 	unsigned int i;
166 	struct device_node *pd;
167 
168 	pd = of_parse_phandle(np, "power-domains", 0);
169 	if (!pd)
170 		return;
171 
172 	for (i = 0; i < num_special_pds; i++)
173 		if (pd == special_pds[i].pd && type == special_pds[i].type) {
174 			of_node_put(pd);
175 			return;
176 		}
177 
178 	if (num_special_pds == ARRAY_SIZE(special_pds)) {
179 		pr_warn("Too many special PM domains\n");
180 		of_node_put(pd);
181 		return;
182 	}
183 
184 	pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np);
185 
186 	special_pds[num_special_pds].pd = pd;
187 	special_pds[num_special_pds].type = type;
188 	num_special_pds++;
189 }
190 
get_special_pds(void)191 static void __init get_special_pds(void)
192 {
193 	struct device_node *np;
194 	const struct of_device_id *id;
195 
196 	/* PM domains containing CPUs */
197 	for_each_of_cpu_node(np)
198 		add_special_pd(np, PD_CPU);
199 
200 	/* PM domain containing console */
201 	if (of_stdout)
202 		add_special_pd(of_stdout, PD_CONSOLE);
203 
204 	/* PM domains containing other special devices */
205 	for_each_matching_node_and_match(np, special_ids, &id)
206 		add_special_pd(np, (enum pd_types)id->data);
207 }
208 
put_special_pds(void)209 static void __init put_special_pds(void)
210 {
211 	unsigned int i;
212 
213 	for (i = 0; i < num_special_pds; i++)
214 		of_node_put(special_pds[i].pd);
215 }
216 
pd_type(const struct device_node * pd)217 static enum pd_types __init pd_type(const struct device_node *pd)
218 {
219 	unsigned int i;
220 
221 	for (i = 0; i < num_special_pds; i++)
222 		if (pd == special_pds[i].pd)
223 			return special_pds[i].type;
224 
225 	return PD_NORMAL;
226 }
227 
rmobile_setup_pm_domain(struct device_node * np,struct rmobile_pm_domain * pd)228 static void __init rmobile_setup_pm_domain(struct device_node *np,
229 					   struct rmobile_pm_domain *pd)
230 {
231 	const char *name = pd->genpd.name;
232 
233 	switch (pd_type(np)) {
234 	case PD_CPU:
235 		/*
236 		 * This domain contains the CPU core and therefore it should
237 		 * only be turned off if the CPU is not in use.
238 		 */
239 		pr_debug("PM domain %s contains CPU\n", name);
240 		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
241 		break;
242 
243 	case PD_CONSOLE:
244 		pr_debug("PM domain %s contains serial console\n", name);
245 		pd->gov = &pm_domain_always_on_gov;
246 		pd->suspend = rmobile_pd_suspend_console;
247 		break;
248 
249 	case PD_DEBUG:
250 		/*
251 		 * This domain contains the Coresight-ETM hardware block and
252 		 * therefore it should only be turned off if the debug module
253 		 * is not in use.
254 		 */
255 		pr_debug("PM domain %s contains Coresight-ETM\n", name);
256 		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
257 		break;
258 
259 	case PD_MEMCTL:
260 		/*
261 		 * This domain contains a memory-controller and therefore it
262 		 * should only be turned off if memory is not in use.
263 		 */
264 		pr_debug("PM domain %s contains MEMCTL\n", name);
265 		pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
266 		break;
267 
268 	case PD_NORMAL:
269 		if (pd->bit_shift == ~0) {
270 			/* Top-level always-on domain */
271 			pr_debug("PM domain %s is always-on domain\n", name);
272 			pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
273 		}
274 		break;
275 	}
276 
277 	rmobile_init_pm_domain(pd);
278 }
279 
rmobile_add_pm_domains(void __iomem * base,struct device_node * parent,struct generic_pm_domain * genpd_parent)280 static int __init rmobile_add_pm_domains(void __iomem *base,
281 					 struct device_node *parent,
282 					 struct generic_pm_domain *genpd_parent)
283 {
284 	struct device_node *np;
285 
286 	for_each_child_of_node(parent, np) {
287 		struct rmobile_pm_domain *pd;
288 		u32 idx = ~0;
289 
290 		if (of_property_read_u32(np, "reg", &idx)) {
291 			/* always-on domain */
292 		}
293 
294 		pd = kzalloc(sizeof(*pd), GFP_KERNEL);
295 		if (!pd) {
296 			of_node_put(np);
297 			return -ENOMEM;
298 		}
299 
300 		pd->genpd.name = np->name;
301 		pd->base = base;
302 		pd->bit_shift = idx;
303 
304 		rmobile_setup_pm_domain(np, pd);
305 		if (genpd_parent)
306 			pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
307 		of_genpd_add_provider_simple(np, &pd->genpd);
308 
309 		rmobile_add_pm_domains(base, np, &pd->genpd);
310 	}
311 	return 0;
312 }
313 
rmobile_init_pm_domains(void)314 static int __init rmobile_init_pm_domains(void)
315 {
316 	struct device_node *np, *pmd;
317 	bool scanned = false;
318 	void __iomem *base;
319 	int ret = 0;
320 
321 	for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
322 		base = of_iomap(np, 0);
323 		if (!base) {
324 			pr_warn("%pOF cannot map reg 0\n", np);
325 			continue;
326 		}
327 
328 		pmd = of_get_child_by_name(np, "pm-domains");
329 		if (!pmd) {
330 			pr_warn("%pOF lacks pm-domains node\n", np);
331 			continue;
332 		}
333 
334 		if (!scanned) {
335 			/* Find PM domains containing special blocks */
336 			get_special_pds();
337 			scanned = true;
338 		}
339 
340 		ret = rmobile_add_pm_domains(base, pmd, NULL);
341 		of_node_put(pmd);
342 		if (ret) {
343 			of_node_put(np);
344 			break;
345 		}
346 	}
347 
348 	put_special_pds();
349 
350 	return ret;
351 }
352 
353 core_initcall(rmobile_init_pm_domains);
354