root/drivers/soc/renesas/rmobile-sysc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_rmobile_pd
  2. rmobile_pd_power_down
  3. __rmobile_pd_power_up
  4. rmobile_pd_power_up
  5. rmobile_init_pm_domain
  6. rmobile_pd_suspend_console
  7. add_special_pd
  8. get_special_pds
  9. put_special_pds
  10. rmobile_setup_pm_domain
  11. rmobile_add_pm_domains
  12. rmobile_init_pm_domains

   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
  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 
  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 
  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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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);

/* [<][>][^][v][top][bottom][index][help] */