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