ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t12x.c
1 /*
2  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <linux/spinlock.h>
16 #include <linux/delay.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/tegra-powergate.h>
19
20 #include <asm/atomic.h>
21
22 #include "powergate-priv.h"
23 #include "powergate-ops-txx.h"
24 #include "powergate-ops-t1xx.h"
25 #include "dvfs.h"
26
27 enum mc_client {
28         MC_CLIENT_AFI           = 0,
29         MC_CLIENT_DC            = 2,
30         MC_CLIENT_DCB           = 3,
31         MC_CLIENT_ISP           = 8,
32         MC_CLIENT_MSENC         = 11,
33         MC_CLIENT_SATA          = 15,
34         MC_CLIENT_VDE           = 16,
35         MC_CLIENT_VI            = 17,
36         MC_CLIENT_VIC           = 18,
37         MC_CLIENT_XUSB_HOST     = 19,
38         MC_CLIENT_XUSB_DEV      = 20,
39         MC_CLIENT_ISPB          = 33,
40         MC_CLIENT_GPU           = 34,
41         MC_CLIENT_LAST          = -1,
42 };
43
44 struct tegra12x_powergate_mc_client_info {
45         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
46 };
47
48 static struct tegra12x_powergate_mc_client_info tegra12x_pg_mc_info[] = {
49         [TEGRA_POWERGATE_CRAIL] = {
50                 .hot_reset_clients = {
51                         [0] = MC_CLIENT_LAST,
52                 },
53         },
54         [TEGRA_POWERGATE_GPU] = {
55                 .hot_reset_clients = {
56                         [0] = MC_CLIENT_GPU,
57                         [1] = MC_CLIENT_LAST,
58                 },
59         },
60         [TEGRA_POWERGATE_VDEC] = {
61                 .hot_reset_clients = {
62                         [0] = MC_CLIENT_VDE,
63                         [1] = MC_CLIENT_LAST,
64                 },
65         },
66         [TEGRA_POWERGATE_MPE] = {
67                 .hot_reset_clients = {
68                         [0] = MC_CLIENT_MSENC,
69                         [1] = MC_CLIENT_LAST,
70                 },
71         },
72         [TEGRA_POWERGATE_VENC] = {
73                 .hot_reset_clients = {
74                         [0] = MC_CLIENT_ISP,
75                         [1] = MC_CLIENT_ISPB,
76                         [2] = MC_CLIENT_VI,
77                         [3] = MC_CLIENT_LAST,
78                 },
79         },
80         [TEGRA_POWERGATE_CPU1] = {
81                 .hot_reset_clients = {
82                         [0] = MC_CLIENT_LAST,
83                 },
84         },
85         [TEGRA_POWERGATE_CPU2] = {
86                 .hot_reset_clients = {
87                         [0] = MC_CLIENT_LAST,
88                 },
89         },
90         [TEGRA_POWERGATE_CPU3] = {
91                 .hot_reset_clients = {
92                         [0] = MC_CLIENT_LAST,
93                 },
94         },
95         [TEGRA_POWERGATE_CELP] = {
96                 .hot_reset_clients = {
97                         [0] = MC_CLIENT_LAST,
98                 },
99         },
100         [TEGRA_POWERGATE_CPU0] = {
101                 .hot_reset_clients = {
102                         [0] = MC_CLIENT_LAST,
103                 },
104         },
105         [TEGRA_POWERGATE_C0NC] = {
106                 .hot_reset_clients = {
107                         [0] = MC_CLIENT_LAST,
108                 },
109         },
110         [TEGRA_POWERGATE_C1NC] = {
111                 .hot_reset_clients = {
112                         [0] = MC_CLIENT_LAST,
113                 },
114         },
115         [TEGRA_POWERGATE_DISA] = {
116                 .hot_reset_clients = {
117                         [0] = MC_CLIENT_DC,
118                         [1] = MC_CLIENT_LAST,
119                 },
120         },
121         [TEGRA_POWERGATE_DISB] = {
122                 .hot_reset_clients = {
123                         [0] = MC_CLIENT_DCB,
124                         [1] = MC_CLIENT_LAST,
125                 },
126         },
127         [TEGRA_POWERGATE_XUSBA] = {
128                 .hot_reset_clients = {
129                         [0] = MC_CLIENT_LAST,
130                 },
131         },
132         [TEGRA_POWERGATE_XUSBB] = {
133                 .hot_reset_clients = {
134                         [0] = MC_CLIENT_XUSB_DEV,
135                         [1] = MC_CLIENT_LAST
136                 },
137         },
138         [TEGRA_POWERGATE_XUSBC] = {
139                 .hot_reset_clients = {
140                         [0] = MC_CLIENT_XUSB_HOST,
141                         [1] = MC_CLIENT_LAST,
142                 },
143         },
144 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
145         [TEGRA_POWERGATE_PCIE] = {
146                 .hot_reset_clients = {
147                         [0] = MC_CLIENT_AFI,
148                         [1] = MC_CLIENT_LAST,
149                 },
150         },
151 #endif
152 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
153         [TEGRA_POWERGATE_SATA] = {
154                 .hot_reset_clients = {
155                         [0] = MC_CLIENT_SATA,
156                         [1] = MC_CLIENT_LAST,
157                 },
158         },
159 #endif
160         [TEGRA_POWERGATE_SOR] = {
161                 .hot_reset_clients = {
162                         [0] = MC_CLIENT_LAST,
163                 },
164         },
165 #ifdef CONFIG_ARCH_TEGRA_VIC
166         [TEGRA_POWERGATE_VIC] = {
167                 .hot_reset_clients = {
168                         [0] = MC_CLIENT_VIC,
169                         [1] = MC_CLIENT_LAST,
170                 },
171         },
172 #endif
173 };
174
175 static struct powergate_partition_info tegra12x_powergate_partition_info[] = {
176         [TEGRA_POWERGATE_CRAIL] = { .name = "crail" },
177         [TEGRA_POWERGATE_GPU] = {
178                 .name = "gpu",
179                 .clk_info = {
180                         [0] = { .clk_name = "gpu_ref", .clk_type = CLK_AND_RST },
181                         [1] = { .clk_name = "pll_p_out5", .clk_type = CLK_ONLY },
182                 },
183         },
184         [TEGRA_POWERGATE_VDEC] = {
185                 .name = "vde",
186                 .clk_info = {
187                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
188                 },
189         },
190         [TEGRA_POWERGATE_MPE] = {
191                 .name = "mpe",
192                 .clk_info = {
193                         [0] = { .clk_name = "msenc.cbus", .clk_type = CLK_AND_RST },
194                 },
195         },
196         [TEGRA_POWERGATE_VENC] = {
197                 .name = "ve",
198                 .clk_info = {
199                         [0] = { .clk_name = "ispa", .clk_type = CLK_AND_RST },
200                         [1] = { .clk_name = "ispb", .clk_type = CLK_AND_RST },
201                         [2] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
202                         [3] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
203                 },
204         },
205         [TEGRA_POWERGATE_CPU1] = { .name = "cpu1" },
206         [TEGRA_POWERGATE_CPU2] = { .name = "cpu2" },
207         [TEGRA_POWERGATE_CPU3] = { .name = "cpu3" },
208         [TEGRA_POWERGATE_CELP] = { .name = "celp" },
209         [TEGRA_POWERGATE_CPU0] = { .name = "cpu0" },
210         [TEGRA_POWERGATE_C0NC] = { .name = "c0nc" },
211         [TEGRA_POWERGATE_C1NC] = { .name = "c1nc" },
212         [TEGRA_POWERGATE_DISA] = {
213                 .name = "disa",
214                 .clk_info = {
215                         [0] = { .clk_name = "disp1", .clk_type = CLK_AND_RST },
216                 },
217         },
218         [TEGRA_POWERGATE_DISB] = {
219                 .name = "disb",
220                 .clk_info = {
221                         [0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
222                 },
223         },
224         [TEGRA_POWERGATE_XUSBA] = {
225                 .name = "xusba",
226                 .clk_info = {
227                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_AND_RST },
228                 },
229         },
230         [TEGRA_POWERGATE_XUSBB] = {
231                 .name = "xusbb",
232                 .clk_info = {
233                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_AND_RST },
234                 },
235         },
236         [TEGRA_POWERGATE_XUSBC] = {
237                 .name = "xusbc",
238                 .clk_info = {
239                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_AND_RST },
240                 },
241         },
242 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
243         [TEGRA_POWERGATE_PCIE] = {
244                 .name = "pcie",
245                 .clk_info = {
246                         [0] = { .clk_name = "afi", .clk_type = CLK_AND_RST },
247                         [1] = { .clk_name = "pcie", .clk_type = CLK_AND_RST },
248                         [2] = { .clk_name = "cml0", .clk_type = CLK_ONLY },
249                         [3] = { .clk_name = "pciex", .clk_type = RST_ONLY },
250                 },
251         },
252 #endif
253 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
254         [TEGRA_POWERGATE_SATA] = {
255                 .name = "sata",
256                 .clk_info = {
257                         [0] = { .clk_name = "sata", .clk_type = CLK_AND_RST },
258                         [1] = { .clk_name = "sata_oob", .clk_type = CLK_AND_RST },
259                         [2] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
260                         [3] = { .clk_name = "sata_cold", .clk_type = RST_ONLY },
261                 },
262         },
263 #endif
264         [TEGRA_POWERGATE_SOR] = {
265                 .name = "sor",
266                 .clk_info = {
267                         [0] = { .clk_name = "sor0", .clk_type = CLK_AND_RST },
268                         [1] = { .clk_name = "dsia", .clk_type = CLK_AND_RST },
269                         [2] = { .clk_name = "dsib", .clk_type = CLK_AND_RST },
270                         [3] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
271                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
272                         [5] = { .clk_name = "dpaux", .clk_type = CLK_ONLY },
273                 },
274         },
275 #ifdef CONFIG_ARCH_TEGRA_VIC
276         [TEGRA_POWERGATE_VIC] = {
277                 .name = "vic",
278                 .clk_info = {
279                         [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_AND_RST },
280                 },
281         },
282 #endif
283 };
284
285 #define MC_CLIENT_HOTRESET_CTRL         0x200
286 #define MC_CLIENT_HOTRESET_STAT         0x204
287 #define MC_CLIENT_HOTRESET_CTRL_1       0x970
288 #define MC_CLIENT_HOTRESET_STAT_1       0x974
289 #define MC_VIDEO_PROTECT_REG_CTRL       0x650
290
291 #define PMC_GPU_RG_CNTRL_0              0x2d4
292
293 static DEFINE_SPINLOCK(tegra12x_powergate_lock);
294
295 static struct dvfs_rail *gpu_rail;
296
297 #define HOTRESET_READ_COUNT     5
298 static bool tegra12x_stable_hotreset_check(u32 stat_reg, u32 *stat)
299 {
300         int i;
301         u32 cur_stat;
302         u32 prv_stat;
303         unsigned long flags;
304
305         spin_lock_irqsave(&tegra12x_powergate_lock, flags);
306         prv_stat = mc_read(stat_reg);
307         for (i = 0; i < HOTRESET_READ_COUNT; i++) {
308                 cur_stat = mc_read(stat_reg);
309                 if (cur_stat != prv_stat) {
310                         spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
311                         return false;
312                 }
313         }
314         *stat = cur_stat;
315         spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
316         return true;
317 }
318
319 int tegra12x_powergate_mc_enable(int id)
320 {
321         return 0;
322 }
323
324 int tegra12x_powergate_mc_disable(int id)
325 {
326         return 0;
327 }
328
329 int tegra12x_powergate_mc_flush(int id)
330 {
331         u32 idx, rst_ctrl, rst_stat;
332         u32 rst_ctrl_reg, rst_stat_reg;
333         enum mc_client mcClientBit;
334         unsigned long flags;
335         bool ret;
336
337         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
338                 mcClientBit =
339                         tegra12x_pg_mc_info[id].hot_reset_clients[idx];
340                 if (mcClientBit == MC_CLIENT_LAST)
341                         break;
342
343                 if (mcClientBit < 32) {
344                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
345                         rst_stat_reg = MC_CLIENT_HOTRESET_STAT;
346                 } else {
347                         mcClientBit %= 32;
348                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
349                         rst_stat_reg = MC_CLIENT_HOTRESET_STAT_1;
350                 }
351
352                 spin_lock_irqsave(&tegra12x_powergate_lock, flags);
353
354                 rst_ctrl = mc_read(rst_ctrl_reg);
355                 rst_ctrl |= (1 << mcClientBit);
356                 mc_write(rst_ctrl, rst_ctrl_reg);
357
358                 spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
359
360                 do {
361                         udelay(10);
362                         rst_stat = 0;
363                         ret = tegra12x_stable_hotreset_check(rst_stat_reg, &rst_stat);
364                         if (!ret)
365                                 continue;
366                 } while (!(rst_stat & (1 << mcClientBit)));
367         }
368
369         return 0;
370 }
371
372 int tegra12x_powergate_mc_flush_done(int id)
373 {
374         u32 idx, rst_ctrl, rst_ctrl_reg;
375         enum mc_client mcClientBit;
376         unsigned long flags;
377
378         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
379                 mcClientBit =
380                         tegra12x_pg_mc_info[id].hot_reset_clients[idx];
381                 if (mcClientBit == MC_CLIENT_LAST)
382                         break;
383
384                 if (mcClientBit < 32)
385                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL;
386                 else {
387                         mcClientBit %= 32;
388                         rst_ctrl_reg = MC_CLIENT_HOTRESET_CTRL_1;
389                 }
390
391                 spin_lock_irqsave(&tegra12x_powergate_lock, flags);
392
393                 rst_ctrl = mc_read(rst_ctrl_reg);
394                 rst_ctrl &= ~(1 << mcClientBit);
395                 mc_write(rst_ctrl, rst_ctrl_reg);
396
397                 spin_unlock_irqrestore(&tegra12x_powergate_lock, flags);
398         }
399
400         wmb();
401
402         return 0;
403 }
404
405 static int tegra12x_gpu_powergate(int id, struct powergate_partition_info *pg_info)
406 {
407         int ret;
408
409         /* If first clk_ptr is null, fill clk info for the partition */
410         if (!pg_info->clk_info[0].clk_ptr)
411                 get_clk_info(pg_info);
412
413         tegra_powergate_mc_flush(id);
414
415         udelay(10);
416
417         /* enable clamp */
418         pmc_write(0x1, PMC_GPU_RG_CNTRL_0);
419
420         udelay(10);
421
422         powergate_partition_assert_reset(pg_info);
423
424         udelay(10);
425
426         /*
427          * GPCPLL is already disabled before entering this function; reference
428          * clocks are enabled until now - disable them just before rail gating
429          */
430         partition_clk_disable(pg_info);
431
432         udelay(10);
433
434         if (gpu_rail && tegra_powergate_is_powered(id)) {
435                 ret = tegra_dvfs_rail_power_down(gpu_rail);
436                 if (ret)
437                         goto err_power_off;
438         } else
439                 pr_info("No GPU regulator?\n");
440
441         return 0;
442
443 err_power_off:
444         WARN(1, "Could not Railgate Partition %d", id);
445         return ret;
446 }
447
448 static int mc_check_vpr(void)
449 {
450         int ret = 0;
451         u32 val = mc_read(MC_VIDEO_PROTECT_REG_CTRL);
452         if ((val & 1) == 0) {
453                 pr_err("VPR configuration not locked down\n");
454                 ret = -EINVAL;
455         }
456         return ret;
457 }
458
459 static int tegra12x_gpu_unpowergate(int id,
460         struct powergate_partition_info *pg_info)
461 {
462         int ret = 0;
463         bool first = false;
464
465         ret = mc_check_vpr();
466         if (ret)
467                 return ret;
468
469         if (!gpu_rail) {
470                 gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu");
471                 if (IS_ERR_OR_NULL(gpu_rail)) {
472                         WARN(1, "No GPU regulator?\n");
473                         goto err_power;
474                 }
475                 first = true;
476         } else {
477                 ret = tegra_dvfs_rail_power_up(gpu_rail);
478                 if (ret)
479                         goto err_power;
480         }
481
482         /* If first clk_ptr is null, fill clk info for the partition */
483         if (!pg_info->clk_info[0].clk_ptr)
484                 get_clk_info(pg_info);
485
486         /*
487          * GPU reference clocks are initially enabled - skip clock enable if
488          * 1st unpowergate, and in any case leave reference clock enabled on
489          * exit. GPCPLL is still disabled, and will be enabled by driver.
490          */
491         if (!first) {
492                 /* Un-Powergating fails if all clks are not enabled */
493                 ret = partition_clk_enable(pg_info);
494                 if (ret)
495                         goto err_clk_on;
496         }
497
498         udelay(10);
499
500         powergate_partition_assert_reset(pg_info);
501
502         udelay(10);
503
504         /* disable clamp */
505         pmc_write(0, PMC_GPU_RG_CNTRL_0);
506
507         udelay(10);
508
509         powergate_partition_deassert_reset(pg_info);
510
511         udelay(10);
512
513         tegra_powergate_mc_flush_done(id);
514
515         udelay(10);
516
517         return 0;
518
519 err_clk_on:
520         powergate_module(id);
521 err_power:
522         WARN(1, "Could not Un-Railgate %d", id);
523         return ret;
524 }
525
526 static atomic_t ref_count_dispa = ATOMIC_INIT(0);
527 static atomic_t ref_count_dispb = ATOMIC_INIT(0);
528 static atomic_t ref_count_venc = ATOMIC_INIT(0);
529
530 #define CHECK_RET(x)                    \
531         do {                            \
532                 ret = (x);              \
533                 if (ret != 0)           \
534                         return ret;     \
535         } while (0)
536
537
538 static inline int tegra12x_powergate(int id)
539 {
540         if (tegra_powergate_is_powered(id))
541                 return tegra1xx_powergate(id,
542                         &tegra12x_powergate_partition_info[id]);
543         return 0;
544 }
545
546 static inline int tegra12x_unpowergate(int id)
547 {
548         if (!tegra_powergate_is_powered(id))
549                 return tegra1xx_unpowergate(id,
550                         &tegra12x_powergate_partition_info[id]);
551         return 0;
552 }
553
554 static int tegra12x_disp_powergate(int id)
555 {
556         int ret = 0;
557         int ref_counta = atomic_read(&ref_count_dispa);
558         int ref_countb = atomic_read(&ref_count_dispb);
559         int ref_countve = atomic_read(&ref_count_venc);
560
561         if (id == TEGRA_POWERGATE_DISA) {
562                 ref_counta = atomic_dec_return(&ref_count_dispa);
563                 WARN_ONCE(ref_counta < 0, "DISPA ref count underflow");
564         } else if (id == TEGRA_POWERGATE_DISB) {
565                 if (ref_countb > 0)
566                         ref_countb = atomic_dec_return(&ref_count_dispb);
567                 if (ref_countb <= 0)
568                         CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_DISB));
569         }
570
571         if ((ref_counta <= 0) && (ref_countb <= 0) && (ref_countve <= 0)) {
572                 CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_SOR));
573                 CHECK_RET(tegra12x_powergate(TEGRA_POWERGATE_DISA));
574         }
575         return ret;
576 }
577
578 static int tegra12x_disp_unpowergate(int id)
579 {
580         int ret;
581
582         /* always unpowergate dispA and SOR partition */
583         CHECK_RET(tegra12x_unpowergate(TEGRA_POWERGATE_DISA));
584         CHECK_RET(tegra12x_unpowergate(TEGRA_POWERGATE_SOR));
585
586         if (id == TEGRA_POWERGATE_DISA)
587                 atomic_inc(&ref_count_dispa);
588         else if (id == TEGRA_POWERGATE_DISB) {
589                 atomic_inc(&ref_count_dispb);
590                 ret = tegra12x_unpowergate(TEGRA_POWERGATE_DISB);
591         }
592
593         return ret;
594 }
595
596 static int tegra12x_venc_powergate(int id)
597 {
598         int ret = 0;
599         int ref_count = atomic_read(&ref_count_venc);
600
601         if (!TEGRA_IS_VENC_POWERGATE_ID(id))
602                 return -EINVAL;
603
604         ref_count = atomic_dec_return(&ref_count_venc);
605
606         if (ref_count > 0)
607                 return ret;
608
609         if (ref_count <= 0) {
610                 CHECK_RET(tegra12x_powergate(id));
611                 CHECK_RET(tegra12x_disp_powergate(id));
612         }
613
614         return ret;
615 }
616
617 static int tegra12x_venc_unpowergate(int id)
618 {
619         int ret = 0;
620
621         if (!TEGRA_IS_VENC_POWERGATE_ID(id))
622                 return -EINVAL;
623
624         CHECK_RET(tegra12x_disp_unpowergate(id));
625
626         atomic_inc(&ref_count_venc);
627         CHECK_RET(tegra12x_unpowergate(id));
628
629         return ret;
630 }
631
632 int tegra12x_powergate_partition(int id)
633 {
634         int ret;
635
636         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
637                 ret = tegra12x_gpu_powergate(id,
638                         &tegra12x_powergate_partition_info[id]);
639         } else if (TEGRA_IS_DISP_POWERGATE_ID(id))
640                 ret = tegra12x_disp_powergate(id);
641         else if (id == TEGRA_POWERGATE_CRAIL)
642                 ret = tegra_powergate_set(id, false);
643         else if (id == TEGRA_POWERGATE_VENC)
644                 ret = tegra12x_venc_powergate(id);
645         else {
646                 /* call common power-gate API for t1xx */
647                 ret = tegra1xx_powergate(id,
648                         &tegra12x_powergate_partition_info[id]);
649         }
650
651         return ret;
652 }
653
654 int tegra12x_unpowergate_partition(int id)
655 {
656         int ret;
657
658         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
659                 ret = tegra12x_gpu_unpowergate(id,
660                         &tegra12x_powergate_partition_info[id]);
661         } else if (TEGRA_IS_DISP_POWERGATE_ID(id))
662                 ret = tegra12x_disp_unpowergate(id);
663         else if (id == TEGRA_POWERGATE_CRAIL)
664                 ret = tegra_powergate_set(id, true);
665         else if (id == TEGRA_POWERGATE_VENC)
666                 ret = tegra12x_venc_unpowergate(id);
667         else {
668                 ret = tegra1xx_unpowergate(id,
669                         &tegra12x_powergate_partition_info[id]);
670         }
671
672         return ret;
673 }
674
675 int tegra12x_powergate_partition_with_clk_off(int id)
676 {
677         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
678
679         return tegraxx_powergate_partition_with_clk_off(id,
680                 &tegra12x_powergate_partition_info[id]);
681 }
682
683 int tegra12x_unpowergate_partition_with_clk_on(int id)
684 {
685         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
686
687         return tegraxx_unpowergate_partition_with_clk_on(id,
688                 &tegra12x_powergate_partition_info[id]);
689 }
690
691 const char *tegra12x_get_powergate_domain_name(int id)
692 {
693         return tegra12x_powergate_partition_info[id].name;
694 }
695
696 spinlock_t *tegra12x_get_powergate_lock(void)
697 {
698         return &tegra12x_powergate_lock;
699 }
700
701 bool tegra12x_powergate_skip(int id)
702 {
703         switch (id) {
704 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
705         case TEGRA_POWERGATE_SATA:
706 #endif
707                 return true;
708
709         default:
710                 return false;
711         }
712 }
713
714 bool tegra12x_powergate_is_powered(int id)
715 {
716         u32 status = 0;
717
718         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
719                 if (gpu_rail)
720                         return tegra_dvfs_is_rail_up(gpu_rail);
721         } else {
722                 status = pmc_read(PWRGATE_STATUS) & (1 << id);
723                 return !!status;
724         }
725         return status;
726 }
727
728 static struct powergate_ops tegra12x_powergate_ops = {
729         .soc_name = "tegra12x",
730
731         .num_powerdomains = TEGRA_NUM_POWERGATE,
732
733         .get_powergate_lock = tegra12x_get_powergate_lock,
734         .get_powergate_domain_name = tegra12x_get_powergate_domain_name,
735
736         .powergate_partition = tegra12x_powergate_partition,
737         .unpowergate_partition = tegra12x_unpowergate_partition,
738
739         .powergate_partition_with_clk_off =  tegra12x_powergate_partition_with_clk_off,
740         .unpowergate_partition_with_clk_on = tegra12x_unpowergate_partition_with_clk_on,
741
742         .powergate_mc_enable = tegra12x_powergate_mc_enable,
743         .powergate_mc_disable = tegra12x_powergate_mc_disable,
744
745         .powergate_mc_flush = tegra12x_powergate_mc_flush,
746         .powergate_mc_flush_done = tegra12x_powergate_mc_flush_done,
747
748         .powergate_skip = tegra12x_powergate_skip,
749
750         .powergate_is_powered = tegra12x_powergate_is_powered,
751 };
752
753 struct powergate_ops *tegra12x_powergate_init_chip_support(void)
754 {
755         if (tegra_powergate_is_powered(TEGRA_POWERGATE_VENC))
756                 atomic_set(&ref_count_venc, 1);
757
758         return &tegra12x_powergate_ops;
759 }