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