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