linux/drivers/soc/rockchip/pm_domains.c
<<
>>
Prefs
   1/*
   2 * Rockchip Generic power domain support.
   3 *
   4 * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/io.h>
  12#include <linux/err.h>
  13#include <linux/pm_clock.h>
  14#include <linux/pm_domain.h>
  15#include <linux/of_address.h>
  16#include <linux/of_platform.h>
  17#include <linux/clk.h>
  18#include <linux/regmap.h>
  19#include <linux/mfd/syscon.h>
  20#include <dt-bindings/power/rk3288-power.h>
  21#include <dt-bindings/power/rk3368-power.h>
  22#include <dt-bindings/power/rk3399-power.h>
  23
  24struct rockchip_domain_info {
  25        int pwr_mask;
  26        int status_mask;
  27        int req_mask;
  28        int idle_mask;
  29        int ack_mask;
  30};
  31
  32struct rockchip_pmu_info {
  33        u32 pwr_offset;
  34        u32 status_offset;
  35        u32 req_offset;
  36        u32 idle_offset;
  37        u32 ack_offset;
  38
  39        u32 core_pwrcnt_offset;
  40        u32 gpu_pwrcnt_offset;
  41
  42        unsigned int core_power_transition_time;
  43        unsigned int gpu_power_transition_time;
  44
  45        int num_domains;
  46        const struct rockchip_domain_info *domain_info;
  47};
  48
  49#define MAX_QOS_REGS_NUM        5
  50#define QOS_PRIORITY            0x08
  51#define QOS_MODE                0x0c
  52#define QOS_BANDWIDTH           0x10
  53#define QOS_SATURATION          0x14
  54#define QOS_EXTCONTROL          0x18
  55
  56struct rockchip_pm_domain {
  57        struct generic_pm_domain genpd;
  58        const struct rockchip_domain_info *info;
  59        struct rockchip_pmu *pmu;
  60        int num_qos;
  61        struct regmap **qos_regmap;
  62        u32 *qos_save_regs[MAX_QOS_REGS_NUM];
  63        int num_clks;
  64        struct clk *clks[];
  65};
  66
  67struct rockchip_pmu {
  68        struct device *dev;
  69        struct regmap *regmap;
  70        const struct rockchip_pmu_info *info;
  71        struct mutex mutex; /* mutex lock for pmu */
  72        struct genpd_onecell_data genpd_data;
  73        struct generic_pm_domain *domains[];
  74};
  75
  76#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
  77
  78#define DOMAIN(pwr, status, req, idle, ack)     \
  79{                                               \
  80        .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0,          \
  81        .status_mask = (status >= 0) ? BIT(status) : 0, \
  82        .req_mask = (req >= 0) ? BIT(req) : 0,          \
  83        .idle_mask = (idle >= 0) ? BIT(idle) : 0,       \
  84        .ack_mask = (ack >= 0) ? BIT(ack) : 0,          \
  85}
  86
  87#define DOMAIN_RK3288(pwr, status, req)         \
  88        DOMAIN(pwr, status, req, req, (req) + 16)
  89
  90#define DOMAIN_RK3368(pwr, status, req)         \
  91        DOMAIN(pwr, status, req, (req) + 16, req)
  92
  93#define DOMAIN_RK3399(pwr, status, req)                \
  94        DOMAIN(pwr, status, req, req, req)
  95
  96static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
  97{
  98        struct rockchip_pmu *pmu = pd->pmu;
  99        const struct rockchip_domain_info *pd_info = pd->info;
 100        unsigned int val;
 101
 102        regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
 103        return (val & pd_info->idle_mask) == pd_info->idle_mask;
 104}
 105
 106static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
 107                                         bool idle)
 108{
 109        const struct rockchip_domain_info *pd_info = pd->info;
 110        struct rockchip_pmu *pmu = pd->pmu;
 111        unsigned int val;
 112
 113        if (pd_info->req_mask == 0)
 114                return 0;
 115
 116        regmap_update_bits(pmu->regmap, pmu->info->req_offset,
 117                           pd_info->req_mask, idle ? -1U : 0);
 118
 119        dsb(sy);
 120
 121        do {
 122                regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
 123        } while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0));
 124
 125        while (rockchip_pmu_domain_is_idle(pd) != idle)
 126                cpu_relax();
 127
 128        return 0;
 129}
 130
 131static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd)
 132{
 133        int i;
 134
 135        for (i = 0; i < pd->num_qos; i++) {
 136                regmap_read(pd->qos_regmap[i],
 137                            QOS_PRIORITY,
 138                            &pd->qos_save_regs[0][i]);
 139                regmap_read(pd->qos_regmap[i],
 140                            QOS_MODE,
 141                            &pd->qos_save_regs[1][i]);
 142                regmap_read(pd->qos_regmap[i],
 143                            QOS_BANDWIDTH,
 144                            &pd->qos_save_regs[2][i]);
 145                regmap_read(pd->qos_regmap[i],
 146                            QOS_SATURATION,
 147                            &pd->qos_save_regs[3][i]);
 148                regmap_read(pd->qos_regmap[i],
 149                            QOS_EXTCONTROL,
 150                            &pd->qos_save_regs[4][i]);
 151        }
 152        return 0;
 153}
 154
 155static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd)
 156{
 157        int i;
 158
 159        for (i = 0; i < pd->num_qos; i++) {
 160                regmap_write(pd->qos_regmap[i],
 161                             QOS_PRIORITY,
 162                             pd->qos_save_regs[0][i]);
 163                regmap_write(pd->qos_regmap[i],
 164                             QOS_MODE,
 165                             pd->qos_save_regs[1][i]);
 166                regmap_write(pd->qos_regmap[i],
 167                             QOS_BANDWIDTH,
 168                             pd->qos_save_regs[2][i]);
 169                regmap_write(pd->qos_regmap[i],
 170                             QOS_SATURATION,
 171                             pd->qos_save_regs[3][i]);
 172                regmap_write(pd->qos_regmap[i],
 173                             QOS_EXTCONTROL,
 174                             pd->qos_save_regs[4][i]);
 175        }
 176
 177        return 0;
 178}
 179
 180static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
 181{
 182        struct rockchip_pmu *pmu = pd->pmu;
 183        unsigned int val;
 184
 185        /* check idle status for idle-only domains */
 186        if (pd->info->status_mask == 0)
 187                return !rockchip_pmu_domain_is_idle(pd);
 188
 189        regmap_read(pmu->regmap, pmu->info->status_offset, &val);
 190
 191        /* 1'b0: power on, 1'b1: power off */
 192        return !(val & pd->info->status_mask);
 193}
 194
 195static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
 196                                             bool on)
 197{
 198        struct rockchip_pmu *pmu = pd->pmu;
 199
 200        if (pd->info->pwr_mask == 0)
 201                return;
 202
 203        regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
 204                           pd->info->pwr_mask, on ? 0 : -1U);
 205
 206        dsb(sy);
 207
 208        while (rockchip_pmu_domain_is_on(pd) != on)
 209                cpu_relax();
 210}
 211
 212static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
 213{
 214        int i;
 215
 216        mutex_lock(&pd->pmu->mutex);
 217
 218        if (rockchip_pmu_domain_is_on(pd) != power_on) {
 219                for (i = 0; i < pd->num_clks; i++)
 220                        clk_enable(pd->clks[i]);
 221
 222                if (!power_on) {
 223                        rockchip_pmu_save_qos(pd);
 224
 225                        /* if powering down, idle request to NIU first */
 226                        rockchip_pmu_set_idle_request(pd, true);
 227                }
 228
 229                rockchip_do_pmu_set_power_domain(pd, power_on);
 230
 231                if (power_on) {
 232                        /* if powering up, leave idle mode */
 233                        rockchip_pmu_set_idle_request(pd, false);
 234
 235                        rockchip_pmu_restore_qos(pd);
 236                }
 237
 238                for (i = pd->num_clks - 1; i >= 0; i--)
 239                        clk_disable(pd->clks[i]);
 240        }
 241
 242        mutex_unlock(&pd->pmu->mutex);
 243        return 0;
 244}
 245
 246static int rockchip_pd_power_on(struct generic_pm_domain *domain)
 247{
 248        struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
 249
 250        return rockchip_pd_power(pd, true);
 251}
 252
 253static int rockchip_pd_power_off(struct generic_pm_domain *domain)
 254{
 255        struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
 256
 257        return rockchip_pd_power(pd, false);
 258}
 259
 260static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
 261                                  struct device *dev)
 262{
 263        struct clk *clk;
 264        int i;
 265        int error;
 266
 267        dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
 268
 269        error = pm_clk_create(dev);
 270        if (error) {
 271                dev_err(dev, "pm_clk_create failed %d\n", error);
 272                return error;
 273        }
 274
 275        i = 0;
 276        while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
 277                dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
 278                error = pm_clk_add_clk(dev, clk);
 279                if (error) {
 280                        dev_err(dev, "pm_clk_add_clk failed %d\n", error);
 281                        clk_put(clk);
 282                        pm_clk_destroy(dev);
 283                        return error;
 284                }
 285        }
 286
 287        return 0;
 288}
 289
 290static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
 291                                   struct device *dev)
 292{
 293        dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
 294
 295        pm_clk_destroy(dev);
 296}
 297
 298static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
 299                                      struct device_node *node)
 300{
 301        const struct rockchip_domain_info *pd_info;
 302        struct rockchip_pm_domain *pd;
 303        struct device_node *qos_node;
 304        struct clk *clk;
 305        int clk_cnt;
 306        int i, j;
 307        u32 id;
 308        int error;
 309
 310        error = of_property_read_u32(node, "reg", &id);
 311        if (error) {
 312                dev_err(pmu->dev,
 313                        "%s: failed to retrieve domain id (reg): %d\n",
 314                        node->name, error);
 315                return -EINVAL;
 316        }
 317
 318        if (id >= pmu->info->num_domains) {
 319                dev_err(pmu->dev, "%s: invalid domain id %d\n",
 320                        node->name, id);
 321                return -EINVAL;
 322        }
 323
 324        pd_info = &pmu->info->domain_info[id];
 325        if (!pd_info) {
 326                dev_err(pmu->dev, "%s: undefined domain id %d\n",
 327                        node->name, id);
 328                return -EINVAL;
 329        }
 330
 331        clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells");
 332        pd = devm_kzalloc(pmu->dev,
 333                          sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]),
 334                          GFP_KERNEL);
 335        if (!pd)
 336                return -ENOMEM;
 337
 338        pd->info = pd_info;
 339        pd->pmu = pmu;
 340
 341        for (i = 0; i < clk_cnt; i++) {
 342                clk = of_clk_get(node, i);
 343                if (IS_ERR(clk)) {
 344                        error = PTR_ERR(clk);
 345                        dev_err(pmu->dev,
 346                                "%s: failed to get clk at index %d: %d\n",
 347                                node->name, i, error);
 348                        goto err_out;
 349                }
 350
 351                error = clk_prepare(clk);
 352                if (error) {
 353                        dev_err(pmu->dev,
 354                                "%s: failed to prepare clk %pC (index %d): %d\n",
 355                                node->name, clk, i, error);
 356                        clk_put(clk);
 357                        goto err_out;
 358                }
 359
 360                pd->clks[pd->num_clks++] = clk;
 361
 362                dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n",
 363                        clk, node->name);
 364        }
 365
 366        pd->num_qos = of_count_phandle_with_args(node, "pm_qos",
 367                                                 NULL);
 368
 369        if (pd->num_qos > 0) {
 370                pd->qos_regmap = devm_kcalloc(pmu->dev, pd->num_qos,
 371                                              sizeof(*pd->qos_regmap),
 372                                              GFP_KERNEL);
 373                if (!pd->qos_regmap) {
 374                        error = -ENOMEM;
 375                        goto err_out;
 376                }
 377
 378                for (j = 0; j < MAX_QOS_REGS_NUM; j++) {
 379                        pd->qos_save_regs[j] = devm_kcalloc(pmu->dev,
 380                                                            pd->num_qos,
 381                                                            sizeof(u32),
 382                                                            GFP_KERNEL);
 383                        if (!pd->qos_save_regs[j]) {
 384                                error = -ENOMEM;
 385                                goto err_out;
 386                        }
 387                }
 388
 389                for (j = 0; j < pd->num_qos; j++) {
 390                        qos_node = of_parse_phandle(node, "pm_qos", j);
 391                        if (!qos_node) {
 392                                error = -ENODEV;
 393                                goto err_out;
 394                        }
 395                        pd->qos_regmap[j] = syscon_node_to_regmap(qos_node);
 396                        if (IS_ERR(pd->qos_regmap[j])) {
 397                                error = -ENODEV;
 398                                of_node_put(qos_node);
 399                                goto err_out;
 400                        }
 401                        of_node_put(qos_node);
 402                }
 403        }
 404
 405        error = rockchip_pd_power(pd, true);
 406        if (error) {
 407                dev_err(pmu->dev,
 408                        "failed to power on domain '%s': %d\n",
 409                        node->name, error);
 410                goto err_out;
 411        }
 412
 413        pd->genpd.name = node->name;
 414        pd->genpd.power_off = rockchip_pd_power_off;
 415        pd->genpd.power_on = rockchip_pd_power_on;
 416        pd->genpd.attach_dev = rockchip_pd_attach_dev;
 417        pd->genpd.detach_dev = rockchip_pd_detach_dev;
 418        pd->genpd.flags = GENPD_FLAG_PM_CLK;
 419        pm_genpd_init(&pd->genpd, NULL, false);
 420
 421        pmu->genpd_data.domains[id] = &pd->genpd;
 422        return 0;
 423
 424err_out:
 425        while (--i >= 0) {
 426                clk_unprepare(pd->clks[i]);
 427                clk_put(pd->clks[i]);
 428        }
 429        return error;
 430}
 431
 432static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
 433{
 434        int i;
 435
 436        for (i = 0; i < pd->num_clks; i++) {
 437                clk_unprepare(pd->clks[i]);
 438                clk_put(pd->clks[i]);
 439        }
 440
 441        /* protect the zeroing of pm->num_clks */
 442        mutex_lock(&pd->pmu->mutex);
 443        pd->num_clks = 0;
 444        mutex_unlock(&pd->pmu->mutex);
 445
 446        /* devm will free our memory */
 447}
 448
 449static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
 450{
 451        struct generic_pm_domain *genpd;
 452        struct rockchip_pm_domain *pd;
 453        int i;
 454
 455        for (i = 0; i < pmu->genpd_data.num_domains; i++) {
 456                genpd = pmu->genpd_data.domains[i];
 457                if (genpd) {
 458                        pd = to_rockchip_pd(genpd);
 459                        rockchip_pm_remove_one_domain(pd);
 460                }
 461        }
 462
 463        /* devm will free our memory */
 464}
 465
 466static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
 467                                      u32 domain_reg_offset,
 468                                      unsigned int count)
 469{
 470        /* First configure domain power down transition count ... */
 471        regmap_write(pmu->regmap, domain_reg_offset, count);
 472        /* ... and then power up count. */
 473        regmap_write(pmu->regmap, domain_reg_offset + 4, count);
 474}
 475
 476static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
 477                                     struct device_node *parent)
 478{
 479        struct device_node *np;
 480        struct generic_pm_domain *child_domain, *parent_domain;
 481        int error;
 482
 483        for_each_child_of_node(parent, np) {
 484                u32 idx;
 485
 486                error = of_property_read_u32(parent, "reg", &idx);
 487                if (error) {
 488                        dev_err(pmu->dev,
 489                                "%s: failed to retrieve domain id (reg): %d\n",
 490                                parent->name, error);
 491                        goto err_out;
 492                }
 493                parent_domain = pmu->genpd_data.domains[idx];
 494
 495                error = rockchip_pm_add_one_domain(pmu, np);
 496                if (error) {
 497                        dev_err(pmu->dev, "failed to handle node %s: %d\n",
 498                                np->name, error);
 499                        goto err_out;
 500                }
 501
 502                error = of_property_read_u32(np, "reg", &idx);
 503                if (error) {
 504                        dev_err(pmu->dev,
 505                                "%s: failed to retrieve domain id (reg): %d\n",
 506                                np->name, error);
 507                        goto err_out;
 508                }
 509                child_domain = pmu->genpd_data.domains[idx];
 510
 511                error = pm_genpd_add_subdomain(parent_domain, child_domain);
 512                if (error) {
 513                        dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n",
 514                                parent_domain->name, child_domain->name, error);
 515                        goto err_out;
 516                } else {
 517                        dev_dbg(pmu->dev, "%s add subdomain: %s\n",
 518                                parent_domain->name, child_domain->name);
 519                }
 520
 521                rockchip_pm_add_subdomain(pmu, np);
 522        }
 523
 524        return 0;
 525
 526err_out:
 527        of_node_put(np);
 528        return error;
 529}
 530
 531static int rockchip_pm_domain_probe(struct platform_device *pdev)
 532{
 533        struct device *dev = &pdev->dev;
 534        struct device_node *np = dev->of_node;
 535        struct device_node *node;
 536        struct device *parent;
 537        struct rockchip_pmu *pmu;
 538        const struct of_device_id *match;
 539        const struct rockchip_pmu_info *pmu_info;
 540        int error;
 541
 542        if (!np) {
 543                dev_err(dev, "device tree node not found\n");
 544                return -ENODEV;
 545        }
 546
 547        match = of_match_device(dev->driver->of_match_table, dev);
 548        if (!match || !match->data) {
 549                dev_err(dev, "missing pmu data\n");
 550                return -EINVAL;
 551        }
 552
 553        pmu_info = match->data;
 554
 555        pmu = devm_kzalloc(dev,
 556                           sizeof(*pmu) +
 557                                pmu_info->num_domains * sizeof(pmu->domains[0]),
 558                           GFP_KERNEL);
 559        if (!pmu)
 560                return -ENOMEM;
 561
 562        pmu->dev = &pdev->dev;
 563        mutex_init(&pmu->mutex);
 564
 565        pmu->info = pmu_info;
 566
 567        pmu->genpd_data.domains = pmu->domains;
 568        pmu->genpd_data.num_domains = pmu_info->num_domains;
 569
 570        parent = dev->parent;
 571        if (!parent) {
 572                dev_err(dev, "no parent for syscon devices\n");
 573                return -ENODEV;
 574        }
 575
 576        pmu->regmap = syscon_node_to_regmap(parent->of_node);
 577        if (IS_ERR(pmu->regmap)) {
 578                dev_err(dev, "no regmap available\n");
 579                return PTR_ERR(pmu->regmap);
 580        }
 581
 582        /*
 583         * Configure power up and down transition delays for CORE
 584         * and GPU domains.
 585         */
 586        rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
 587                                  pmu_info->core_power_transition_time);
 588        rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
 589                                  pmu_info->gpu_power_transition_time);
 590
 591        error = -ENODEV;
 592
 593        for_each_available_child_of_node(np, node) {
 594                error = rockchip_pm_add_one_domain(pmu, node);
 595                if (error) {
 596                        dev_err(dev, "failed to handle node %s: %d\n",
 597                                node->name, error);
 598                        of_node_put(node);
 599                        goto err_out;
 600                }
 601
 602                error = rockchip_pm_add_subdomain(pmu, node);
 603                if (error < 0) {
 604                        dev_err(dev, "failed to handle subdomain node %s: %d\n",
 605                                node->name, error);
 606                        of_node_put(node);
 607                        goto err_out;
 608                }
 609        }
 610
 611        if (error) {
 612                dev_dbg(dev, "no power domains defined\n");
 613                goto err_out;
 614        }
 615
 616        of_genpd_add_provider_onecell(np, &pmu->genpd_data);
 617
 618        return 0;
 619
 620err_out:
 621        rockchip_pm_domain_cleanup(pmu);
 622        return error;
 623}
 624
 625static const struct rockchip_domain_info rk3288_pm_domains[] = {
 626        [RK3288_PD_VIO]         = DOMAIN_RK3288(7, 7, 4),
 627        [RK3288_PD_HEVC]        = DOMAIN_RK3288(14, 10, 9),
 628        [RK3288_PD_VIDEO]       = DOMAIN_RK3288(8, 8, 3),
 629        [RK3288_PD_GPU]         = DOMAIN_RK3288(9, 9, 2),
 630};
 631
 632static const struct rockchip_domain_info rk3368_pm_domains[] = {
 633        [RK3368_PD_PERI]        = DOMAIN_RK3368(13, 12, 6),
 634        [RK3368_PD_VIO]         = DOMAIN_RK3368(15, 14, 8),
 635        [RK3368_PD_VIDEO]       = DOMAIN_RK3368(14, 13, 7),
 636        [RK3368_PD_GPU_0]       = DOMAIN_RK3368(16, 15, 2),
 637        [RK3368_PD_GPU_1]       = DOMAIN_RK3368(17, 16, 2),
 638};
 639
 640static const struct rockchip_domain_info rk3399_pm_domains[] = {
 641        [RK3399_PD_TCPD0]       = DOMAIN_RK3399(8, 8, -1),
 642        [RK3399_PD_TCPD1]       = DOMAIN_RK3399(9, 9, -1),
 643        [RK3399_PD_CCI]         = DOMAIN_RK3399(10, 10, -1),
 644        [RK3399_PD_CCI0]        = DOMAIN_RK3399(-1, -1, 15),
 645        [RK3399_PD_CCI1]        = DOMAIN_RK3399(-1, -1, 16),
 646        [RK3399_PD_PERILP]      = DOMAIN_RK3399(11, 11, 1),
 647        [RK3399_PD_PERIHP]      = DOMAIN_RK3399(12, 12, 2),
 648        [RK3399_PD_CENTER]      = DOMAIN_RK3399(13, 13, 14),
 649        [RK3399_PD_VIO]         = DOMAIN_RK3399(14, 14, 17),
 650        [RK3399_PD_GPU]         = DOMAIN_RK3399(15, 15, 0),
 651        [RK3399_PD_VCODEC]      = DOMAIN_RK3399(16, 16, 3),
 652        [RK3399_PD_VDU]         = DOMAIN_RK3399(17, 17, 4),
 653        [RK3399_PD_RGA]         = DOMAIN_RK3399(18, 18, 5),
 654        [RK3399_PD_IEP]         = DOMAIN_RK3399(19, 19, 6),
 655        [RK3399_PD_VO]          = DOMAIN_RK3399(20, 20, -1),
 656        [RK3399_PD_VOPB]        = DOMAIN_RK3399(-1, -1, 7),
 657        [RK3399_PD_VOPL]        = DOMAIN_RK3399(-1, -1, 8),
 658        [RK3399_PD_ISP0]        = DOMAIN_RK3399(22, 22, 9),
 659        [RK3399_PD_ISP1]        = DOMAIN_RK3399(23, 23, 10),
 660        [RK3399_PD_HDCP]        = DOMAIN_RK3399(24, 24, 11),
 661        [RK3399_PD_GMAC]        = DOMAIN_RK3399(25, 25, 23),
 662        [RK3399_PD_EMMC]        = DOMAIN_RK3399(26, 26, 24),
 663        [RK3399_PD_USB3]        = DOMAIN_RK3399(27, 27, 12),
 664        [RK3399_PD_EDP]         = DOMAIN_RK3399(28, 28, 22),
 665        [RK3399_PD_GIC]         = DOMAIN_RK3399(29, 29, 27),
 666        [RK3399_PD_SD]          = DOMAIN_RK3399(30, 30, 28),
 667        [RK3399_PD_SDIOAUDIO]   = DOMAIN_RK3399(31, 31, 29),
 668};
 669
 670static const struct rockchip_pmu_info rk3288_pmu = {
 671        .pwr_offset = 0x08,
 672        .status_offset = 0x0c,
 673        .req_offset = 0x10,
 674        .idle_offset = 0x14,
 675        .ack_offset = 0x14,
 676
 677        .core_pwrcnt_offset = 0x34,
 678        .gpu_pwrcnt_offset = 0x3c,
 679
 680        .core_power_transition_time = 24, /* 1us */
 681        .gpu_power_transition_time = 24, /* 1us */
 682
 683        .num_domains = ARRAY_SIZE(rk3288_pm_domains),
 684        .domain_info = rk3288_pm_domains,
 685};
 686
 687static const struct rockchip_pmu_info rk3368_pmu = {
 688        .pwr_offset = 0x0c,
 689        .status_offset = 0x10,
 690        .req_offset = 0x3c,
 691        .idle_offset = 0x40,
 692        .ack_offset = 0x40,
 693
 694        .core_pwrcnt_offset = 0x48,
 695        .gpu_pwrcnt_offset = 0x50,
 696
 697        .core_power_transition_time = 24,
 698        .gpu_power_transition_time = 24,
 699
 700        .num_domains = ARRAY_SIZE(rk3368_pm_domains),
 701        .domain_info = rk3368_pm_domains,
 702};
 703
 704static const struct rockchip_pmu_info rk3399_pmu = {
 705        .pwr_offset = 0x14,
 706        .status_offset = 0x18,
 707        .req_offset = 0x60,
 708        .idle_offset = 0x64,
 709        .ack_offset = 0x68,
 710
 711        .core_pwrcnt_offset = 0x9c,
 712        .gpu_pwrcnt_offset = 0xa4,
 713
 714        .core_power_transition_time = 24,
 715        .gpu_power_transition_time = 24,
 716
 717        .num_domains = ARRAY_SIZE(rk3399_pm_domains),
 718        .domain_info = rk3399_pm_domains,
 719};
 720
 721static const struct of_device_id rockchip_pm_domain_dt_match[] = {
 722        {
 723                .compatible = "rockchip,rk3288-power-controller",
 724                .data = (void *)&rk3288_pmu,
 725        },
 726        {
 727                .compatible = "rockchip,rk3368-power-controller",
 728                .data = (void *)&rk3368_pmu,
 729        },
 730        {
 731                .compatible = "rockchip,rk3399-power-controller",
 732                .data = (void *)&rk3399_pmu,
 733        },
 734        { /* sentinel */ },
 735};
 736
 737static struct platform_driver rockchip_pm_domain_driver = {
 738        .probe = rockchip_pm_domain_probe,
 739        .driver = {
 740                .name   = "rockchip-pm-domain",
 741                .of_match_table = rockchip_pm_domain_dt_match,
 742                /*
 743                 * We can't forcibly eject devices form power domain,
 744                 * so we can't really remove power domains once they
 745                 * were added.
 746                 */
 747                .suppress_bind_attrs = true,
 748        },
 749};
 750
 751static int __init rockchip_pm_domain_drv_register(void)
 752{
 753        return platform_driver_register(&rockchip_pm_domain_driver);
 754}
 755postcore_initcall(rockchip_pm_domain_drv_register);
 756