]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/soc/rockchip/pm_domains.c
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszer...
[karo-tx-linux.git] / drivers / soc / rockchip / pm_domains.c
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
24 struct 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
32 struct 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
56 struct 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
67 struct 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
96 static 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
106 static 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
131 static 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
155 static 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
180 static 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
195 static 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
212 static 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
246 static 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
253 static 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
260 static 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
290 static 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
298 static 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
424 err_out:
425         while (--i >= 0) {
426                 clk_unprepare(pd->clks[i]);
427                 clk_put(pd->clks[i]);
428         }
429         return error;
430 }
431
432 static 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
449 static 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
466 static 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
476 static 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
526 err_out:
527         of_node_put(np);
528         return error;
529 }
530
531 static 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
620 err_out:
621         rockchip_pm_domain_cleanup(pmu);
622         return error;
623 }
624
625 static 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
632 static 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
640 static 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
670 static 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
687 static 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
704 static 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
721 static 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
737 static 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
751 static int __init rockchip_pm_domain_drv_register(void)
752 {
753         return platform_driver_register(&rockchip_pm_domain_driver);
754 }
755 postcore_initcall(rockchip_pm_domain_drv_register);