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