Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * rmobile power management support
0004  *
0005  * Copyright (C) 2012  Renesas Solutions Corp.
0006  * Copyright (C) 2012  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
0007  * Copyright (C) 2014  Glider bvba
0008  *
0009  * based on pm-sh7372.c
0010  *  Copyright (C) 2011 Magnus Damm
0011  */
0012 #include <linux/clk/renesas.h>
0013 #include <linux/console.h>
0014 #include <linux/delay.h>
0015 #include <linux/of.h>
0016 #include <linux/of_address.h>
0017 #include <linux/pm.h>
0018 #include <linux/pm_clock.h>
0019 #include <linux/pm_domain.h>
0020 #include <linux/slab.h>
0021 
0022 #include <asm/io.h>
0023 
0024 /* SYSC */
0025 #define SPDCR       0x08    /* SYS Power Down Control Register */
0026 #define SWUCR       0x14    /* SYS Wakeup Control Register */
0027 #define PSTR        0x80    /* Power Status Register */
0028 
0029 #define PSTR_RETRIES    100
0030 #define PSTR_DELAY_US   10
0031 
0032 struct rmobile_pm_domain {
0033     struct generic_pm_domain genpd;
0034     struct dev_power_governor *gov;
0035     int (*suspend)(void);
0036     void __iomem *base;
0037     unsigned int bit_shift;
0038 };
0039 
0040 static inline
0041 struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
0042 {
0043     return container_of(d, struct rmobile_pm_domain, genpd);
0044 }
0045 
0046 static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
0047 {
0048     struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
0049     unsigned int mask = BIT(rmobile_pd->bit_shift);
0050 
0051     if (rmobile_pd->suspend) {
0052         int ret = rmobile_pd->suspend();
0053 
0054         if (ret)
0055             return ret;
0056     }
0057 
0058     if (readl(rmobile_pd->base + PSTR) & mask) {
0059         unsigned int retry_count;
0060         writel(mask, rmobile_pd->base + SPDCR);
0061 
0062         for (retry_count = PSTR_RETRIES; retry_count; retry_count--) {
0063             if (!(readl(rmobile_pd->base + SPDCR) & mask))
0064                 break;
0065             cpu_relax();
0066         }
0067     }
0068 
0069     pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask,
0070          readl(rmobile_pd->base + PSTR));
0071 
0072     return 0;
0073 }
0074 
0075 static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd)
0076 {
0077     unsigned int mask = BIT(rmobile_pd->bit_shift);
0078     unsigned int retry_count;
0079     int ret = 0;
0080 
0081     if (readl(rmobile_pd->base + PSTR) & mask)
0082         return ret;
0083 
0084     writel(mask, rmobile_pd->base + SWUCR);
0085 
0086     for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) {
0087         if (!(readl(rmobile_pd->base + SWUCR) & mask))
0088             break;
0089         if (retry_count > PSTR_RETRIES)
0090             udelay(PSTR_DELAY_US);
0091         else
0092             cpu_relax();
0093     }
0094     if (!retry_count)
0095         ret = -EIO;
0096 
0097     pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
0098          rmobile_pd->genpd.name, mask,
0099          readl(rmobile_pd->base + PSTR));
0100 
0101     return ret;
0102 }
0103 
0104 static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
0105 {
0106     return __rmobile_pd_power_up(to_rmobile_pd(genpd));
0107 }
0108 
0109 static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
0110 {
0111     struct generic_pm_domain *genpd = &rmobile_pd->genpd;
0112     struct dev_power_governor *gov = rmobile_pd->gov;
0113 
0114     genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
0115     genpd->attach_dev = cpg_mstp_attach_dev;
0116     genpd->detach_dev = cpg_mstp_detach_dev;
0117 
0118     if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) {
0119         genpd->power_off = rmobile_pd_power_down;
0120         genpd->power_on = rmobile_pd_power_up;
0121         __rmobile_pd_power_up(rmobile_pd);
0122     }
0123 
0124     pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
0125 }
0126 
0127 static int rmobile_pd_suspend_console(void)
0128 {
0129     /*
0130      * Serial consoles make use of SCIF hardware located in this domain,
0131      * hence keep the power domain on if "no_console_suspend" is set.
0132      */
0133     return console_suspend_enabled ? 0 : -EBUSY;
0134 }
0135 
0136 enum pd_types {
0137     PD_NORMAL,
0138     PD_CPU,
0139     PD_CONSOLE,
0140     PD_DEBUG,
0141     PD_MEMCTL,
0142 };
0143 
0144 #define MAX_NUM_SPECIAL_PDS 16
0145 
0146 static struct special_pd {
0147     struct device_node *pd;
0148     enum pd_types type;
0149 } special_pds[MAX_NUM_SPECIAL_PDS] __initdata;
0150 
0151 static unsigned int num_special_pds __initdata;
0152 
0153 static const struct of_device_id special_ids[] __initconst = {
0154     { .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG },
0155     { .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, },
0156     { .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, },
0157     { .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, },
0158     { /* sentinel */ },
0159 };
0160 
0161 static void __init add_special_pd(struct device_node *np, enum pd_types type)
0162 {
0163     unsigned int i;
0164     struct device_node *pd;
0165 
0166     pd = of_parse_phandle(np, "power-domains", 0);
0167     if (!pd)
0168         return;
0169 
0170     for (i = 0; i < num_special_pds; i++)
0171         if (pd == special_pds[i].pd && type == special_pds[i].type) {
0172             of_node_put(pd);
0173             return;
0174         }
0175 
0176     if (num_special_pds == ARRAY_SIZE(special_pds)) {
0177         pr_warn("Too many special PM domains\n");
0178         of_node_put(pd);
0179         return;
0180     }
0181 
0182     pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np);
0183 
0184     special_pds[num_special_pds].pd = pd;
0185     special_pds[num_special_pds].type = type;
0186     num_special_pds++;
0187 }
0188 
0189 static void __init get_special_pds(void)
0190 {
0191     struct device_node *np;
0192     const struct of_device_id *id;
0193 
0194     /* PM domains containing CPUs */
0195     for_each_of_cpu_node(np)
0196         add_special_pd(np, PD_CPU);
0197 
0198     /* PM domain containing console */
0199     if (of_stdout)
0200         add_special_pd(of_stdout, PD_CONSOLE);
0201 
0202     /* PM domains containing other special devices */
0203     for_each_matching_node_and_match(np, special_ids, &id)
0204         add_special_pd(np, (enum pd_types)id->data);
0205 }
0206 
0207 static void __init put_special_pds(void)
0208 {
0209     unsigned int i;
0210 
0211     for (i = 0; i < num_special_pds; i++)
0212         of_node_put(special_pds[i].pd);
0213 }
0214 
0215 static enum pd_types __init pd_type(const struct device_node *pd)
0216 {
0217     unsigned int i;
0218 
0219     for (i = 0; i < num_special_pds; i++)
0220         if (pd == special_pds[i].pd)
0221             return special_pds[i].type;
0222 
0223     return PD_NORMAL;
0224 }
0225 
0226 static void __init rmobile_setup_pm_domain(struct device_node *np,
0227                        struct rmobile_pm_domain *pd)
0228 {
0229     const char *name = pd->genpd.name;
0230 
0231     switch (pd_type(np)) {
0232     case PD_CPU:
0233         /*
0234          * This domain contains the CPU core and therefore it should
0235          * only be turned off if the CPU is not in use.
0236          */
0237         pr_debug("PM domain %s contains CPU\n", name);
0238         pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
0239         break;
0240 
0241     case PD_CONSOLE:
0242         pr_debug("PM domain %s contains serial console\n", name);
0243         pd->gov = &pm_domain_always_on_gov;
0244         pd->suspend = rmobile_pd_suspend_console;
0245         break;
0246 
0247     case PD_DEBUG:
0248         /*
0249          * This domain contains the Coresight-ETM hardware block and
0250          * therefore it should only be turned off if the debug module
0251          * is not in use.
0252          */
0253         pr_debug("PM domain %s contains Coresight-ETM\n", name);
0254         pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
0255         break;
0256 
0257     case PD_MEMCTL:
0258         /*
0259          * This domain contains a memory-controller and therefore it
0260          * should only be turned off if memory is not in use.
0261          */
0262         pr_debug("PM domain %s contains MEMCTL\n", name);
0263         pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
0264         break;
0265 
0266     case PD_NORMAL:
0267         if (pd->bit_shift == ~0) {
0268             /* Top-level always-on domain */
0269             pr_debug("PM domain %s is always-on domain\n", name);
0270             pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
0271         }
0272         break;
0273     }
0274 
0275     rmobile_init_pm_domain(pd);
0276 }
0277 
0278 static int __init rmobile_add_pm_domains(void __iomem *base,
0279                      struct device_node *parent,
0280                      struct generic_pm_domain *genpd_parent)
0281 {
0282     struct device_node *np;
0283 
0284     for_each_child_of_node(parent, np) {
0285         struct rmobile_pm_domain *pd;
0286         u32 idx = ~0;
0287 
0288         if (of_property_read_u32(np, "reg", &idx)) {
0289             /* always-on domain */
0290         }
0291 
0292         pd = kzalloc(sizeof(*pd), GFP_KERNEL);
0293         if (!pd) {
0294             of_node_put(np);
0295             return -ENOMEM;
0296         }
0297 
0298         pd->genpd.name = np->name;
0299         pd->base = base;
0300         pd->bit_shift = idx;
0301 
0302         rmobile_setup_pm_domain(np, pd);
0303         if (genpd_parent)
0304             pm_genpd_add_subdomain(genpd_parent, &pd->genpd);
0305         of_genpd_add_provider_simple(np, &pd->genpd);
0306 
0307         rmobile_add_pm_domains(base, np, &pd->genpd);
0308     }
0309     return 0;
0310 }
0311 
0312 static int __init rmobile_init_pm_domains(void)
0313 {
0314     struct device_node *np, *pmd;
0315     bool scanned = false;
0316     void __iomem *base;
0317     int ret = 0;
0318 
0319     for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") {
0320         base = of_iomap(np, 0);
0321         if (!base) {
0322             pr_warn("%pOF cannot map reg 0\n", np);
0323             continue;
0324         }
0325 
0326         pmd = of_get_child_by_name(np, "pm-domains");
0327         if (!pmd) {
0328             iounmap(base);
0329             pr_warn("%pOF lacks pm-domains node\n", np);
0330             continue;
0331         }
0332 
0333         if (!scanned) {
0334             /* Find PM domains containing special blocks */
0335             get_special_pds();
0336             scanned = true;
0337         }
0338 
0339         ret = rmobile_add_pm_domains(base, pmd, NULL);
0340         of_node_put(pmd);
0341         if (ret) {
0342             of_node_put(np);
0343             break;
0344         }
0345 
0346         fwnode_dev_initialized(&np->fwnode, true);
0347     }
0348 
0349     put_special_pds();
0350 
0351     return ret;
0352 }
0353 
0354 core_initcall(rmobile_init_pm_domains);