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