ARM: tegra: Export tegra_powergate_is_powered()
[linux-2.6.git] / arch / arm / mach-tegra / powergate.c
1 /*
2  * drivers/powergate/tegra-powergate.c
3  *
4  * Copyright (c) 2010 Google, Inc
5  * Copyright (C) 2011 NVIDIA Corporation.
6  *
7  * Author:
8  *      Colin Cross <ccross@google.com>
9  *
10  * This software is licensed under the terms of the GNU General Public
11  * License version 2, as published by the Free Software Foundation, and
12  * may be copied, distributed, and modified under those terms.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/clk.h>
24 #include <linux/debugfs.h>
25 #include <linux/delay.h>
26 #include <linux/err.h>
27 #include <linux/init.h>
28 #include <linux/io.h>
29 #include <linux/seq_file.h>
30 #include <linux/spinlock.h>
31 #include <trace/events/power.h>
32
33 #include <mach/clk.h>
34 #include <mach/iomap.h>
35 #include <mach/powergate.h>
36
37 #include "clock.h"
38
39 #define PWRGATE_TOGGLE          0x30
40 #define PWRGATE_TOGGLE_START    (1 << 8)
41
42 #define REMOVE_CLAMPING         0x34
43
44 #define PWRGATE_STATUS          0x38
45
46 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
47 enum mc_client {
48         MC_CLIENT_AFI           = 0,
49         MC_CLIENT_AVPC          = 1,
50         MC_CLIENT_DC            = 2,
51         MC_CLIENT_DCB           = 3,
52         MC_CLIENT_EPP           = 4,
53         MC_CLIENT_G2            = 5,
54         MC_CLIENT_HC            = 6,
55         MC_CLIENT_HDA           = 7,
56         MC_CLIENT_ISP           = 8,
57         MC_CLIENT_MPCORE        = 9,
58         MC_CLIENT_MPCORELP      = 10,
59         MC_CLIENT_MPE           = 11,
60         MC_CLIENT_NV            = 12,
61         MC_CLIENT_NV2           = 13,
62         MC_CLIENT_PPCS          = 14,
63         MC_CLIENT_SATA          = 15,
64         MC_CLIENT_VDE           = 16,
65         MC_CLIENT_VI            = 17,
66         MC_CLIENT_LAST          = -1,
67 };
68 #else
69 enum mc_client {
70         MC_CLIENT_AVPC          = 0,
71         MC_CLIENT_DC            = 1,
72         MC_CLIENT_DCB           = 2,
73         MC_CLIENT_EPP           = 3,
74         MC_CLIENT_G2            = 4,
75         MC_CLIENT_HC            = 5,
76         MC_CLIENT_ISP           = 6,
77         MC_CLIENT_MPCORE        = 7,
78         MC_CLIENT_MPEA          = 8,
79         MC_CLIENT_MPEB          = 9,
80         MC_CLIENT_MPEC          = 10,
81         MC_CLIENT_NV            = 11,
82         MC_CLIENT_PPCS          = 12,
83         MC_CLIENT_VDE           = 13,
84         MC_CLIENT_VI            = 14,
85         MC_CLIENT_LAST          = -1,
86         MC_CLIENT_AFI           = MC_CLIENT_LAST,
87 };
88 #endif
89
90 #define MAX_CLK_EN_NUM                  4
91
92 static DEFINE_SPINLOCK(tegra_powergate_lock);
93
94 #define MAX_HOTRESET_CLIENT_NUM         4
95
96 enum clk_type {
97         CLK_AND_RST,
98         RST_ONLY,
99         CLK_ONLY,
100 };
101
102 struct partition_clk_info {
103         const char *clk_name;
104         enum clk_type clk_type;
105         /* true if clk is only used in assert/deassert reset and not while enable-den*/
106         struct clk *clk_ptr;
107 };
108
109 struct powergate_partition {
110         const char *name;
111         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
112         struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
113 };
114
115 static struct powergate_partition powergate_partition_info[TEGRA_NUM_POWERGATE] = {
116         [TEGRA_POWERGATE_CPU]   = { "cpu0",     {MC_CLIENT_LAST}, },
117         [TEGRA_POWERGATE_L2]    = { "l2",       {MC_CLIENT_LAST}, },
118         [TEGRA_POWERGATE_3D]    = { "3d0",
119                                                 {MC_CLIENT_NV, MC_CLIENT_LAST},
120                                                 {{"3d", CLK_AND_RST} }, },
121         [TEGRA_POWERGATE_PCIE]  = { "pcie",
122                                                 {MC_CLIENT_AFI, MC_CLIENT_LAST},
123                                                 {{"afi", CLK_AND_RST},
124                                                 {"pcie", CLK_AND_RST},
125 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
126                                                 {"cml0", CLK_ONLY},
127 #endif
128                                                 {"pciex", RST_ONLY} }, },
129         [TEGRA_POWERGATE_VDEC]  = { "vde",
130                                                 {MC_CLIENT_VDE, MC_CLIENT_LAST},
131                                                 {{"vde", CLK_AND_RST} }, },
132         [TEGRA_POWERGATE_MPE]   = { "mpe",
133 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
134                                         {MC_CLIENT_MPE, MC_CLIENT_LAST},
135 #else
136                                         {MC_CLIENT_MPEA, MC_CLIENT_MPEB,
137                                          MC_CLIENT_MPEC, MC_CLIENT_LAST},
138 #endif
139                                                 {{"mpe", CLK_AND_RST} }, },
140         [TEGRA_POWERGATE_VENC]  = { "ve",
141                                                 {MC_CLIENT_ISP, MC_CLIENT_VI, MC_CLIENT_LAST},
142                                                 {{"isp", CLK_AND_RST},
143                                                 {"vi", CLK_AND_RST},
144                                                 {"csi", CLK_AND_RST} }, },
145 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
146         [TEGRA_POWERGATE_CPU1]  = { "cpu1",     {MC_CLIENT_LAST}, },
147         [TEGRA_POWERGATE_CPU2]  = { "cpu2",     {MC_CLIENT_LAST}, },
148         [TEGRA_POWERGATE_CPU3]  = { "cpu3",     {MC_CLIENT_LAST}, },
149         [TEGRA_POWERGATE_CELP]  = { "celp",     {MC_CLIENT_LAST}, },
150         [TEGRA_POWERGATE_SATA]  = { "sata",     {MC_CLIENT_SATA, MC_CLIENT_LAST},
151                                                 {{"sata", CLK_AND_RST},
152                                                 {"sata_oob", CLK_AND_RST},
153                                                 {"cml1", CLK_ONLY},
154                                                 {"sata_cold", RST_ONLY} }, },
155         [TEGRA_POWERGATE_3D1]   = { "3d1",
156                                                 {MC_CLIENT_NV2, MC_CLIENT_LAST},
157                                                 {{"3d2", CLK_AND_RST} }, },
158         [TEGRA_POWERGATE_HEG]   = { "heg",
159                                                 {MC_CLIENT_G2, MC_CLIENT_EPP,
160                                                         MC_CLIENT_HC,
161                                                         MC_CLIENT_LAST},
162                                                 {{"2d", CLK_AND_RST},
163                                                 {"epp", CLK_AND_RST},
164                                                 {"host1x", CLK_AND_RST},
165                                                 {"3d", RST_ONLY} }, },
166 #endif
167 };
168
169 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
170
171 static u32 pmc_read(unsigned long reg)
172 {
173         return readl(pmc + reg);
174 }
175
176 static void pmc_write(u32 val, unsigned long reg)
177 {
178         writel(val, pmc + reg);
179 }
180
181 static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
182
183 static u32 mc_read(unsigned long reg)
184 {
185         return readl(mc + reg);
186 }
187
188 static void mc_write(u32 val, unsigned long reg)
189 {
190         writel(val, mc + reg);
191 }
192
193 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
194
195 #define MC_CLIENT_HOTRESET_CTRL 0x200
196 #define MC_CLIENT_HOTRESET_STAT 0x204
197
198 static void mc_flush(int id)
199 {
200         u32 idx, rst_ctrl, rst_stat;
201         enum mc_client mcClientBit;
202         unsigned long flags;
203
204         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
205
206         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
207                 mcClientBit = powergate_partition_info[id].hot_reset_clients[idx];
208                 if (mcClientBit == MC_CLIENT_LAST)
209                         break;
210
211                 spin_lock_irqsave(&tegra_powergate_lock, flags);
212                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
213                 rst_ctrl |= (1 << mcClientBit);
214                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
215
216                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
217
218                 do {
219                         udelay(10);
220                         rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
221                 } while (!(rst_stat & (1 << mcClientBit)));
222         }
223 }
224
225 static void mc_flush_done(int id)
226 {
227         u32 idx, rst_ctrl;
228         enum mc_client mcClientBit;
229         unsigned long flags;
230
231         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
232
233         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
234                 mcClientBit = powergate_partition_info[id].hot_reset_clients[idx];
235                 if (mcClientBit == MC_CLIENT_LAST)
236                         break;
237
238                 spin_lock_irqsave(&tegra_powergate_lock, flags);
239
240                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
241                 rst_ctrl &= ~(1 << mcClientBit);
242                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
243
244                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
245         }
246
247         wmb();
248 }
249
250 int tegra_powergate_mc_flush(int id)
251 {
252         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
253                 return -EINVAL;
254         mc_flush(id);
255         return 0;
256 }
257
258 int tegra_powergate_mc_flush_done(int id)
259 {
260         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
261                 return -EINVAL;
262         mc_flush_done(id);
263         return 0;
264 }
265
266 int tegra_powergate_mc_disable(int id)
267 {
268         return 0;
269 }
270
271 int tegra_powergate_mc_enable(int id)
272 {
273         return 0;
274 }
275
276 #else
277
278 #define MC_CLIENT_CTRL          0x100
279 #define MC_CLIENT_HOTRESETN     0x104
280 #define MC_CLIENT_ORRC_BASE     0x140
281
282 int tegra_powergate_mc_disable(int id)
283 {
284         u32 idx, clt_ctrl, orrc_reg;
285         enum mc_client mcClientBit;
286         unsigned long flags;
287
288         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
289                 WARN_ON(1);
290                 return -EINVAL;
291         }
292
293         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
294                 mcClientBit =
295                         powergate_partition_info[id].hot_reset_clients[idx];
296                 if (mcClientBit == MC_CLIENT_LAST)
297                         break;
298
299                 spin_lock_irqsave(&tegra_powergate_lock, flags);
300
301                 /* clear client enable bit */
302                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
303                 clt_ctrl &= ~(1 << mcClientBit);
304                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
305
306                 /* read back to flush write */
307                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
308
309                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
310
311                 /* wait for outstanding requests to reach 0 */
312                 orrc_reg = MC_CLIENT_ORRC_BASE + (mcClientBit * 4);
313                 while (mc_read(orrc_reg) != 0)
314                         udelay(10);
315         }
316         return 0;
317 }
318
319 int tegra_powergate_mc_flush(int id)
320 {
321         u32 idx, hot_rstn;
322         enum mc_client mcClientBit;
323         unsigned long flags;
324
325         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
326                 WARN_ON(1);
327                 return -EINVAL;
328         }
329
330         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
331                 mcClientBit =
332                         powergate_partition_info[id].hot_reset_clients[idx];
333                 if (mcClientBit == MC_CLIENT_LAST)
334                         break;
335
336                 spin_lock_irqsave(&tegra_powergate_lock, flags);
337
338                 /* assert hotreset (client module is currently in reset) */
339                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
340                 hot_rstn &= ~(1 << mcClientBit);
341                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
342
343                 /* read back to flush write */
344                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
345
346                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
347         }
348         return 0;
349 }
350
351 int tegra_powergate_mc_flush_done(int id)
352 {
353         u32 idx, hot_rstn;
354         enum mc_client mcClientBit;
355         unsigned long flags;
356
357         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
358                 WARN_ON(1);
359                 return -EINVAL;
360         }
361
362         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
363                 mcClientBit =
364                         powergate_partition_info[id].hot_reset_clients[idx];
365                 if (mcClientBit == MC_CLIENT_LAST)
366                         break;
367
368                 spin_lock_irqsave(&tegra_powergate_lock, flags);
369
370                 /* deassert hotreset */
371                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
372                 hot_rstn |= (1 << mcClientBit);
373                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
374
375                 /* read back to flush write */
376                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
377
378                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
379         }
380         return 0;
381 }
382
383 int tegra_powergate_mc_enable(int id)
384 {
385         u32 idx, clt_ctrl;
386         enum mc_client mcClientBit;
387         unsigned long flags;
388
389         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
390                 WARN_ON(1);
391                 return -EINVAL;
392         }
393
394         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
395                 mcClientBit =
396                         powergate_partition_info[id].hot_reset_clients[idx];
397                 if (mcClientBit == MC_CLIENT_LAST)
398                         break;
399
400                 spin_lock_irqsave(&tegra_powergate_lock, flags);
401
402                 /* enable client */
403                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
404                 clt_ctrl |= (1 << mcClientBit);
405                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
406
407                 /* read back to flush write */
408                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
409
410                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
411         }
412         return 0;
413 }
414
415 static void mc_flush(int id) {}
416 static void mc_flush_done(int id) {}
417 #endif
418
419 static int tegra_powergate_set(int id, bool new_state)
420 {
421         bool status;
422         unsigned long flags;
423         /* 10us timeout for toggle operation if it takes affect*/
424         int toggle_timeout = 10;
425         /* 100 * 10 = 1000us timeout for toggle command to take affect in case
426            of contention with h/w initiated CPU power gating */
427         int contention_timeout = 100;
428
429         spin_lock_irqsave(&tegra_powergate_lock, flags);
430
431         status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
432
433         if (status == new_state) {
434                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
435                 return 0;
436         }
437
438         if (TEGRA_IS_CPU_POWERGATE_ID(id)) {
439                 /* CPU ungated in s/w only during boot/resume with outer
440                    waiting loop and no contention from other CPUs */
441                 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
442                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
443                 return 0;
444         }
445
446         do {
447                 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
448                 do {
449                         udelay(1);
450                         status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
451
452                         toggle_timeout--;
453                 } while ((status != new_state) && (toggle_timeout > 0));
454
455                 contention_timeout--;
456         } while ((status != new_state) && (contention_timeout > 0));
457
458         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
459
460         if (status != new_state) {
461                 WARN(1, "Could not set powergate %d to %d", id, new_state);
462                 return -EBUSY;
463         }
464
465         trace_power_domain_target(powergate_partition_info[id].name, new_state,
466                         smp_processor_id());
467
468         return 0;
469 }
470
471 static int unpowergate_module(int id)
472 {
473         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
474                 return -EINVAL;
475         return tegra_powergate_set(id, true);
476 }
477
478 static int powergate_module(int id)
479 {
480         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
481                 return -EINVAL;
482
483         mc_flush(id);
484         return tegra_powergate_set(id, false);
485 }
486
487 bool tegra_powergate_is_powered(int id)
488 {
489         u32 status;
490
491         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
492                 return false;
493
494         status = pmc_read(PWRGATE_STATUS) & (1 << id);
495         return !!status;
496 }
497 EXPORT_SYMBOL(tegra_powergate_is_powered);
498
499 int tegra_powergate_remove_clamping(int id)
500 {
501         u32 mask;
502         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
503                 return -EINVAL;
504
505         /*
506          * PCIE and VDE clamping masks are swapped with respect to their
507          * partition ids
508          */
509         if (id ==  TEGRA_POWERGATE_VDEC)
510                 mask = (1 << TEGRA_POWERGATE_PCIE);
511         else if (id == TEGRA_POWERGATE_PCIE)
512                 mask = (1 << TEGRA_POWERGATE_VDEC);
513         else
514                 mask = (1 << id);
515
516         pmc_write(mask, REMOVE_CLAMPING);
517
518         return 0;
519 }
520
521 static void get_clk_info(int id)
522 {
523         int idx;
524
525         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
526                 if (!powergate_partition_info[id].clk_info[idx].clk_name)
527                         break;
528                 powergate_partition_info[id].
529                                 clk_info[idx].clk_ptr =
530                                         tegra_get_clock_by_name(
531                         powergate_partition_info[id].clk_info[idx].clk_name);
532         }
533 }
534
535 static int partition_clk_enable(int id)
536 {
537         int ret;
538         u32 idx;
539         struct clk *clk;
540         struct partition_clk_info *clk_info;
541
542         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
543
544         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
545                 clk_info = &powergate_partition_info[id].clk_info[idx];
546                 clk = clk_info->clk_ptr;
547                 if (!clk)
548                         break;
549
550                 if (clk_info->clk_type != RST_ONLY) {
551                         ret = clk_enable(clk);
552                         if (ret)
553                                 goto err_clk_en;
554                 }
555         }
556
557         return 0;
558
559 err_clk_en:
560         WARN(1, "Could not enable clk %s", clk->name);
561         while (idx--) {
562                 clk_info = &powergate_partition_info[id].clk_info[idx];
563                 if (clk_info->clk_type != RST_ONLY)
564                         clk_disable(clk_info->clk_ptr);
565         }
566
567         return ret;
568 }
569
570 static int is_partition_clk_disabled(int id)
571 {
572         u32 idx;
573         struct clk *clk;
574         struct partition_clk_info *clk_info;
575         int ret = 0;
576
577         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
578
579         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
580                 clk_info = &powergate_partition_info[id].clk_info[idx];
581                 clk = clk_info->clk_ptr;
582                 if (!clk)
583                         break;
584
585                 if (clk_info->clk_type != RST_ONLY) {
586                         if (tegra_is_clk_enabled(clk)) {
587                                 ret = -1;
588                                 break;
589                         }
590                 }
591         }
592
593         return ret;
594 }
595
596 static void partition_clk_disable(int id)
597 {
598         u32 idx;
599         struct clk *clk;
600         struct partition_clk_info *clk_info;
601
602         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
603
604         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
605                 clk_info = &powergate_partition_info[id].clk_info[idx];
606                 clk = clk_info->clk_ptr;
607                 if (!clk)
608                         break;
609
610                 if (clk_info->clk_type != RST_ONLY)
611                         clk_disable(clk);
612         }
613 }
614
615 static void powergate_partition_assert_reset(int id)
616 {
617         u32 idx;
618         struct clk *clk_ptr;
619         struct partition_clk_info *clk_info;
620
621         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
622
623         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
624                 clk_info = &powergate_partition_info[id].clk_info[idx];
625                 clk_ptr = clk_info->clk_ptr;
626                 if (!clk_ptr)
627                         break;
628                 if (clk_info->clk_type != CLK_ONLY)
629                         tegra_periph_reset_assert(clk_ptr);
630         }
631 }
632
633 static void powergate_partition_deassert_reset(int id)
634 {
635         u32 idx;
636         struct clk *clk_ptr;
637         struct partition_clk_info *clk_info;
638
639         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
640
641         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
642                 clk_info = &powergate_partition_info[id].clk_info[idx];
643                 clk_ptr = clk_info->clk_ptr;
644                 if (!clk_ptr)
645                         break;
646                 if (clk_info->clk_type != CLK_ONLY)
647                         tegra_periph_reset_deassert(clk_ptr);
648         }
649 }
650
651 /* Must be called with clk disabled, and returns with clk disabled */
652 static int tegra_powergate_reset_module(int id)
653 {
654         int ret;
655
656         powergate_partition_assert_reset(id);
657
658         udelay(10);
659
660         ret = partition_clk_enable(id);
661         if (ret)
662                 return ret;
663
664         udelay(10);
665
666         powergate_partition_deassert_reset(id);
667
668         partition_clk_disable(id);
669
670         return 0;
671 }
672
673 /*
674  * Must be called with clk disabled, and returns with clk disabled
675  * Drivers should enable clks for partition. Unpowergates only the
676  * partition.
677  */
678 int tegra_unpowergate_partition(int id)
679 {
680         int ret;
681
682         /* If first clk_ptr is null, fill clk info for the partition */
683         if (!powergate_partition_info[id].clk_info[0].clk_ptr)
684                 get_clk_info(id);
685
686         if (tegra_powergate_is_powered(id))
687                 return tegra_powergate_reset_module(id);
688
689         ret = unpowergate_module(id);
690         if (ret)
691                 goto err_power;
692
693         powergate_partition_assert_reset(id);
694
695         /* Un-Powergating fails if all clks are not enabled */
696         ret = partition_clk_enable(id);
697         if (ret)
698                 goto err_clk_on;
699
700         udelay(10);
701
702         ret = tegra_powergate_remove_clamping(id);
703         if (ret)
704                 goto err_clamp;
705
706         udelay(10);
707         powergate_partition_deassert_reset(id);
708
709         mc_flush_done(id);
710
711         /* Disable all clks enabled earlier. Drivers should enable clks */
712         partition_clk_disable(id);
713
714         return 0;
715
716 err_clamp:
717         partition_clk_disable(id);
718 err_clk_on:
719         powergate_module(id);
720 err_power:
721         WARN(1, "Could not Un-Powergate %d", id);
722         return ret;
723 }
724
725 /*
726  * Must be called with clk disabled, and returns with clk enabled
727  * Unpowergates the partition and enables all required clks.
728  */
729 int tegra_unpowergate_partition_with_clk_on(int id)
730 {
731         int ret = 0;
732
733 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
734         /* Restrict this functions use to few partitions */
735         BUG_ON(id != TEGRA_POWERGATE_SATA && id != TEGRA_POWERGATE_PCIE);
736 #else
737         /* Restrict this functions use to few partitions */
738         BUG_ON(id != TEGRA_POWERGATE_PCIE);
739 #endif
740
741         ret = tegra_unpowergate_partition(id);
742         if (ret)
743                 goto err_unpowergating;
744
745         /* Enable clks for the partition */
746         ret = partition_clk_enable(id);
747         if (ret)
748                 goto err_unpowergate_clk;
749
750         return ret;
751
752 err_unpowergate_clk:
753         tegra_powergate_partition(id);
754         WARN(1, "Could not Un-Powergate %d, err in enabling clk", id);
755 err_unpowergating:
756         WARN(1, "Could not Un-Powergate %d", id);
757         return ret;
758 }
759
760 /*
761  * Must be called with clk disabled. Powergates the partition only
762  */
763 int tegra_powergate_partition(int id)
764 {
765         int ret;
766
767         /* If first clk_ptr is null, fill clk info for the partition */
768         if (powergate_partition_info[id].clk_info[0].clk_ptr)
769                 get_clk_info(id);
770         powergate_partition_assert_reset(id);
771
772         /* Powergating is done only if refcnt of all clks is 0 */
773         ret = is_partition_clk_disabled(id);
774         if (ret)
775                 goto err_clk_off;
776
777         ret = powergate_module(id);
778         if (ret)
779                 goto err_power_off;
780
781         return 0;
782
783 err_power_off:
784         WARN(1, "Could not Powergate Partition %d", id);
785 err_clk_off:
786         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
787         return ret;
788 }
789
790 int tegra_powergate_partition_with_clk_off(int id)
791 {
792         int ret = 0;
793
794 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
795         /* Restrict functions use to selected partitions */
796         BUG_ON(id != TEGRA_POWERGATE_PCIE && id != TEGRA_POWERGATE_SATA);
797 #else
798         /* Restrict functions use to selected partitions */
799         BUG_ON(id != TEGRA_POWERGATE_PCIE);
800 #endif
801         /* Disable clks for the partition */
802         partition_clk_disable(id);
803
804         ret = is_partition_clk_disabled(id);
805         if (ret)
806                 goto err_powergate_clk;
807
808         ret = tegra_powergate_partition(id);
809         if (ret)
810                 goto err_powergating;
811
812         return ret;
813
814 err_powergate_clk:
815         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
816 err_powergating:
817         partition_clk_enable(id);
818         WARN(1, "Could not Powergate Partition %d", id);
819         return ret;
820 }
821
822 const char *tegra_powergate_get_name(int id)
823 {
824         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
825                 return "invalid";
826
827         return powergate_partition_info[id].name;
828 }
829
830 #ifdef CONFIG_DEBUG_FS
831
832 static int powergate_show(struct seq_file *s, void *data)
833 {
834         int i;
835
836         seq_printf(s, " powergate powered\n");
837         seq_printf(s, "------------------\n");
838
839         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
840                 seq_printf(s, " %9s %7s\n", powergate_partition_info[i].name,
841                         tegra_powergate_is_powered(i) ? "yes" : "no");
842         return 0;
843 }
844
845 static int powergate_open(struct inode *inode, struct file *file)
846 {
847         return single_open(file, powergate_show, inode->i_private);
848 }
849
850 static const struct file_operations powergate_fops = {
851         .open           = powergate_open,
852         .read           = seq_read,
853         .llseek         = seq_lseek,
854         .release        = single_release,
855 };
856
857 static int __init powergate_debugfs_init(void)
858 {
859         struct dentry *d;
860
861         d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
862                 &powergate_fops);
863         if (!d)
864                 return -ENOMEM;
865
866         return 0;
867 }
868
869 late_initcall(powergate_debugfs_init);
870
871 #endif