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