root/drivers/soc/rockchip/pm_domains.c

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

DEFINITIONS

This source file includes following definitions.
  1. rockchip_pmu_domain_is_idle
  2. rockchip_pmu_read_ack
  3. rockchip_pmu_set_idle_request
  4. rockchip_pmu_save_qos
  5. rockchip_pmu_restore_qos
  6. rockchip_pmu_domain_is_on
  7. rockchip_do_pmu_set_power_domain
  8. rockchip_pd_power
  9. rockchip_pd_power_on
  10. rockchip_pd_power_off
  11. rockchip_pd_attach_dev
  12. rockchip_pd_detach_dev
  13. rockchip_pm_add_one_domain
  14. rockchip_pm_remove_one_domain
  15. rockchip_pm_domain_cleanup
  16. rockchip_configure_pd_cnt
  17. rockchip_pm_add_subdomain
  18. rockchip_pm_domain_probe
  19. rockchip_pm_domain_drv_register

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Rockchip Generic power domain support.
   4  *
   5  * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
   6  */
   7 
   8 #include <linux/io.h>
   9 #include <linux/iopoll.h>
  10 #include <linux/err.h>
  11 #include <linux/pm_clock.h>
  12 #include <linux/pm_domain.h>
  13 #include <linux/of_address.h>
  14 #include <linux/of_clk.h>
  15 #include <linux/of_platform.h>
  16 #include <linux/clk.h>
  17 #include <linux/regmap.h>
  18 #include <linux/mfd/syscon.h>
  19 #include <dt-bindings/power/px30-power.h>
  20 #include <dt-bindings/power/rk3036-power.h>
  21 #include <dt-bindings/power/rk3066-power.h>
  22 #include <dt-bindings/power/rk3128-power.h>
  23 #include <dt-bindings/power/rk3188-power.h>
  24 #include <dt-bindings/power/rk3228-power.h>
  25 #include <dt-bindings/power/rk3288-power.h>
  26 #include <dt-bindings/power/rk3328-power.h>
  27 #include <dt-bindings/power/rk3366-power.h>
  28 #include <dt-bindings/power/rk3368-power.h>
  29 #include <dt-bindings/power/rk3399-power.h>
  30 
  31 struct rockchip_domain_info {
  32         int pwr_mask;
  33         int status_mask;
  34         int req_mask;
  35         int idle_mask;
  36         int ack_mask;
  37         bool active_wakeup;
  38         int pwr_w_mask;
  39         int req_w_mask;
  40 };
  41 
  42 struct rockchip_pmu_info {
  43         u32 pwr_offset;
  44         u32 status_offset;
  45         u32 req_offset;
  46         u32 idle_offset;
  47         u32 ack_offset;
  48 
  49         u32 core_pwrcnt_offset;
  50         u32 gpu_pwrcnt_offset;
  51 
  52         unsigned int core_power_transition_time;
  53         unsigned int gpu_power_transition_time;
  54 
  55         int num_domains;
  56         const struct rockchip_domain_info *domain_info;
  57 };
  58 
  59 #define MAX_QOS_REGS_NUM        5
  60 #define QOS_PRIORITY            0x08
  61 #define QOS_MODE                0x0c
  62 #define QOS_BANDWIDTH           0x10
  63 #define QOS_SATURATION          0x14
  64 #define QOS_EXTCONTROL          0x18
  65 
  66 struct rockchip_pm_domain {
  67         struct generic_pm_domain genpd;
  68         const struct rockchip_domain_info *info;
  69         struct rockchip_pmu *pmu;
  70         int num_qos;
  71         struct regmap **qos_regmap;
  72         u32 *qos_save_regs[MAX_QOS_REGS_NUM];
  73         int num_clks;
  74         struct clk_bulk_data *clks;
  75 };
  76 
  77 struct rockchip_pmu {
  78         struct device *dev;
  79         struct regmap *regmap;
  80         const struct rockchip_pmu_info *info;
  81         struct mutex mutex; /* mutex lock for pmu */
  82         struct genpd_onecell_data genpd_data;
  83         struct generic_pm_domain *domains[];
  84 };
  85 
  86 #define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
  87 
  88 #define DOMAIN(pwr, status, req, idle, ack, wakeup)     \
  89 {                                                       \
  90         .pwr_mask = (pwr),                              \
  91         .status_mask = (status),                        \
  92         .req_mask = (req),                              \
  93         .idle_mask = (idle),                            \
  94         .ack_mask = (ack),                              \
  95         .active_wakeup = (wakeup),                      \
  96 }
  97 
  98 #define DOMAIN_M(pwr, status, req, idle, ack, wakeup)   \
  99 {                                                       \
 100         .pwr_w_mask = (pwr) << 16,                      \
 101         .pwr_mask = (pwr),                              \
 102         .status_mask = (status),                        \
 103         .req_w_mask = (req) << 16,                      \
 104         .req_mask = (req),                              \
 105         .idle_mask = (idle),                            \
 106         .ack_mask = (ack),                              \
 107         .active_wakeup = wakeup,                        \
 108 }
 109 
 110 #define DOMAIN_RK3036(req, ack, idle, wakeup)           \
 111 {                                                       \
 112         .req_mask = (req),                              \
 113         .req_w_mask = (req) << 16,                      \
 114         .ack_mask = (ack),                              \
 115         .idle_mask = (idle),                            \
 116         .active_wakeup = wakeup,                        \
 117 }
 118 
 119 #define DOMAIN_PX30(pwr, status, req, wakeup)           \
 120         DOMAIN_M(pwr, status, req, (req) << 16, req, wakeup)
 121 
 122 #define DOMAIN_RK3288(pwr, status, req, wakeup)         \
 123         DOMAIN(pwr, status, req, req, (req) << 16, wakeup)
 124 
 125 #define DOMAIN_RK3328(pwr, status, req, wakeup)         \
 126         DOMAIN_M(pwr, pwr, req, (req) << 10, req, wakeup)
 127 
 128 #define DOMAIN_RK3368(pwr, status, req, wakeup)         \
 129         DOMAIN(pwr, status, req, (req) << 16, req, wakeup)
 130 
 131 #define DOMAIN_RK3399(pwr, status, req, wakeup)         \
 132         DOMAIN(pwr, status, req, req, req, wakeup)
 133 
 134 static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
 135 {
 136         struct rockchip_pmu *pmu = pd->pmu;
 137         const struct rockchip_domain_info *pd_info = pd->info;
 138         unsigned int val;
 139 
 140         regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
 141         return (val & pd_info->idle_mask) == pd_info->idle_mask;
 142 }
 143 
 144 static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu)
 145 {
 146         unsigned int val;
 147 
 148         regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
 149         return val;
 150 }
 151 
 152 static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
 153                                          bool idle)
 154 {
 155         const struct rockchip_domain_info *pd_info = pd->info;
 156         struct generic_pm_domain *genpd = &pd->genpd;
 157         struct rockchip_pmu *pmu = pd->pmu;
 158         unsigned int target_ack;
 159         unsigned int val;
 160         bool is_idle;
 161         int ret;
 162 
 163         if (pd_info->req_mask == 0)
 164                 return 0;
 165         else if (pd_info->req_w_mask)
 166                 regmap_write(pmu->regmap, pmu->info->req_offset,
 167                              idle ? (pd_info->req_mask | pd_info->req_w_mask) :
 168                              pd_info->req_w_mask);
 169         else
 170                 regmap_update_bits(pmu->regmap, pmu->info->req_offset,
 171                                    pd_info->req_mask, idle ? -1U : 0);
 172 
 173         dsb(sy);
 174 
 175         /* Wait util idle_ack = 1 */
 176         target_ack = idle ? pd_info->ack_mask : 0;
 177         ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val,
 178                                         (val & pd_info->ack_mask) == target_ack,
 179                                         0, 10000);
 180         if (ret) {
 181                 dev_err(pmu->dev,
 182                         "failed to get ack on domain '%s', val=0x%x\n",
 183                         genpd->name, val);
 184                 return ret;
 185         }
 186 
 187         ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd,
 188                                         is_idle, is_idle == idle, 0, 10000);
 189         if (ret) {
 190                 dev_err(pmu->dev,
 191                         "failed to set idle on domain '%s', val=%d\n",
 192                         genpd->name, is_idle);
 193                 return ret;
 194         }
 195 
 196         return 0;
 197 }
 198 
 199 static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
 200 {
 201         int i;
 202 
 203         for (i = 0; i < pd->num_qos; i++) {
 204                 regmap_read(pd->qos_regmap[i],
 205                             QOS_PRIORITY,
 206                             &pd->qos_save_regs[0][i]);
 207                 regmap_read(pd->qos_regmap[i],
 208                             QOS_MODE,
 209                             &pd->qos_save_regs[1][i]);
 210                 regmap_read(pd->qos_regmap[i],
 211                             QOS_BANDWIDTH,
 212                             &pd->qos_save_regs[2][i]);
 213                 regmap_read(pd->qos_regmap[i],
 214                             QOS_SATURATION,
 215                             &pd->qos_save_regs[3][i]);
 216                 regmap_read(pd->qos_regmap[i],
 217                             QOS_EXTCONTROL,
 218                             &pd->qos_save_regs[4][i]);
 219         }
 220         return 0;
 221 }
 222 
 223 static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
 224 {
 225         int i;
 226 
 227         for (i = 0; i < pd->num_qos; i++) {
 228                 regmap_write(pd->qos_regmap[i],
 229                              QOS_PRIORITY,
 230                              pd->qos_save_regs[0][i]);
 231                 regmap_write(pd->qos_regmap[i],
 232                              QOS_MODE,
 233                              pd->qos_save_regs[1][i]);
 234                 regmap_write(pd->qos_regmap[i],
 235                              QOS_BANDWIDTH,
 236                              pd->qos_save_regs[2][i]);
 237                 regmap_write(pd->qos_regmap[i],
 238                              QOS_SATURATION,
 239                              pd->qos_save_regs[3][i]);
 240                 regmap_write(pd->qos_regmap[i],
 241                              QOS_EXTCONTROL,
 242                              pd->qos_save_regs[4][i]);
 243         }
 244 
 245         return 0;
 246 }
 247 
 248 static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
 249 {
 250         struct rockchip_pmu *pmu = pd->pmu;
 251         unsigned int val;
 252 
 253         /* check idle status for idle-only domains */
 254         if (pd->info->status_mask == 0)
 255                 return !rockchip_pmu_domain_is_idle(pd);
 256 
 257         regmap_read(pmu->regmap, pmu->info->status_offset, &val);
 258 
 259         /* 1'b0: power on, 1'b1: power off */
 260         return !(val & pd->info->status_mask);
 261 }
 262 
 263 static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
 264                                              bool on)
 265 {
 266         struct rockchip_pmu *pmu = pd->pmu;
 267         struct generic_pm_domain *genpd = &pd->genpd;
 268         bool is_on;
 269 
 270         if (pd->info->pwr_mask == 0)
 271                 return;
 272         else if (pd->info->pwr_w_mask)
 273                 regmap_write(pmu->regmap, pmu->info->pwr_offset,
 274                              on ? pd->info->pwr_w_mask :
 275                              (pd->info->pwr_mask | pd->info->pwr_w_mask));
 276         else
 277                 regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
 278                                    pd->info->pwr_mask, on ? 0 : -1U);
 279 
 280         dsb(sy);
 281 
 282         if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on,
 283                                       is_on == on, 0, 10000)) {
 284                 dev_err(pmu->dev,
 285                         "failed to set domain '%s', val=%d\n",
 286                         genpd->name, is_on);
 287                 return;
 288         }
 289 }
 290 
 291 static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
 292 {
 293         struct rockchip_pmu *pmu = pd->pmu;
 294         int ret;
 295 
 296         mutex_lock(&pmu->mutex);
 297 
 298         if (rockchip_pmu_domain_is_on(pd) != power_on) {
 299                 ret = clk_bulk_enable(pd->num_clks, pd->clks);
 300                 if (ret < 0) {
 301                         dev_err(pmu->dev, "failed to enable clocks\n");
 302                         mutex_unlock(&pmu->mutex);
 303                         return ret;
 304                 }
 305 
 306                 if (!power_on) {
 307                         rockchip_pmu_save_qos(pd);
 308 
 309                         /* if powering down, idle request to NIU first */
 310                         rockchip_pmu_set_idle_request(pd, true);
 311                 }
 312 
 313                 rockchip_do_pmu_set_power_domain(pd, power_on);
 314 
 315                 if (power_on) {
 316                         /* if powering up, leave idle mode */
 317                         rockchip_pmu_set_idle_request(pd, false);
 318 
 319                         rockchip_pmu_restore_qos(pd);
 320                 }
 321 
 322                 clk_bulk_disable(pd->num_clks, pd->clks);
 323         }
 324 
 325         mutex_unlock(&pmu->mutex);
 326         return 0;
 327 }
 328 
 329 static int rockchip_pd_power_on(struct generic_pm_domain *domain)
 330 {
 331         struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
 332 
 333         return rockchip_pd_power(pd, true);
 334 }
 335 
 336 static int rockchip_pd_power_off(struct generic_pm_domain *domain)
 337 {
 338         struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
 339 
 340         return rockchip_pd_power(pd, false);
 341 }
 342 
 343 static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
 344                                   struct device *dev)
 345 {
 346         struct clk *clk;
 347         int i;
 348         int error;
 349 
 350         dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
 351 
 352         error = pm_clk_create(dev);
 353         if (error) {
 354                 dev_err(dev, "pm_clk_create failed %d\n", error);
 355                 return error;
 356         }
 357 
 358         i = 0;
 359         while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
 360                 dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
 361                 error = pm_clk_add_clk(dev, clk);
 362                 if (error) {
 363                         dev_err(dev, "pm_clk_add_clk failed %d\n", error);
 364                         clk_put(clk);
 365                         pm_clk_destroy(dev);
 366                         return error;
 367                 }
 368         }
 369 
 370         return 0;
 371 }
 372 
 373 static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
 374                                    struct device *dev)
 375 {
 376         dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
 377 
 378         pm_clk_destroy(dev);
 379 }
 380 
 381 static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
 382                                       struct device_node *node)
 383 {
 384         const struct rockchip_domain_info *pd_info;
 385         struct rockchip_pm_domain *pd;
 386         struct device_node *qos_node;
 387         int i, j;
 388         u32 id;
 389         int error;
 390 
 391         error = of_property_read_u32(node, "reg", &id);
 392         if (error) {
 393                 dev_err(pmu->dev,
 394                         "%pOFn: failed to retrieve domain id (reg): %d\n",
 395                         node, error);
 396                 return -EINVAL;
 397         }
 398 
 399         if (id >= pmu->info->num_domains) {
 400                 dev_err(pmu->dev, "%pOFn: invalid domain id %d\n",
 401                         node, id);
 402                 return -EINVAL;
 403         }
 404 
 405         pd_info = &pmu->info->domain_info[id];
 406         if (!pd_info) {
 407                 dev_err(pmu->dev, "%pOFn: undefined domain id %d\n",
 408                         node, id);
 409                 return -EINVAL;
 410         }
 411 
 412         pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
 413         if (!pd)
 414                 return -ENOMEM;
 415 
 416         pd->info = pd_info;
 417         pd->pmu = pmu;
 418 
 419         pd->num_clks = of_clk_get_parent_count(node);
 420         if (pd->num_clks > 0) {
 421                 pd->clks = devm_kcalloc(pmu->dev, pd->num_clks,
 422                                         sizeof(*pd->clks), GFP_KERNEL);
 423                 if (!pd->clks)
 424                         return -ENOMEM;
 425         } else {
 426                 dev_dbg(pmu->dev, "%pOFn: doesn't have clocks: %d\n",
 427                         node, pd->num_clks);
 428                 pd->num_clks = 0;
 429         }
 430 
 431         for (i = 0; i < pd->num_clks; i++) {
 432                 pd->clks[i].clk = of_clk_get(node, i);
 433                 if (IS_ERR(pd->clks[i].clk)) {
 434                         error = PTR_ERR(pd->clks[i].clk);
 435                         dev_err(pmu->dev,
 436                                 "%pOFn: failed to get clk at index %d: %d\n",
 437                                 node, i, error);
 438                         return error;
 439                 }
 440         }
 441 
 442         error = clk_bulk_prepare(pd->num_clks, pd->clks);
 443         if (error)
 444                 goto err_put_clocks;
 445 
 446         pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
 447                                                  NULL);
 448 
 449         if (pd->num_qos > 0) {
 450                 pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
 451                                               sizeof(*pd->qos_regmap),
 452                                               GFP_KERNEL);
 453                 if (!pd->qos_regmap) {
 454                         error = -ENOMEM;
 455                         goto err_unprepare_clocks;
 456                 }
 457 
 458                 for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
 459                         pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
 460                                                             pd->num_qos,
 461                                                             sizeof(u32),
 462                                                             GFP_KERNEL);
 463                         if (!pd->qos_save_regs[j]) {
 464                                 error = -ENOMEM;
 465                                 goto err_unprepare_clocks;
 466                         }
 467                 }
 468 
 469                 for (j = 0; j < pd->num_qos; j++) {
 470                         qos_node = of_parse_phandle(node, "pm_qos", j);
 471                         if (!qos_node) {
 472                                 error = -ENODEV;
 473                                 goto err_unprepare_clocks;
 474                         }
 475                         pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
 476                         if (IS_ERR(pd->qos_regmap[j])) {
 477                                 error = -ENODEV;
 478                                 of_node_put(qos_node);
 479                                 goto err_unprepare_clocks;
 480                         }
 481                         of_node_put(qos_node);
 482                 }
 483         }
 484 
 485         error = rockchip_pd_power(pd, true);
 486         if (error) {
 487                 dev_err(pmu->dev,
 488                         "failed to power on domain '%pOFn': %d\n",
 489                         node, error);
 490                 goto err_unprepare_clocks;
 491         }
 492 
 493         pd->genpd.name = node->name;
 494         pd->genpd.power_off = rockchip_pd_power_off;
 495         pd->genpd.power_on = rockchip_pd_power_on;
 496         pd->genpd.attach_dev = rockchip_pd_attach_dev;
 497         pd->genpd.detach_dev = rockchip_pd_detach_dev;
 498         pd->genpd.flags = GENPD_FLAG_PM_CLK;
 499         if (pd_info->active_wakeup)
 500                 pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
 501         pm_genpd_init(&pd->genpd, NULL, false);
 502 
 503         pmu->genpd_data.domains[id] = &pd->genpd;
 504         return 0;
 505 
 506 err_unprepare_clocks:
 507         clk_bulk_unprepare(pd->num_clks, pd->clks);
 508 err_put_clocks:
 509         clk_bulk_put(pd->num_clks, pd->clks);
 510         return error;
 511 }
 512 
 513 static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
 514 {
 515         int ret;
 516 
 517         /*
 518          * We're in the error cleanup already, so we only complain,
 519          * but won't emit another error on top of the original one.
 520          */
 521         ret = pm_genpd_remove(&pd->genpd);
 522         if (ret < 0)
 523                 dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n",
 524                         pd->genpd.name, ret);
 525 
 526         clk_bulk_unprepare(pd->num_clks, pd->clks);
 527         clk_bulk_put(pd->num_clks, pd->clks);
 528 
 529         /* protect the zeroing of pm->num_clks */
 530         mutex_lock(&pd->pmu->mutex);
 531         pd->num_clks = 0;
 532         mutex_unlock(&pd->pmu->mutex);
 533 
 534         /* devm will free our memory */
 535 }
 536 
 537 static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
 538 {
 539         struct generic_pm_domain *genpd;
 540         struct rockchip_pm_domain *pd;
 541         int i;
 542 
 543         for (i = 0; i < pmu->genpd_data.num_domains; i++) {
 544                 genpd = pmu->genpd_data.domains[i];
 545                 if (genpd) {
 546                         pd = to_rockchip_pd(genpd);
 547                         rockchip_pm_remove_one_domain(pd);
 548                 }
 549         }
 550 
 551         /* devm will free our memory */
 552 }
 553 
 554 static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
 555                                       u32 domain_reg_offset,
 556                                       unsigned int count)
 557 {
 558         /* First configure domain power down transition count ... */
 559         regmap_write(pmu->regmap, domain_reg_offset, count);
 560         /* ... and then power up count. */
 561         regmap_write(pmu->regmap, domain_reg_offset + 4, count);
 562 }
 563 
 564 static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
 565                                      struct device_node *parent)
 566 {
 567         struct device_node *np;
 568         struct generic_pm_domain *child_domain, *parent_domain;
 569         int error;
 570 
 571         for_each_child_of_node(parent, np) {
 572                 u32 idx;
 573 
 574                 error = of_property_read_u32(parent, "reg", &idx);
 575                 if (error) {
 576                         dev_err(pmu->dev,
 577                                 "%pOFn: failed to retrieve domain id (reg): %d\n",
 578                                 parent, error);
 579                         goto err_out;
 580                 }
 581                 parent_domain = pmu->genpd_data.domains[idx];
 582 
 583                 error = rockchip_pm_add_one_domain(pmu, np);
 584                 if (error) {
 585                         dev_err(pmu->dev, "failed to handle node %pOFn: %d\n",
 586                                 np, error);
 587                         goto err_out;
 588                 }
 589 
 590                 error = of_property_read_u32(np, "reg", &idx);
 591                 if (error) {
 592                         dev_err(pmu->dev,
 593                                 "%pOFn: failed to retrieve domain id (reg): %d\n",
 594                                 np, error);
 595                         goto err_out;
 596                 }
 597                 child_domain = pmu->genpd_data.domains[idx];
 598 
 599                 error = pm_genpd_add_subdomain(parent_domain, child_domain);
 600                 if (error) {
 601                         dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
 602                                 parent_domain->name, child_domain->name, error);
 603                         goto err_out;
 604                 } else {
 605                         dev_dbg(pmu->dev, "%s add subdomain: %s\n",
 606                                 parent_domain->name, child_domain->name);
 607                 }
 608 
 609                 rockchip_pm_add_subdomain(pmu, np);
 610         }
 611 
 612         return 0;
 613 
 614 err_out:
 615         of_node_put(np);
 616         return error;
 617 }
 618 
 619 static int rockchip_pm_domain_probe(struct platform_device *pdev)
 620 {
 621         struct device *dev = &pdev->dev;
 622         struct device_node *np = dev->of_node;
 623         struct device_node *node;
 624         struct device *parent;
 625         struct rockchip_pmu *pmu;
 626         const struct of_device_id *match;
 627         const struct rockchip_pmu_info *pmu_info;
 628         int error;
 629 
 630         if (!np) {
 631                 dev_err(dev, "device tree node not found\n");
 632                 return -ENODEV;
 633         }
 634 
 635         match = of_match_device(dev->driver->of_match_table, dev);
 636         if (!match || !match->data) {
 637                 dev_err(dev, "missing pmu data\n");
 638                 return -EINVAL;
 639         }
 640 
 641         pmu_info = match->data;
 642 
 643         pmu = devm_kzalloc(dev,
 644                            struct_size(pmu, domains, pmu_info->num_domains),
 645                            GFP_KERNEL);
 646         if (!pmu)
 647                 return -ENOMEM;
 648 
 649         pmu->dev = &pdev->dev;
 650         mutex_init(&pmu->mutex);
 651 
 652         pmu->info = pmu_info;
 653 
 654         pmu->genpd_data.domains = pmu->domains;
 655         pmu->genpd_data.num_domains = pmu_info->num_domains;
 656 
 657         parent = dev->parent;
 658         if (!parent) {
 659                 dev_err(dev, "no parent for syscon devices\n");
 660                 return -ENODEV;
 661         }
 662 
 663         pmu->regmap = syscon_node_to_regmap(parent->of_node);
 664         if (IS_ERR(pmu->regmap)) {
 665                 dev_err(dev, "no regmap available\n");
 666                 return PTR_ERR(pmu->regmap);
 667         }
 668 
 669         /*
 670          * Configure power up and down transition delays for CORE
 671          * and GPU domains.
 672          */
 673         if (pmu_info->core_power_transition_time)
 674                 rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
 675                                         pmu_info->core_power_transition_time);
 676         if (pmu_info->gpu_pwrcnt_offset)
 677                 rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
 678                                         pmu_info->gpu_power_transition_time);
 679 
 680         error = -ENODEV;
 681 
 682         for_each_available_child_of_node(np, node) {
 683                 error = rockchip_pm_add_one_domain(pmu, node);
 684                 if (error) {
 685                         dev_err(dev, "failed to handle node %pOFn: %d\n",
 686                                 node, error);
 687                         of_node_put(node);
 688                         goto err_out;
 689                 }
 690 
 691                 error = rockchip_pm_add_subdomain(pmu, node);
 692                 if (error < 0) {
 693                         dev_err(dev, "failed to handle subdomain node %pOFn: %d\n",
 694                                 node, error);
 695                         of_node_put(node);
 696                         goto err_out;
 697                 }
 698         }
 699 
 700         if (error) {
 701                 dev_dbg(dev, "no power domains defined\n");
 702                 goto err_out;
 703         }
 704 
 705         error = of_genpd_add_provider_onecell(np, &pmu->genpd_data);
 706         if (error) {
 707                 dev_err(dev, "failed to add provider: %d\n", error);
 708                 goto err_out;
 709         }
 710 
 711         return 0;
 712 
 713 err_out:
 714         rockchip_pm_domain_cleanup(pmu);
 715         return error;
 716 }
 717 
 718 static const struct rockchip_domain_info px30_pm_domains[] = {
 719         [PX30_PD_USB]           = DOMAIN_PX30(BIT(5),  BIT(5),  BIT(10), false),
 720         [PX30_PD_SDCARD]        = DOMAIN_PX30(BIT(8),  BIT(8),  BIT(9),  false),
 721         [PX30_PD_GMAC]          = DOMAIN_PX30(BIT(10), BIT(10), BIT(6),  false),
 722         [PX30_PD_MMC_NAND]      = DOMAIN_PX30(BIT(11), BIT(11), BIT(5),  false),
 723         [PX30_PD_VPU]           = DOMAIN_PX30(BIT(12), BIT(12), BIT(14), false),
 724         [PX30_PD_VO]            = DOMAIN_PX30(BIT(13), BIT(13), BIT(7),  false),
 725         [PX30_PD_VI]            = DOMAIN_PX30(BIT(14), BIT(14), BIT(8),  false),
 726         [PX30_PD_GPU]           = DOMAIN_PX30(BIT(15), BIT(15), BIT(2),  false),
 727 };
 728 
 729 static const struct rockchip_domain_info rk3036_pm_domains[] = {
 730         [RK3036_PD_MSCH]        = DOMAIN_RK3036(BIT(14), BIT(23), BIT(30), true),
 731         [RK3036_PD_CORE]        = DOMAIN_RK3036(BIT(13), BIT(17), BIT(24), false),
 732         [RK3036_PD_PERI]        = DOMAIN_RK3036(BIT(12), BIT(18), BIT(25), false),
 733         [RK3036_PD_VIO]         = DOMAIN_RK3036(BIT(11), BIT(19), BIT(26), false),
 734         [RK3036_PD_VPU]         = DOMAIN_RK3036(BIT(10), BIT(20), BIT(27), false),
 735         [RK3036_PD_GPU]         = DOMAIN_RK3036(BIT(9),  BIT(21), BIT(28), false),
 736         [RK3036_PD_SYS]         = DOMAIN_RK3036(BIT(8),  BIT(22), BIT(29), false),
 737 };
 738 
 739 static const struct rockchip_domain_info rk3066_pm_domains[] = {
 740         [RK3066_PD_GPU]         = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
 741         [RK3066_PD_VIDEO]       = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
 742         [RK3066_PD_VIO]         = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
 743         [RK3066_PD_PERI]        = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
 744         [RK3066_PD_CPU]         = DOMAIN(0,      BIT(5), BIT(1), BIT(26), BIT(31), false),
 745 };
 746 
 747 static const struct rockchip_domain_info rk3128_pm_domains[] = {
 748         [RK3128_PD_CORE]        = DOMAIN_RK3288(BIT(0), BIT(0), BIT(4), false),
 749         [RK3128_PD_MSCH]        = DOMAIN_RK3288(0,      0,      BIT(6), true),
 750         [RK3128_PD_VIO]         = DOMAIN_RK3288(BIT(3), BIT(3), BIT(2), false),
 751         [RK3128_PD_VIDEO]       = DOMAIN_RK3288(BIT(2), BIT(2), BIT(1), false),
 752         [RK3128_PD_GPU]         = DOMAIN_RK3288(BIT(1), BIT(1), BIT(3), false),
 753 };
 754 
 755 static const struct rockchip_domain_info rk3188_pm_domains[] = {
 756         [RK3188_PD_GPU]         = DOMAIN(BIT(9), BIT(9), BIT(3), BIT(24), BIT(29), false),
 757         [RK3188_PD_VIDEO]       = DOMAIN(BIT(8), BIT(8), BIT(4), BIT(23), BIT(28), false),
 758         [RK3188_PD_VIO]         = DOMAIN(BIT(7), BIT(7), BIT(5), BIT(22), BIT(27), false),
 759         [RK3188_PD_PERI]        = DOMAIN(BIT(6), BIT(6), BIT(2), BIT(25), BIT(30), false),
 760         [RK3188_PD_CPU]         = DOMAIN(BIT(5), BIT(5), BIT(1), BIT(26), BIT(31), false),
 761 };
 762 
 763 static const struct rockchip_domain_info rk3228_pm_domains[] = {
 764         [RK3228_PD_CORE]        = DOMAIN_RK3036(BIT(0),  BIT(0),  BIT(16), true),
 765         [RK3228_PD_MSCH]        = DOMAIN_RK3036(BIT(1),  BIT(1),  BIT(17), true),
 766         [RK3228_PD_BUS]         = DOMAIN_RK3036(BIT(2),  BIT(2),  BIT(18), true),
 767         [RK3228_PD_SYS]         = DOMAIN_RK3036(BIT(3),  BIT(3),  BIT(19), true),
 768         [RK3228_PD_VIO]         = DOMAIN_RK3036(BIT(4),  BIT(4),  BIT(20), false),
 769         [RK3228_PD_VOP]         = DOMAIN_RK3036(BIT(5),  BIT(5),  BIT(21), false),
 770         [RK3228_PD_VPU]         = DOMAIN_RK3036(BIT(6),  BIT(6),  BIT(22), false),
 771         [RK3228_PD_RKVDEC]      = DOMAIN_RK3036(BIT(7),  BIT(7),  BIT(23), false),
 772         [RK3228_PD_GPU]         = DOMAIN_RK3036(BIT(8),  BIT(8),  BIT(24), false),
 773         [RK3228_PD_PERI]        = DOMAIN_RK3036(BIT(9),  BIT(9),  BIT(25), true),
 774         [RK3228_PD_GMAC]        = DOMAIN_RK3036(BIT(10), BIT(10), BIT(26), false),
 775 };
 776 
 777 static const struct rockchip_domain_info rk3288_pm_domains[] = {
 778         [RK3288_PD_VIO]         = DOMAIN_RK3288(BIT(7),  BIT(7),  BIT(4), false),
 779         [RK3288_PD_HEVC]        = DOMAIN_RK3288(BIT(14), BIT(10), BIT(9), false),
 780         [RK3288_PD_VIDEO]       = DOMAIN_RK3288(BIT(8),  BIT(8),  BIT(3), false),
 781         [RK3288_PD_GPU]         = DOMAIN_RK3288(BIT(9),  BIT(9),  BIT(2), false),
 782 };
 783 
 784 static const struct rockchip_domain_info rk3328_pm_domains[] = {
 785         [RK3328_PD_CORE]        = DOMAIN_RK3328(0, BIT(0), BIT(0), false),
 786         [RK3328_PD_GPU]         = DOMAIN_RK3328(0, BIT(1), BIT(1), false),
 787         [RK3328_PD_BUS]         = DOMAIN_RK3328(0, BIT(2), BIT(2), true),
 788         [RK3328_PD_MSCH]        = DOMAIN_RK3328(0, BIT(3), BIT(3), true),
 789         [RK3328_PD_PERI]        = DOMAIN_RK3328(0, BIT(4), BIT(4), true),
 790         [RK3328_PD_VIDEO]       = DOMAIN_RK3328(0, BIT(5), BIT(5), false),
 791         [RK3328_PD_HEVC]        = DOMAIN_RK3328(0, BIT(6), BIT(6), false),
 792         [RK3328_PD_VIO]         = DOMAIN_RK3328(0, BIT(8), BIT(8), false),
 793         [RK3328_PD_VPU]         = DOMAIN_RK3328(0, BIT(9), BIT(9), false),
 794 };
 795 
 796 static const struct rockchip_domain_info rk3366_pm_domains[] = {
 797         [RK3366_PD_PERI]        = DOMAIN_RK3368(BIT(10), BIT(10), BIT(6), true),
 798         [RK3366_PD_VIO]         = DOMAIN_RK3368(BIT(14), BIT(14), BIT(8), false),
 799         [RK3366_PD_VIDEO]       = DOMAIN_RK3368(BIT(13), BIT(13), BIT(7), false),
 800         [RK3366_PD_RKVDEC]      = DOMAIN_RK3368(BIT(11), BIT(11), BIT(7), false),
 801         [RK3366_PD_WIFIBT]      = DOMAIN_RK3368(BIT(8),  BIT(8),  BIT(9), false),
 802         [RK3366_PD_VPU]         = DOMAIN_RK3368(BIT(12), BIT(12), BIT(7), false),
 803         [RK3366_PD_GPU]         = DOMAIN_RK3368(BIT(15), BIT(15), BIT(2), false),
 804 };
 805 
 806 static const struct rockchip_domain_info rk3368_pm_domains[] = {
 807         [RK3368_PD_PERI]        = DOMAIN_RK3368(BIT(13), BIT(12), BIT(6), true),
 808         [RK3368_PD_VIO]         = DOMAIN_RK3368(BIT(15), BIT(14), BIT(8), false),
 809         [RK3368_PD_VIDEO]       = DOMAIN_RK3368(BIT(14), BIT(13), BIT(7), false),
 810         [RK3368_PD_GPU_0]       = DOMAIN_RK3368(BIT(16), BIT(15), BIT(2), false),
 811         [RK3368_PD_GPU_1]       = DOMAIN_RK3368(BIT(17), BIT(16), BIT(2), false),
 812 };
 813 
 814 static const struct rockchip_domain_info rk3399_pm_domains[] = {
 815         [RK3399_PD_TCPD0]       = DOMAIN_RK3399(BIT(8),  BIT(8),  0,       false),
 816         [RK3399_PD_TCPD1]       = DOMAIN_RK3399(BIT(9),  BIT(9),  0,       false),
 817         [RK3399_PD_CCI]         = DOMAIN_RK3399(BIT(10), BIT(10), 0,       true),
 818         [RK3399_PD_CCI0]        = DOMAIN_RK3399(0,       0,       BIT(15), true),
 819         [RK3399_PD_CCI1]        = DOMAIN_RK3399(0,       0,       BIT(16), true),
 820         [RK3399_PD_PERILP]      = DOMAIN_RK3399(BIT(11), BIT(11), BIT(1),  true),
 821         [RK3399_PD_PERIHP]      = DOMAIN_RK3399(BIT(12), BIT(12), BIT(2),  true),
 822         [RK3399_PD_CENTER]      = DOMAIN_RK3399(BIT(13), BIT(13), BIT(14), true),
 823         [RK3399_PD_VIO]         = DOMAIN_RK3399(BIT(14), BIT(14), BIT(17), false),
 824         [RK3399_PD_GPU]         = DOMAIN_RK3399(BIT(15), BIT(15), BIT(0),  false),
 825         [RK3399_PD_VCODEC]      = DOMAIN_RK3399(BIT(16), BIT(16), BIT(3),  false),
 826         [RK3399_PD_VDU]         = DOMAIN_RK3399(BIT(17), BIT(17), BIT(4),  false),
 827         [RK3399_PD_RGA]         = DOMAIN_RK3399(BIT(18), BIT(18), BIT(5),  false),
 828         [RK3399_PD_IEP]         = DOMAIN_RK3399(BIT(19), BIT(19), BIT(6),  false),
 829         [RK3399_PD_VO]          = DOMAIN_RK3399(BIT(20), BIT(20), 0,       false),
 830         [RK3399_PD_VOPB]        = DOMAIN_RK3399(0,       0,       BIT(7),  false),
 831         [RK3399_PD_VOPL]        = DOMAIN_RK3399(0,       0,       BIT(8),  false),
 832         [RK3399_PD_ISP0]        = DOMAIN_RK3399(BIT(22), BIT(22), BIT(9),  false),
 833         [RK3399_PD_ISP1]        = DOMAIN_RK3399(BIT(23), BIT(23), BIT(10), false),
 834         [RK3399_PD_HDCP]        = DOMAIN_RK3399(BIT(24), BIT(24), BIT(11), false),
 835         [RK3399_PD_GMAC]        = DOMAIN_RK3399(BIT(25), BIT(25), BIT(23), true),
 836         [RK3399_PD_EMMC]        = DOMAIN_RK3399(BIT(26), BIT(26), BIT(24), true),
 837         [RK3399_PD_USB3]        = DOMAIN_RK3399(BIT(27), BIT(27), BIT(12), true),
 838         [RK3399_PD_EDP]         = DOMAIN_RK3399(BIT(28), BIT(28), BIT(22), false),
 839         [RK3399_PD_GIC]         = DOMAIN_RK3399(BIT(29), BIT(29), BIT(27), true),
 840         [RK3399_PD_SD]          = DOMAIN_RK3399(BIT(30), BIT(30), BIT(28), true),
 841         [RK3399_PD_SDIOAUDIO]   = DOMAIN_RK3399(BIT(31), BIT(31), BIT(29), true),
 842 };
 843 
 844 static const struct rockchip_pmu_info px30_pmu = {
 845         .pwr_offset = 0x18,
 846         .status_offset = 0x20,
 847         .req_offset = 0x64,
 848         .idle_offset = 0x6c,
 849         .ack_offset = 0x6c,
 850 
 851         .num_domains = ARRAY_SIZE(px30_pm_domains),
 852         .domain_info = px30_pm_domains,
 853 };
 854 
 855 static const struct rockchip_pmu_info rk3036_pmu = {
 856         .req_offset = 0x148,
 857         .idle_offset = 0x14c,
 858         .ack_offset = 0x14c,
 859 
 860         .num_domains = ARRAY_SIZE(rk3036_pm_domains),
 861         .domain_info = rk3036_pm_domains,
 862 };
 863 
 864 static const struct rockchip_pmu_info rk3066_pmu = {
 865         .pwr_offset = 0x08,
 866         .status_offset = 0x0c,
 867         .req_offset = 0x38, /* PMU_MISC_CON1 */
 868         .idle_offset = 0x0c,
 869         .ack_offset = 0x0c,
 870 
 871         .num_domains = ARRAY_SIZE(rk3066_pm_domains),
 872         .domain_info = rk3066_pm_domains,
 873 };
 874 
 875 static const struct rockchip_pmu_info rk3128_pmu = {
 876         .pwr_offset = 0x04,
 877         .status_offset = 0x08,
 878         .req_offset = 0x0c,
 879         .idle_offset = 0x10,
 880         .ack_offset = 0x10,
 881 
 882         .num_domains = ARRAY_SIZE(rk3128_pm_domains),
 883         .domain_info = rk3128_pm_domains,
 884 };
 885 
 886 static const struct rockchip_pmu_info rk3188_pmu = {
 887         .pwr_offset = 0x08,
 888         .status_offset = 0x0c,
 889         .req_offset = 0x38, /* PMU_MISC_CON1 */
 890         .idle_offset = 0x0c,
 891         .ack_offset = 0x0c,
 892 
 893         .num_domains = ARRAY_SIZE(rk3188_pm_domains),
 894         .domain_info = rk3188_pm_domains,
 895 };
 896 
 897 static const struct rockchip_pmu_info rk3228_pmu = {
 898         .req_offset = 0x40c,
 899         .idle_offset = 0x488,
 900         .ack_offset = 0x488,
 901 
 902         .num_domains = ARRAY_SIZE(rk3228_pm_domains),
 903         .domain_info = rk3228_pm_domains,
 904 };
 905 
 906 static const struct rockchip_pmu_info rk3288_pmu = {
 907         .pwr_offset = 0x08,
 908         .status_offset = 0x0c,
 909         .req_offset = 0x10,
 910         .idle_offset = 0x14,
 911         .ack_offset = 0x14,
 912 
 913         .core_pwrcnt_offset = 0x34,
 914         .gpu_pwrcnt_offset = 0x3c,
 915 
 916         .core_power_transition_time = 24, /* 1us */
 917         .gpu_power_transition_time = 24, /* 1us */
 918 
 919         .num_domains = ARRAY_SIZE(rk3288_pm_domains),
 920         .domain_info = rk3288_pm_domains,
 921 };
 922 
 923 static const struct rockchip_pmu_info rk3328_pmu = {
 924         .req_offset = 0x414,
 925         .idle_offset = 0x484,
 926         .ack_offset = 0x484,
 927 
 928         .num_domains = ARRAY_SIZE(rk3328_pm_domains),
 929         .domain_info = rk3328_pm_domains,
 930 };
 931 
 932 static const struct rockchip_pmu_info rk3366_pmu = {
 933         .pwr_offset = 0x0c,
 934         .status_offset = 0x10,
 935         .req_offset = 0x3c,
 936         .idle_offset = 0x40,
 937         .ack_offset = 0x40,
 938 
 939         .core_pwrcnt_offset = 0x48,
 940         .gpu_pwrcnt_offset = 0x50,
 941 
 942         .core_power_transition_time = 24,
 943         .gpu_power_transition_time = 24,
 944 
 945         .num_domains = ARRAY_SIZE(rk3366_pm_domains),
 946         .domain_info = rk3366_pm_domains,
 947 };
 948 
 949 static const struct rockchip_pmu_info rk3368_pmu = {
 950         .pwr_offset = 0x0c,
 951         .status_offset = 0x10,
 952         .req_offset = 0x3c,
 953         .idle_offset = 0x40,
 954         .ack_offset = 0x40,
 955 
 956         .core_pwrcnt_offset = 0x48,
 957         .gpu_pwrcnt_offset = 0x50,
 958 
 959         .core_power_transition_time = 24,
 960         .gpu_power_transition_time = 24,
 961 
 962         .num_domains = ARRAY_SIZE(rk3368_pm_domains),
 963         .domain_info = rk3368_pm_domains,
 964 };
 965 
 966 static const struct rockchip_pmu_info rk3399_pmu = {
 967         .pwr_offset = 0x14,
 968         .status_offset = 0x18,
 969         .req_offset = 0x60,
 970         .idle_offset = 0x64,
 971         .ack_offset = 0x68,
 972 
 973         /* ARM Trusted Firmware manages power transition times */
 974 
 975         .num_domains = ARRAY_SIZE(rk3399_pm_domains),
 976         .domain_info = rk3399_pm_domains,
 977 };
 978 
 979 static const struct of_device_id rockchip_pm_domain_dt_match[] = {
 980         {
 981                 .compatible = "rockchip,px30-power-controller",
 982                 .data = (void *)&px30_pmu,
 983         },
 984         {
 985                 .compatible = "rockchip,rk3036-power-controller",
 986                 .data = (void *)&rk3036_pmu,
 987         },
 988         {
 989                 .compatible = "rockchip,rk3066-power-controller",
 990                 .data = (void *)&rk3066_pmu,
 991         },
 992         {
 993                 .compatible = "rockchip,rk3128-power-controller",
 994                 .data = (void *)&rk3128_pmu,
 995         },
 996         {
 997                 .compatible = "rockchip,rk3188-power-controller",
 998                 .data = (void *)&rk3188_pmu,
 999         },
1000         {
1001                 .compatible = "rockchip,rk3228-power-controller",
1002                 .data = (void *)&rk3228_pmu,
1003         },
1004         {
1005                 .compatible = "rockchip,rk3288-power-controller",
1006                 .data = (void *)&rk3288_pmu,
1007         },
1008         {
1009                 .compatible = "rockchip,rk3328-power-controller",
1010                 .data = (void *)&rk3328_pmu,
1011         },
1012         {
1013                 .compatible = "rockchip,rk3366-power-controller",
1014                 .data = (void *)&rk3366_pmu,
1015         },
1016         {
1017                 .compatible = "rockchip,rk3368-power-controller",
1018                 .data = (void *)&rk3368_pmu,
1019         },
1020         {
1021                 .compatible = "rockchip,rk3399-power-controller",
1022                 .data = (void *)&rk3399_pmu,
1023         },
1024         { /* sentinel */ },
1025 };
1026 
1027 static struct platform_driver rockchip_pm_domain_driver = {
1028         .probe = rockchip_pm_domain_probe,
1029         .driver = {
1030                 .name   = "rockchip-pm-domain",
1031                 .of_match_table = rockchip_pm_domain_dt_match,
1032                 /*
1033                  * We can't forcibly eject devices form power domain,
1034                  * so we can't really remove power domains once they
1035                  * were added.
1036                  */
1037                 .suppress_bind_attrs = true,
1038         },
1039 };
1040 
1041 static int __init rockchip_pm_domain_drv_register(void)
1042 {
1043         return platform_driver_register(&rockchip_pm_domain_driver);
1044 }
1045 postcore_initcall(rockchip_pm_domain_drv_register);

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