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->attach_dev = cpg_mstp_attach_dev; 105 genpd->detach_dev = cpg_mstp_detach_dev; 106 107 if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) { 108 genpd->power_off = rmobile_pd_power_down; 109 genpd->power_on = rmobile_pd_power_up; 110 __rmobile_pd_power_up(rmobile_pd); 111 } 112 113 pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); 114 } 115 116 static int rmobile_pd_suspend_console(void) 117 { 118 /* 119 * Serial consoles make use of SCIF hardware located in this domain, 120 * hence keep the power domain on if "no_console_suspend" is set. 121 */ 122 return console_suspend_enabled ? 0 : -EBUSY; 123 } 124 125 enum pd_types { 126 PD_NORMAL, 127 PD_CPU, 128 PD_CONSOLE, 129 PD_DEBUG, 130 PD_MEMCTL, 131 }; 132 133 #define MAX_NUM_SPECIAL_PDS 16 134 135 static struct special_pd { 136 struct device_node *pd; 137 enum pd_types type; 138 } special_pds[MAX_NUM_SPECIAL_PDS] __initdata; 139 140 static unsigned int num_special_pds __initdata; 141 142 static const struct of_device_id special_ids[] __initconst = { 143 { .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG }, 144 { .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, }, 145 { .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, }, 146 { .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, }, 147 { /* sentinel */ }, 148 }; 149 150 static void __init add_special_pd(struct device_node *np, enum pd_types type) 151 { 152 unsigned int i; 153 struct device_node *pd; 154 155 pd = of_parse_phandle(np, "power-domains", 0); 156 if (!pd) 157 return; 158 159 for (i = 0; i < num_special_pds; i++) 160 if (pd == special_pds[i].pd && type == special_pds[i].type) { 161 of_node_put(pd); 162 return; 163 } 164 165 if (num_special_pds == ARRAY_SIZE(special_pds)) { 166 pr_warn("Too many special PM domains\n"); 167 of_node_put(pd); 168 return; 169 } 170 171 pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np); 172 173 special_pds[num_special_pds].pd = pd; 174 special_pds[num_special_pds].type = type; 175 num_special_pds++; 176 } 177 178 static void __init get_special_pds(void) 179 { 180 struct device_node *np; 181 const struct of_device_id *id; 182 183 /* PM domains containing CPUs */ 184 for_each_of_cpu_node(np) 185 add_special_pd(np, PD_CPU); 186 187 /* PM domain containing console */ 188 if (of_stdout) 189 add_special_pd(of_stdout, PD_CONSOLE); 190 191 /* PM domains containing other special devices */ 192 for_each_matching_node_and_match(np, special_ids, &id) 193 add_special_pd(np, (uintptr_t)id->data); 194 } 195 196 static void __init put_special_pds(void) 197 { 198 unsigned int i; 199 200 for (i = 0; i < num_special_pds; i++) 201 of_node_put(special_pds[i].pd); 202 } 203 204 static enum pd_types __init pd_type(const struct device_node *pd) 205 { 206 unsigned int i; 207 208 for (i = 0; i < num_special_pds; i++) 209 if (pd == special_pds[i].pd) 210 return special_pds[i].type; 211 212 return PD_NORMAL; 213 } 214 215 static void __init rmobile_setup_pm_domain(struct device_node *np, 216 struct rmobile_pm_domain *pd) 217 { 218 const char *name = pd->genpd.name; 219 220 switch (pd_type(np)) { 221 case PD_CPU: 222 /* 223 * This domain contains the CPU core and therefore it should 224 * only be turned off if the CPU is not in use. 225 */ 226 pr_debug("PM domain %s contains CPU\n", name); 227 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; 228 break; 229 230 case PD_CONSOLE: 231 pr_debug("PM domain %s contains serial console\n", name); 232 pd->gov = &pm_domain_always_on_gov; 233 pd->suspend = rmobile_pd_suspend_console; 234 break; 235 236 case PD_DEBUG: 237 /* 238 * This domain contains the Coresight-ETM hardware block and 239 * therefore it should only be turned off if the debug module 240 * is not in use. 241 */ 242 pr_debug("PM domain %s contains Coresight-ETM\n", name); 243 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; 244 break; 245 246 case PD_MEMCTL: 247 /* 248 * This domain contains a memory-controller and therefore it 249 * should only be turned off if memory is not in use. 250 */ 251 pr_debug("PM domain %s contains MEMCTL\n", name); 252 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; 253 break; 254 255 case PD_NORMAL: 256 if (pd->bit_shift == ~0) { 257 /* Top-level always-on domain */ 258 pr_debug("PM domain %s is always-on domain\n", name); 259 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; 260 } 261 break; 262 } 263 264 rmobile_init_pm_domain(pd); 265 } 266 267 static int __init rmobile_add_pm_domains(void __iomem *base, 268 struct device_node *parent, 269 struct generic_pm_domain *genpd_parent) 270 { 271 struct device_node *np; 272 273 for_each_child_of_node(parent, np) { 274 struct rmobile_pm_domain *pd; 275 u32 idx = ~0; 276 277 if (of_property_read_u32(np, "reg", &idx)) { 278 /* always-on domain */ 279 } 280 281 pd = kzalloc(sizeof(*pd), GFP_KERNEL); 282 if (!pd) { 283 of_node_put(np); 284 return -ENOMEM; 285 } 286 287 pd->genpd.name = np->name; 288 pd->base = base; 289 pd->bit_shift = idx; 290 291 rmobile_setup_pm_domain(np, pd); 292 if (genpd_parent) 293 pm_genpd_add_subdomain(genpd_parent, &pd->genpd); 294 of_genpd_add_provider_simple(np, &pd->genpd); 295 296 rmobile_add_pm_domains(base, np, &pd->genpd); 297 } 298 return 0; 299 } 300 301 static int __init rmobile_init_pm_domains(void) 302 { 303 struct device_node *np, *pmd; 304 bool scanned = false; 305 void __iomem *base; 306 int ret = 0; 307 308 for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") { 309 base = of_iomap(np, 0); 310 if (!base) { 311 pr_warn("%pOF cannot map reg 0\n", np); 312 continue; 313 } 314 315 pmd = of_get_child_by_name(np, "pm-domains"); 316 if (!pmd) { 317 iounmap(base); 318 pr_warn("%pOF lacks pm-domains node\n", np); 319 continue; 320 } 321 322 if (!scanned) { 323 /* Find PM domains containing special blocks */ 324 get_special_pds(); 325 scanned = true; 326 } 327 328 ret = rmobile_add_pm_domains(base, pmd, NULL); 329 of_node_put(pmd); 330 if (ret) { 331 of_node_put(np); 332 break; 333 } 334 335 fwnode_dev_initialized(of_fwnode_handle(np), true); 336 } 337 338 put_special_pds(); 339 340 return ret; 341 } 342 343 core_initcall(rmobile_init_pm_domains); 344