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