root/drivers/soc/samsung/pm_domains.c

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

DEFINITIONS

This source file includes following definitions.
  1. exynos_pd_power
  2. exynos_pd_power_on
  3. exynos_pd_power_off
  4. exynos_get_domain_name
  5. exynos4_pm_init_power_domain

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Exynos Generic power domain support.
   4 //
   5 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
   6 //              http://www.samsung.com
   7 //
   8 // Implementation of Exynos specific power domain control which is used in
   9 // conjunction with runtime-pm. Support for both device-tree and non-device-tree
  10 // based power domain support is included.
  11 
  12 #include <linux/io.h>
  13 #include <linux/err.h>
  14 #include <linux/slab.h>
  15 #include <linux/pm_domain.h>
  16 #include <linux/delay.h>
  17 #include <linux/of_address.h>
  18 #include <linux/of_platform.h>
  19 #include <linux/sched.h>
  20 
  21 struct exynos_pm_domain_config {
  22         /* Value for LOCAL_PWR_CFG and STATUS fields for each domain */
  23         u32 local_pwr_cfg;
  24 };
  25 
  26 /*
  27  * Exynos specific wrapper around the generic power domain
  28  */
  29 struct exynos_pm_domain {
  30         void __iomem *base;
  31         bool is_off;
  32         struct generic_pm_domain pd;
  33         u32 local_pwr_cfg;
  34 };
  35 
  36 static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
  37 {
  38         struct exynos_pm_domain *pd;
  39         void __iomem *base;
  40         u32 timeout, pwr;
  41         char *op;
  42 
  43         pd = container_of(domain, struct exynos_pm_domain, pd);
  44         base = pd->base;
  45 
  46         pwr = power_on ? pd->local_pwr_cfg : 0;
  47         writel_relaxed(pwr, base);
  48 
  49         /* Wait max 1ms */
  50         timeout = 10;
  51 
  52         while ((readl_relaxed(base + 0x4) & pd->local_pwr_cfg) != pwr) {
  53                 if (!timeout) {
  54                         op = (power_on) ? "enable" : "disable";
  55                         pr_err("Power domain %s %s failed\n", domain->name, op);
  56                         return -ETIMEDOUT;
  57                 }
  58                 timeout--;
  59                 cpu_relax();
  60                 usleep_range(80, 100);
  61         }
  62 
  63         return 0;
  64 }
  65 
  66 static int exynos_pd_power_on(struct generic_pm_domain *domain)
  67 {
  68         return exynos_pd_power(domain, true);
  69 }
  70 
  71 static int exynos_pd_power_off(struct generic_pm_domain *domain)
  72 {
  73         return exynos_pd_power(domain, false);
  74 }
  75 
  76 static const struct exynos_pm_domain_config exynos4210_cfg __initconst = {
  77         .local_pwr_cfg          = 0x7,
  78 };
  79 
  80 static const struct exynos_pm_domain_config exynos5433_cfg __initconst = {
  81         .local_pwr_cfg          = 0xf,
  82 };
  83 
  84 static const struct of_device_id exynos_pm_domain_of_match[] __initconst = {
  85         {
  86                 .compatible = "samsung,exynos4210-pd",
  87                 .data = &exynos4210_cfg,
  88         }, {
  89                 .compatible = "samsung,exynos5433-pd",
  90                 .data = &exynos5433_cfg,
  91         },
  92         { },
  93 };
  94 
  95 static __init const char *exynos_get_domain_name(struct device_node *node)
  96 {
  97         const char *name;
  98 
  99         if (of_property_read_string(node, "label", &name) < 0)
 100                 name = kbasename(node->full_name);
 101         return kstrdup_const(name, GFP_KERNEL);
 102 }
 103 
 104 static __init int exynos4_pm_init_power_domain(void)
 105 {
 106         struct device_node *np;
 107         const struct of_device_id *match;
 108 
 109         for_each_matching_node_and_match(np, exynos_pm_domain_of_match, &match) {
 110                 const struct exynos_pm_domain_config *pm_domain_cfg;
 111                 struct exynos_pm_domain *pd;
 112                 int on;
 113 
 114                 pm_domain_cfg = match->data;
 115 
 116                 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
 117                 if (!pd) {
 118                         of_node_put(np);
 119                         return -ENOMEM;
 120                 }
 121                 pd->pd.name = exynos_get_domain_name(np);
 122                 if (!pd->pd.name) {
 123                         kfree(pd);
 124                         of_node_put(np);
 125                         return -ENOMEM;
 126                 }
 127 
 128                 pd->base = of_iomap(np, 0);
 129                 if (!pd->base) {
 130                         pr_warn("%s: failed to map memory\n", __func__);
 131                         kfree_const(pd->pd.name);
 132                         kfree(pd);
 133                         continue;
 134                 }
 135 
 136                 pd->pd.power_off = exynos_pd_power_off;
 137                 pd->pd.power_on = exynos_pd_power_on;
 138                 pd->local_pwr_cfg = pm_domain_cfg->local_pwr_cfg;
 139 
 140                 on = readl_relaxed(pd->base + 0x4) & pd->local_pwr_cfg;
 141 
 142                 pm_genpd_init(&pd->pd, NULL, !on);
 143                 of_genpd_add_provider_simple(np, &pd->pd);
 144         }
 145 
 146         /* Assign the child power domains to their parents */
 147         for_each_matching_node(np, exynos_pm_domain_of_match) {
 148                 struct of_phandle_args child, parent;
 149 
 150                 child.np = np;
 151                 child.args_count = 0;
 152 
 153                 if (of_parse_phandle_with_args(np, "power-domains",
 154                                                "#power-domain-cells", 0,
 155                                                &parent) != 0)
 156                         continue;
 157 
 158                 if (of_genpd_add_subdomain(&parent, &child))
 159                         pr_warn("%pOF failed to add subdomain: %pOF\n",
 160                                 parent.np, child.np);
 161                 else
 162                         pr_info("%pOF has as child subdomain: %pOF.\n",
 163                                 parent.np, child.np);
 164         }
 165 
 166         return 0;
 167 }
 168 core_initcall(exynos4_pm_init_power_domain);

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