root/drivers/soc/tegra/powergate-bpmp.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_tegra_powergate
  2. tegra_bpmp_powergate_set_state
  3. tegra_bpmp_powergate_get_state
  4. tegra_bpmp_powergate_get_max_id
  5. tegra_bpmp_powergate_get_name
  6. tegra_bpmp_powergate_is_powered
  7. tegra_powergate_power_on
  8. tegra_powergate_power_off
  9. tegra_powergate_add
  10. tegra_powergate_remove
  11. tegra_bpmp_probe_powergates
  12. tegra_bpmp_add_powergates
  13. tegra_bpmp_remove_powergates
  14. tegra_powergate_xlate
  15. tegra_bpmp_init_powergates

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
   4  */
   5 
   6 #include <linux/of.h>
   7 #include <linux/platform_device.h>
   8 #include <linux/pm_domain.h>
   9 #include <linux/slab.h>
  10 #include <linux/version.h>
  11 
  12 #include <soc/tegra/bpmp.h>
  13 #include <soc/tegra/bpmp-abi.h>
  14 
  15 struct tegra_powergate_info {
  16         unsigned int id;
  17         char *name;
  18 };
  19 
  20 struct tegra_powergate {
  21         struct generic_pm_domain genpd;
  22         struct tegra_bpmp *bpmp;
  23         unsigned int id;
  24 };
  25 
  26 static inline struct tegra_powergate *
  27 to_tegra_powergate(struct generic_pm_domain *genpd)
  28 {
  29         return container_of(genpd, struct tegra_powergate, genpd);
  30 }
  31 
  32 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
  33                                           unsigned int id, u32 state)
  34 {
  35         struct mrq_pg_request request;
  36         struct tegra_bpmp_message msg;
  37         int err;
  38 
  39         memset(&request, 0, sizeof(request));
  40         request.cmd = CMD_PG_SET_STATE;
  41         request.id = id;
  42         request.set_state.state = state;
  43 
  44         memset(&msg, 0, sizeof(msg));
  45         msg.mrq = MRQ_PG;
  46         msg.tx.data = &request;
  47         msg.tx.size = sizeof(request);
  48 
  49         err = tegra_bpmp_transfer(bpmp, &msg);
  50         if (err < 0)
  51                 return err;
  52         else if (msg.rx.ret < 0)
  53                 return -EINVAL;
  54 
  55         return 0;
  56 }
  57 
  58 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
  59                                           unsigned int id)
  60 {
  61         struct mrq_pg_response response;
  62         struct mrq_pg_request request;
  63         struct tegra_bpmp_message msg;
  64         int err;
  65 
  66         memset(&request, 0, sizeof(request));
  67         request.cmd = CMD_PG_GET_STATE;
  68         request.id = id;
  69 
  70         memset(&response, 0, sizeof(response));
  71 
  72         memset(&msg, 0, sizeof(msg));
  73         msg.mrq = MRQ_PG;
  74         msg.tx.data = &request;
  75         msg.tx.size = sizeof(request);
  76         msg.rx.data = &response;
  77         msg.rx.size = sizeof(response);
  78 
  79         err = tegra_bpmp_transfer(bpmp, &msg);
  80         if (err < 0)
  81                 return PG_STATE_OFF;
  82         else if (msg.rx.ret < 0)
  83                 return -EINVAL;
  84 
  85         return response.get_state.state;
  86 }
  87 
  88 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
  89 {
  90         struct mrq_pg_response response;
  91         struct mrq_pg_request request;
  92         struct tegra_bpmp_message msg;
  93         int err;
  94 
  95         memset(&request, 0, sizeof(request));
  96         request.cmd = CMD_PG_GET_MAX_ID;
  97 
  98         memset(&response, 0, sizeof(response));
  99 
 100         memset(&msg, 0, sizeof(msg));
 101         msg.mrq = MRQ_PG;
 102         msg.tx.data = &request;
 103         msg.tx.size = sizeof(request);
 104         msg.rx.data = &response;
 105         msg.rx.size = sizeof(response);
 106 
 107         err = tegra_bpmp_transfer(bpmp, &msg);
 108         if (err < 0)
 109                 return err;
 110         else if (msg.rx.ret < 0)
 111                 return -EINVAL;
 112 
 113         return response.get_max_id.max_id;
 114 }
 115 
 116 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
 117                                            unsigned int id)
 118 {
 119         struct mrq_pg_response response;
 120         struct mrq_pg_request request;
 121         struct tegra_bpmp_message msg;
 122         int err;
 123 
 124         memset(&request, 0, sizeof(request));
 125         request.cmd = CMD_PG_GET_NAME;
 126         request.id = id;
 127 
 128         memset(&response, 0, sizeof(response));
 129 
 130         memset(&msg, 0, sizeof(msg));
 131         msg.mrq = MRQ_PG;
 132         msg.tx.data = &request;
 133         msg.tx.size = sizeof(request);
 134         msg.rx.data = &response;
 135         msg.rx.size = sizeof(response);
 136 
 137         err = tegra_bpmp_transfer(bpmp, &msg);
 138         if (err < 0 || msg.rx.ret < 0)
 139                 return NULL;
 140 
 141         return kstrdup(response.get_name.name, GFP_KERNEL);
 142 }
 143 
 144 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
 145                                                    unsigned int id)
 146 {
 147         return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
 148 }
 149 
 150 static int tegra_powergate_power_on(struct generic_pm_domain *domain)
 151 {
 152         struct tegra_powergate *powergate = to_tegra_powergate(domain);
 153         struct tegra_bpmp *bpmp = powergate->bpmp;
 154 
 155         return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
 156                                               PG_STATE_ON);
 157 }
 158 
 159 static int tegra_powergate_power_off(struct generic_pm_domain *domain)
 160 {
 161         struct tegra_powergate *powergate = to_tegra_powergate(domain);
 162         struct tegra_bpmp *bpmp = powergate->bpmp;
 163 
 164         return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
 165                                               PG_STATE_OFF);
 166 }
 167 
 168 static struct tegra_powergate *
 169 tegra_powergate_add(struct tegra_bpmp *bpmp,
 170                     const struct tegra_powergate_info *info)
 171 {
 172         struct tegra_powergate *powergate;
 173         bool off;
 174         int err;
 175 
 176         off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
 177 
 178         powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
 179         if (!powergate)
 180                 return ERR_PTR(-ENOMEM);
 181 
 182         powergate->id = info->id;
 183         powergate->bpmp = bpmp;
 184 
 185         powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
 186         powergate->genpd.power_on = tegra_powergate_power_on;
 187         powergate->genpd.power_off = tegra_powergate_power_off;
 188 
 189         err = pm_genpd_init(&powergate->genpd, NULL, off);
 190         if (err < 0) {
 191                 kfree(powergate->genpd.name);
 192                 return ERR_PTR(err);
 193         }
 194 
 195         return powergate;
 196 }
 197 
 198 static void tegra_powergate_remove(struct tegra_powergate *powergate)
 199 {
 200         struct generic_pm_domain *genpd = &powergate->genpd;
 201         struct tegra_bpmp *bpmp = powergate->bpmp;
 202         int err;
 203 
 204         err = pm_genpd_remove(genpd);
 205         if (err < 0)
 206                 dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
 207                         genpd->name, err);
 208 
 209         kfree(genpd->name);
 210 }
 211 
 212 static int
 213 tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
 214                             struct tegra_powergate_info **powergatesp)
 215 {
 216         struct tegra_powergate_info *powergates;
 217         unsigned int max_id, id, count = 0;
 218         unsigned int num_holes = 0;
 219         int err;
 220 
 221         err = tegra_bpmp_powergate_get_max_id(bpmp);
 222         if (err < 0)
 223                 return err;
 224 
 225         max_id = err;
 226 
 227         dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
 228 
 229         powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
 230         if (!powergates)
 231                 return -ENOMEM;
 232 
 233         for (id = 0; id <= max_id; id++) {
 234                 struct tegra_powergate_info *info = &powergates[count];
 235 
 236                 info->name = tegra_bpmp_powergate_get_name(bpmp, id);
 237                 if (!info->name || info->name[0] == '\0') {
 238                         num_holes++;
 239                         continue;
 240                 }
 241 
 242                 info->id = id;
 243                 count++;
 244         }
 245 
 246         dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
 247 
 248         *powergatesp = powergates;
 249 
 250         return count;
 251 }
 252 
 253 static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
 254                                      struct tegra_powergate_info *powergates,
 255                                      unsigned int count)
 256 {
 257         struct genpd_onecell_data *genpd = &bpmp->genpd;
 258         struct generic_pm_domain **domains;
 259         struct tegra_powergate *powergate;
 260         unsigned int i;
 261         int err;
 262 
 263         domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
 264         if (!domains)
 265                 return -ENOMEM;
 266 
 267         for (i = 0; i < count; i++) {
 268                 powergate = tegra_powergate_add(bpmp, &powergates[i]);
 269                 if (IS_ERR(powergate)) {
 270                         err = PTR_ERR(powergate);
 271                         goto remove;
 272                 }
 273 
 274                 dev_dbg(bpmp->dev, "added power domain %s\n",
 275                         powergate->genpd.name);
 276                 domains[i] = &powergate->genpd;
 277         }
 278 
 279         genpd->num_domains = count;
 280         genpd->domains = domains;
 281 
 282         return 0;
 283 
 284 remove:
 285         while (i--) {
 286                 powergate = to_tegra_powergate(domains[i]);
 287                 tegra_powergate_remove(powergate);
 288         }
 289 
 290         kfree(genpd->domains);
 291         return err;
 292 }
 293 
 294 static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
 295 {
 296         struct genpd_onecell_data *genpd = &bpmp->genpd;
 297         unsigned int i = genpd->num_domains;
 298         struct tegra_powergate *powergate;
 299 
 300         while (i--) {
 301                 dev_dbg(bpmp->dev, "removing power domain %s\n",
 302                         genpd->domains[i]->name);
 303                 powergate = to_tegra_powergate(genpd->domains[i]);
 304                 tegra_powergate_remove(powergate);
 305         }
 306 }
 307 
 308 static struct generic_pm_domain *
 309 tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
 310 {
 311         struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
 312         struct genpd_onecell_data *genpd = data;
 313         unsigned int i;
 314 
 315         for (i = 0; i < genpd->num_domains; i++) {
 316                 struct tegra_powergate *powergate;
 317 
 318                 powergate = to_tegra_powergate(genpd->domains[i]);
 319                 if (powergate->id == spec->args[0]) {
 320                         domain = &powergate->genpd;
 321                         break;
 322                 }
 323         }
 324 
 325         return domain;
 326 }
 327 
 328 int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
 329 {
 330         struct device_node *np = bpmp->dev->of_node;
 331         struct tegra_powergate_info *powergates;
 332         struct device *dev = bpmp->dev;
 333         unsigned int count, i;
 334         int err;
 335 
 336         err = tegra_bpmp_probe_powergates(bpmp, &powergates);
 337         if (err < 0)
 338                 return err;
 339 
 340         count = err;
 341 
 342         dev_dbg(dev, "%u power domains probed\n", count);
 343 
 344         err = tegra_bpmp_add_powergates(bpmp, powergates, count);
 345         if (err < 0)
 346                 goto free;
 347 
 348         bpmp->genpd.xlate = tegra_powergate_xlate;
 349 
 350         err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
 351         if (err < 0) {
 352                 dev_err(dev, "failed to add power domain provider: %d\n", err);
 353                 tegra_bpmp_remove_powergates(bpmp);
 354         }
 355 
 356 free:
 357         for (i = 0; i < count; i++)
 358                 kfree(powergates[i].name);
 359 
 360         kfree(powergates);
 361         return err;
 362 }

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