ARM: tegra: add clamping status read.
[linux-3.10.git] / arch / arm / mach-tegra / powergate-t11x.c
1 /*
2  * Copyright (c) 2012, 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
18 #include <asm/atomic.h>
19
20 #include <mach/powergate.h>
21
22 #include "powergate-priv.h"
23 #include "powergate-ops-txx.h"
24 #include "powergate-ops-t1xx.h"
25
26 enum mc_client {
27         MC_CLIENT_AVPC          = 1,
28         MC_CLIENT_DC            = 2,
29         MC_CLIENT_DCB           = 3,
30         MC_CLIENT_EPP           = 4,
31         MC_CLIENT_G2            = 5,
32         MC_CLIENT_HC            = 6,
33         MC_CLIENT_HDA           = 7,
34         MC_CLIENT_ISP           = 8,
35         MC_CLIENT_MPCORE        = 9,
36         MC_CLIENT_MPCORELP      = 10,
37         MC_CLIENT_MSENC         = 11,
38         MC_CLIENT_NV            = 12,
39         MC_CLIENT_PPCS          = 14,
40         MC_CLIENT_VDE           = 16,
41         MC_CLIENT_VI            = 17,
42         MC_CLIENT_XUSB_HOST     = 19,
43         MC_CLIENT_XUSB_DEV      = 20,
44         MC_CLIENT_EMUCIF        = 21,
45         MC_CLIENT_TSEC          = 22,
46         MC_CLIENT_LAST          = -1,
47         MC_CLIENT_AFI           = MC_CLIENT_LAST,
48         MC_CLIENT_MPE           = MC_CLIENT_LAST,
49         MC_CLIENT_NV2           = MC_CLIENT_LAST,
50         MC_CLIENT_SATA          = MC_CLIENT_LAST,
51 };
52
53 struct tegra11x_powergate_mc_client_info {
54         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
55 };
56
57 static struct tegra11x_powergate_mc_client_info tegra11x_pg_mc_info[] = {
58         [TEGRA_POWERGATE_CRAIL] = {
59                 .hot_reset_clients = {
60                         [0] = MC_CLIENT_LAST,
61                 },
62         },
63         [TEGRA_POWERGATE_3D] = {
64                 .hot_reset_clients = {
65                         [0] = MC_CLIENT_NV,
66                         [1] = MC_CLIENT_LAST,
67                 },
68         },
69         [TEGRA_POWERGATE_VDEC] = {
70                 .hot_reset_clients = {
71                         [0] = MC_CLIENT_VDE,
72                         [1] = MC_CLIENT_LAST,
73                 },
74         },
75         [TEGRA_POWERGATE_MPE] = {
76                 .hot_reset_clients = {
77                         [0] = MC_CLIENT_MSENC,
78                         [1] = MC_CLIENT_LAST,
79                 },
80         },
81         [TEGRA_POWERGATE_VENC] = {
82                 .hot_reset_clients = {
83                         [0] = MC_CLIENT_ISP,
84                         [1] = MC_CLIENT_VI,
85                         [2] = MC_CLIENT_LAST,
86                 },
87         },
88         [TEGRA_POWERGATE_HEG] = {
89                 .hot_reset_clients = {
90                         [0] = MC_CLIENT_G2,
91                         [1] = MC_CLIENT_EPP,
92                         [2] = MC_CLIENT_LAST,
93                 },
94         },
95         [TEGRA_POWERGATE_CPU1] = {
96                 .hot_reset_clients = {
97                         [0] = MC_CLIENT_LAST,
98                 },
99         },
100         [TEGRA_POWERGATE_CPU2] = {
101                 .hot_reset_clients = {
102                         [0] = MC_CLIENT_LAST,
103                 },
104         },
105         [TEGRA_POWERGATE_CPU3] = {
106                 .hot_reset_clients = {
107                         [0] = MC_CLIENT_LAST,
108                 },
109         },
110         [TEGRA_POWERGATE_CELP] = {
111                 .hot_reset_clients = {
112                         [0] = MC_CLIENT_LAST,
113                 },
114         },
115         [TEGRA_POWERGATE_CPU0] = {
116                 .hot_reset_clients = {
117                         [0] = MC_CLIENT_LAST,
118                 },
119         },
120         [TEGRA_POWERGATE_C0NC] = {
121                 .hot_reset_clients = {
122                         [0] = MC_CLIENT_LAST,
123                 },
124         },
125         [TEGRA_POWERGATE_C1NC] = {
126                 .hot_reset_clients = {
127                         [0] = MC_CLIENT_LAST,
128                 },
129         },
130         [TEGRA_POWERGATE_DISA] = {
131                 .hot_reset_clients = {
132                         [0] = MC_CLIENT_DC,
133                         [1] = MC_CLIENT_LAST,
134                 },
135         },
136         [TEGRA_POWERGATE_DISB] = {
137                 .hot_reset_clients = {
138                         [0] = MC_CLIENT_DCB,
139                         [1] = MC_CLIENT_LAST,
140                 },
141         },
142         [TEGRA_POWERGATE_XUSBA] = {
143                 .hot_reset_clients = {
144                         [0] = MC_CLIENT_LAST,
145                 },
146         },
147         [TEGRA_POWERGATE_XUSBB] = {
148                 .hot_reset_clients = {
149                         [0] = MC_CLIENT_XUSB_DEV,
150                         [1] = MC_CLIENT_LAST
151                 },
152         },
153         [TEGRA_POWERGATE_XUSBC] = {
154                 .hot_reset_clients = {
155                         [0] = MC_CLIENT_XUSB_HOST,
156                         [1] = MC_CLIENT_LAST,
157                 },
158         },
159 };
160
161 static struct powergate_partition_info tegra11x_powergate_partition_info[] = {
162         [TEGRA_POWERGATE_CRAIL] = { .name = "crail" },
163         [TEGRA_POWERGATE_3D] = {
164                 .name = "3d",
165                 .clk_info = {
166                         [0] = { .clk_name = "3d", .clk_type = CLK_AND_RST },
167                 },
168         },
169         [TEGRA_POWERGATE_VDEC] = {
170                 .name = "vde",
171                 .clk_info = {
172                         [0] = { .clk_name = "vde", .clk_type = CLK_AND_RST },
173                 },
174         },
175         [TEGRA_POWERGATE_MPE] = {
176                 .name = "mpe",
177                 .clk_info = {
178                         [0] = { .clk_name = "msenc.cbus", .clk_type = CLK_AND_RST },
179                 },
180         },
181         [TEGRA_POWERGATE_VENC] = {
182                 .name = "ve",
183                 .clk_info = {
184                         [0] = { .clk_name = "isp", .clk_type = CLK_AND_RST },
185                         [1] = { .clk_name = "vi", .clk_type = CLK_AND_RST },
186                         [2] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
187                 },
188         },
189         [TEGRA_POWERGATE_HEG] = {
190                 .name = "heg",
191                 .clk_info = {
192                         [0] = { .clk_name = "2d.cbus", .clk_type = CLK_AND_RST },
193                         [1] = { .clk_name = "epp.cbus", .clk_type = CLK_AND_RST },
194                 },
195         },
196         [TEGRA_POWERGATE_CPU1] = { .name = "cpu1" },
197         [TEGRA_POWERGATE_CPU2] = { .name = "cpu2" },
198         [TEGRA_POWERGATE_CPU3] = { .name = "cpu3" },
199         [TEGRA_POWERGATE_CELP] = { .name = "celp" },
200         [TEGRA_POWERGATE_CPU0] = { .name = "cpu0" },
201         [TEGRA_POWERGATE_C0NC] = { .name = "c0nc" },
202         [TEGRA_POWERGATE_C1NC] = { .name = "c1nc" },
203         [TEGRA_POWERGATE_DISA] = {
204                 .name = "disa",
205                 .clk_info = {
206                         [0] = { .clk_name = "disp1", .clk_type = CLK_AND_RST },
207                         [1] = { .clk_name = "dsia", .clk_type = CLK_AND_RST },
208                         [2] = { .clk_name = "dsib", .clk_type = CLK_AND_RST },
209                         [3] = { .clk_name = "csi", .clk_type = CLK_AND_RST },
210                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_AND_RST },
211                 },
212         },
213         [TEGRA_POWERGATE_DISB] = {
214                 .name = "disb",
215                 .clk_info = {
216                         [0] = { .clk_name = "disp2", .clk_type = CLK_AND_RST },
217                         [1] = { .clk_name = "hdmi", .clk_type = CLK_AND_RST },
218                 },
219         },
220         [TEGRA_POWERGATE_XUSBA] = {
221                 .name = "xusba",
222                 .clk_info = {
223                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_AND_RST },
224                 },
225         },
226         [TEGRA_POWERGATE_XUSBB] = {
227                 .name = "xusbb",
228                 .clk_info = {
229                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_AND_RST },
230                 },
231         },
232         [TEGRA_POWERGATE_XUSBC] = {
233                 .name = "xusbc",
234                 .clk_info = {
235                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_AND_RST },
236                 },
237         },
238 };
239
240 static atomic_t ref_count_a = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISA */
241 static atomic_t ref_count_b = ATOMIC_INIT(1); /* for TEGRA_POWERGATE_DISB */
242
243 static void __iomem *mipi_cal = IO_ADDRESS(TEGRA_MIPI_CAL_BASE);
244 static u32 mipi_cal_read(unsigned long reg)
245 {
246         return readl(mipi_cal + reg);
247 }
248
249 static void mipi_cal_write(u32 val, unsigned long reg)
250 {
251         writel_relaxed(val, mipi_cal + reg);
252 }
253
254 #define MC_CLIENT_HOTRESET_CTRL         0x200
255 #define MC_CLIENT_HOTRESET_STAT         0x204
256
257 static DEFINE_SPINLOCK(tegra11x_powergate_lock);
258
259 /* Forward Declarations */
260 int tegra11x_powergate_mc_flush(int id);
261 int tegra11x_powergate_mc_flush_done(int id);
262 int tegra11x_unpowergate_partition_with_clk_on(int id);
263 int tegra11x_powergate_partition_with_clk_off(int id);
264
265 bool tegra11x_powergate_check_clamping(int id)
266 {
267         u32 mask;
268         /*
269          * PCIE and VDE clamping masks are swapped with respect to their
270          * partition ids
271          */
272         if (id ==  TEGRA_POWERGATE_VDEC)
273                 mask = (1 << TEGRA_POWERGATE_PCIE);
274         else if (id == TEGRA_POWERGATE_PCIE)
275                 mask = (1 << TEGRA_POWERGATE_VDEC);
276         else
277                 mask = (1 << id);
278
279         return !!(pmc_read(PWRGATE_CLAMP_STATUS) & mask);
280 }
281
282 #define HOTRESET_READ_COUNT     5
283 static bool tegra11x_stable_hotreset_check(u32 *stat)
284 {
285         int i;
286         u32 cur_stat;
287         u32 prv_stat;
288         unsigned long flags;
289
290         spin_lock_irqsave(&tegra11x_powergate_lock, flags);
291         prv_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
292         for (i = 0; i < HOTRESET_READ_COUNT; i++) {
293                 cur_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
294                 if (cur_stat != prv_stat) {
295                         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
296                         return false;
297                 }
298         }
299         *stat = cur_stat;
300         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
301         return true;
302 }
303
304 /*
305  * FIXME: sw war for mipi-cal calibration when unpowergating DISA partition
306  */
307 static void tegra11x_mipical_calibrate(int id)
308 {
309         struct reg_offset_val {
310                 u32 offset;
311                 u32 por_value;
312         };
313         u32 status;
314         unsigned long flags;
315
316 #define MIPI_CAL_MIPI_CAL_CTRL_0                0x0
317 #define MIPI_CAL_CIL_MIPI_CAL_STATUS_0          0x8
318 #define MIPI_CAL_CILA_MIPI_CAL_CONFIG_0         0x14
319 #define MIPI_CAL_CILB_MIPI_CAL_CONFIG_0         0x18
320 #define MIPI_CAL_CILC_MIPI_CAL_CONFIG_0         0x1c
321 #define MIPI_CAL_CILD_MIPI_CAL_CONFIG_0         0x20
322 #define MIPI_CAL_CILE_MIPI_CAL_CONFIG_0         0x24
323 #define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0         0x38
324 #define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0         0x3c
325 #define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0         0x40
326 #define MIPI_CAL_DSID_MIPI_CAL_CONFIG_0         0x44
327
328         static struct reg_offset_val mipi_cal_por_values[] = {
329                 { MIPI_CAL_MIPI_CAL_CTRL_0, 0x2a000000 },
330                 { MIPI_CAL_CILA_MIPI_CAL_CONFIG_0, 0x00200000 },
331                 { MIPI_CAL_CILB_MIPI_CAL_CONFIG_0, 0x00200000 },
332                 { MIPI_CAL_CILC_MIPI_CAL_CONFIG_0, 0x00200000 },
333                 { MIPI_CAL_CILD_MIPI_CAL_CONFIG_0, 0x00200000 },
334                 { MIPI_CAL_CILE_MIPI_CAL_CONFIG_0, 0x00000000 },
335                 { MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0, 0x00200000 },
336                 { MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0, 0x00200000 },
337                 { MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0, 0x00200000 },
338                 { MIPI_CAL_DSID_MIPI_CAL_CONFIG_0, 0x00200000 },
339         };
340         int i;
341
342         if (id != TEGRA_POWERGATE_DISA)
343                 return;
344
345         spin_lock_irqsave(&tegra11x_powergate_lock, flags);
346
347         /* mipi cal por restore */
348         for (i = 0; i < ARRAY_SIZE(mipi_cal_por_values); i++) {
349                 mipi_cal_write(mipi_cal_por_values[i].por_value,
350                         mipi_cal_por_values[i].offset);
351         }
352
353         /* mipi cal status clear */
354         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
355         mipi_cal_write(status, MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
356
357         /* mipi cal status read - to flush writes */
358         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
359
360         spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
361 }
362
363 static int tegra11x_powergate_partition_internal(int id,
364         struct powergate_partition_info *pg_info)
365 {
366         int ret;
367
368         if (tegra_powergate_is_powered(id)) {
369                 ret = is_partition_clk_disabled(pg_info);
370                 if (ret < 0) {
371                         /* clock enabled */
372                         ret = tegra11x_powergate_partition_with_clk_off(id);
373                         if (ret < 0)
374                                 return ret;
375                 } else {
376                         ret = tegra_powergate_partition(id);
377                         if (ret < 0)
378                                 return ret;
379                 }
380         }
381         return 0;
382 }
383
384 static int tegra11x_unpowergate_partition_internal(int id,
385         struct powergate_partition_info *pg_info)
386 {
387         int ret;
388
389         if (!tegra_powergate_is_powered(id)) {
390                 ret = is_partition_clk_disabled(pg_info);
391                 if (ret) {
392                         /* clock disabled */
393                         ret = tegra11x_unpowergate_partition_with_clk_on(id);
394                         if (ret < 0)
395                                 return ret;
396                 } else {
397                         ret = tegra_unpowergate_partition(id);
398                         if (ret < 0)
399                                 return ret;
400                 }
401         }
402         return 0;
403 }
404
405 /*
406  * Tegra11x has powergate dependencies between partitions.
407  * This function captures the dependencies.
408  */
409 static int tegra11x_check_partition_pg_seq(int id,
410         struct powergate_partition_info *pg_info)
411 {
412         int ret;
413
414         if (id == TEGRA_POWERGATE_DISA) {
415                 ret = tegra11x_powergate_partition_internal(TEGRA_POWERGATE_VENC,
416                         pg_info);
417                 if (ret < 0)
418                         return ret;
419
420                 ret = tegra11x_powergate_partition_internal(TEGRA_POWERGATE_DISB,
421                         pg_info);
422                 if (ret < 0)
423                         return ret;
424         }
425
426         return 0;
427 }
428
429 /*
430  * This function captures power-ungate dependencies between tegra11x partitions
431  */
432 static int tegra11x_check_partition_pug_seq(int id,
433         struct powergate_partition_info *pg_info)
434 {
435         int ret;
436
437         switch (id) {
438         case TEGRA_POWERGATE_DISB:
439         case TEGRA_POWERGATE_VENC:
440                 ret = tegra11x_unpowergate_partition_internal(TEGRA_POWERGATE_DISA,
441                         pg_info);
442                 if (ret < 0)
443                         return ret;
444
445                 break;
446         }
447         return 0;
448 }
449
450 int tegra11x_powergate_mc_enable(int id)
451 {
452         return 0;
453 }
454
455 int tegra11x_powergate_mc_disable(int id)
456 {
457         return 0;
458 }
459
460 int tegra11x_powergate_mc_flush(int id)
461 {
462         u32 idx, rst_ctrl, rst_stat;
463         enum mc_client mcClientBit;
464         unsigned long flags;
465         bool ret;
466
467         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
468                 mcClientBit =
469                         tegra11x_pg_mc_info[id].hot_reset_clients[idx];
470                 if (mcClientBit == MC_CLIENT_LAST)
471                         break;
472
473                 spin_lock_irqsave(&tegra11x_powergate_lock, flags);
474                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
475                 rst_ctrl |= (1 << mcClientBit);
476                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
477
478                 spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
479
480                 do {
481                         udelay(10);
482                         rst_stat = 0;
483                         ret = tegra11x_stable_hotreset_check(&rst_stat);
484                         if (!ret)
485                                 continue;
486                 } while (!(rst_stat & (1 << mcClientBit)));
487         }
488
489         return 0;
490 }
491
492 int tegra11x_powergate_mc_flush_done(int id)
493 {
494         u32 idx, rst_ctrl;
495         enum mc_client mcClientBit;
496         unsigned long flags;
497
498         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
499                 mcClientBit =
500                         tegra11x_pg_mc_info[id].hot_reset_clients[idx];
501                 if (mcClientBit == MC_CLIENT_LAST)
502                         break;
503
504                 spin_lock_irqsave(&tegra11x_powergate_lock, flags);
505
506                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
507                 rst_ctrl &= ~(1 << mcClientBit);
508                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
509
510                 spin_unlock_irqrestore(&tegra11x_powergate_lock, flags);
511         }
512
513         wmb();
514
515         return 0;
516 }
517
518 static int tegra11x_unpowergate(int id,
519         struct powergate_partition_info *pg_info)
520 {
521         int ret;
522
523         /* If first clk_ptr is null, fill clk info for the partition */
524         if (!pg_info->clk_info[0].clk_ptr)
525                 get_clk_info(pg_info);
526
527         if (tegra_powergate_is_powered(id))
528                 return tegra_powergate_reset_module(pg_info);
529
530         ret = tegra_powergate_set(id, true);
531         if (ret)
532                 goto err_power;
533
534         udelay(10);
535
536         /* Un-Powergating fails if all clks are not enabled */
537         ret = partition_clk_enable(pg_info);
538         if (ret)
539                 goto err_clk_on;
540
541         udelay(10);
542
543         ret = tegra_powergate_remove_clamping(id);
544         if (ret)
545                 goto err_clamp;
546
547         udelay(10);
548
549         tegra11x_mipical_calibrate(id);
550
551         powergate_partition_deassert_reset(pg_info);
552
553         udelay(10);
554
555         tegra_powergate_mc_flush_done(id);
556
557         udelay(10);
558
559         /* Disable all clks enabled earlier. Drivers should enable clks */
560         partition_clk_disable(pg_info);
561
562         return 0;
563
564 err_clamp:
565         partition_clk_disable(pg_info);
566 err_clk_on:
567         powergate_module(id);
568 err_power:
569         WARN(1, "Could not Un-Powergate %d", id);
570         return ret;
571 }
572
573 void tegra11x_powergate_dis_partition(void)
574 {
575         tegra1xx_powergate(TEGRA_POWERGATE_DISB,
576                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISB]);
577
578         tegra11x_powergate_partition_internal(TEGRA_POWERGATE_VENC,
579                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISA]);
580
581         tegra1xx_powergate(TEGRA_POWERGATE_DISA,
582                 &tegra11x_powergate_partition_info[TEGRA_POWERGATE_DISA]);
583 }
584
585 /* The logic manages the ref-count for dis partitions. The dependency between
586  * disa and disb is hided from client. */
587 bool tegra11x_powergate_check_dis_refcount(int id, int op)
588 {
589         WARN_ONCE(atomic_read(&ref_count_a) < 0, "dis ref a count underflow");
590         WARN_ONCE(atomic_read(&ref_count_b) < 0, "dis ref b count underflow");
591
592         if (op && id == TEGRA_POWERGATE_DISA) {
593                 if (atomic_inc_return(&ref_count_a) != 1)
594                         return 0;
595         } else if (op && id == TEGRA_POWERGATE_DISB) {
596                 if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA))
597                         atomic_inc(&ref_count_a);
598                 if (atomic_inc_return(&ref_count_b) != 1)
599                         return 0;
600         } else if (!op && id == TEGRA_POWERGATE_DISA) {
601                 if (atomic_dec_return(&ref_count_a) != 0)
602                         return 0;
603         } else if (!op && id == TEGRA_POWERGATE_DISB) {
604                 atomic_dec(&ref_count_a);
605                 if (atomic_dec_return(&ref_count_b) != 0) {
606                         return 0;
607                 } else if (atomic_read(&ref_count_a) == 0) {
608                         tegra11x_powergate_dis_partition();
609                         return 0;
610                 }
611         }
612
613         return 1;
614 }
615
616 int tegra11x_powergate_partition(int id)
617 {
618         int ret;
619
620         if ((id == TEGRA_POWERGATE_DISA || id == TEGRA_POWERGATE_DISB) &&
621                         !tegra11x_powergate_check_dis_refcount(id, 0))
622                 return 0;
623
624         ret = tegra11x_check_partition_pg_seq(id,
625                 &tegra11x_powergate_partition_info[id]);
626         if (ret)
627                 return ret;
628
629         /* call common power-gate API for t1xx */
630         ret = tegra1xx_powergate(id,
631                 &tegra11x_powergate_partition_info[id]);
632
633         return ret;
634 }
635
636 int tegra11x_unpowergate_partition(int id)
637 {
638         int ret;
639
640         if ((id == TEGRA_POWERGATE_DISA || id == TEGRA_POWERGATE_DISB) &&
641                         !tegra11x_powergate_check_dis_refcount(id, 1))
642                 return 0;
643
644         ret = tegra11x_check_partition_pug_seq(id,
645                 &tegra11x_powergate_partition_info[id]);
646         if (ret)
647                 return ret;
648
649         /* t11x needs to calibrate mipi in un-power-gate sequence
650          * hence it cannot use common un-power-gate api tegra1xx_unpowergate */
651         ret = tegra11x_unpowergate(id,
652                 &tegra11x_powergate_partition_info[id]);
653
654         return ret;
655 }
656
657 int tegra11x_powergate_partition_with_clk_off(int id)
658 {
659         return tegraxx_powergate_partition_with_clk_off(id,
660                 &tegra11x_powergate_partition_info[id]);
661 }
662
663 int tegra11x_unpowergate_partition_with_clk_on(int id)
664 {
665         return tegraxx_unpowergate_partition_with_clk_on(id,
666                 &tegra11x_powergate_partition_info[id]);
667 }
668
669 const char *tegra11x_get_powergate_domain_name(int id)
670 {
671         return tegra11x_powergate_partition_info[id].name;
672 }
673
674 spinlock_t *tegra11x_get_powergate_lock(void)
675 {
676         return &tegra11x_powergate_lock;
677 }
678
679 int tegra11x_powergate_init_refcount(void)
680 {
681         if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA))
682                         atomic_set(&ref_count_a, 1);
683         else
684                         atomic_set(&ref_count_a, 0);
685
686         if (tegra_powergate_is_powered(TEGRA_POWERGATE_DISB))
687                         atomic_set(&ref_count_b, 1);
688         else
689                         atomic_set(&ref_count_b, 0);
690         return 0;
691 }
692
693 static struct powergate_ops tegra11x_powergate_ops = {
694         .soc_name = "tegra11x",
695
696         .num_powerdomains = TEGRA_NUM_POWERGATE,
697
698         .get_powergate_lock = tegra11x_get_powergate_lock,
699         .get_powergate_domain_name = tegra11x_get_powergate_domain_name,
700
701         .powergate_partition = tegra11x_powergate_partition,
702         .unpowergate_partition = tegra11x_unpowergate_partition,
703
704         .powergate_partition_with_clk_off =  tegra11x_powergate_partition_with_clk_off,
705         .unpowergate_partition_with_clk_on = tegra11x_unpowergate_partition_with_clk_on,
706
707         .powergate_mc_enable = tegra11x_powergate_mc_enable,
708         .powergate_mc_disable = tegra11x_powergate_mc_disable,
709
710         .powergate_mc_flush = tegra11x_powergate_mc_flush,
711         .powergate_mc_flush_done = tegra11x_powergate_mc_flush_done,
712
713         .powergate_init_refcount = tegra11x_powergate_init_refcount,
714         .powergate_check_clamping = tegra11x_powergate_check_clamping,
715 };
716
717 struct powergate_ops *tegra11x_powergate_init_chip_support(void)
718 {
719         return &tegra11x_powergate_ops;
720 }