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