arm: tegra: t11x power gate tables
[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 #if defined(DEBUG_T11x_POWERGATE)
41 static void test_powergate_parts(void);
42 #endif
43 #if defined(DEBUG_T11x_POWERUNGATE)
44 static void test_powerungate_parts(void);
45 #endif
46 #if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
47 static void test_powergate_clk_off_parts(void);
48 #endif
49 #if defined(DEBUG_T11x_POWERUNGATE_CLK_OFF)
50 static void test_unpowergate_clk_on_parts(void);
51 #endif
52
53 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
54 static int tegra11x_check_partition_pug_seq(int id);
55 #endif
56
57 #define PWRGATE_TOGGLE          0x30
58 #define PWRGATE_TOGGLE_START    (1 << 8)
59
60 #define REMOVE_CLAMPING         0x34
61
62 #define PWRGATE_STATUS          0x38
63
64 #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
65 enum mc_client {
66         MC_CLIENT_AFI           = 0,
67         MC_CLIENT_AVPC          = 1,
68         MC_CLIENT_DC            = 2,
69         MC_CLIENT_DCB           = 3,
70         MC_CLIENT_EPP           = 4,
71         MC_CLIENT_G2            = 5,
72         MC_CLIENT_HC            = 6,
73         MC_CLIENT_HDA           = 7,
74         MC_CLIENT_ISP           = 8,
75         MC_CLIENT_MPCORE        = 9,
76         MC_CLIENT_MPCORELP      = 10,
77         MC_CLIENT_MPE           = 11,
78         MC_CLIENT_NV            = 12,
79         MC_CLIENT_NV2           = 13,
80         MC_CLIENT_PPCS          = 14,
81         MC_CLIENT_SATA          = 15,
82         MC_CLIENT_VDE           = 16,
83         MC_CLIENT_VI            = 17,
84         MC_CLIENT_LAST          = -1,
85 };
86 #elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
87 enum mc_client {
88         MC_CLIENT_AVPC          = 0,
89         MC_CLIENT_DC            = 1,
90         MC_CLIENT_DCB           = 2,
91         MC_CLIENT_EPP           = 3,
92         MC_CLIENT_G2            = 4,
93         MC_CLIENT_HC            = 5,
94         MC_CLIENT_ISP           = 6,
95         MC_CLIENT_MPCORE        = 7,
96         MC_CLIENT_MPEA          = 8,
97         MC_CLIENT_MPEB          = 9,
98         MC_CLIENT_MPEC          = 10,
99         MC_CLIENT_NV            = 11,
100         MC_CLIENT_PPCS          = 12,
101         MC_CLIENT_VDE           = 13,
102         MC_CLIENT_VI            = 14,
103         MC_CLIENT_LAST          = -1,
104         MC_CLIENT_AFI           = MC_CLIENT_LAST,
105 };
106 #else
107 /* bit positions are specific to chip */
108 enum mc_client {
109         MC_CLIENT_AVPC          = 1,
110         MC_CLIENT_DC            = 2,
111         MC_CLIENT_DCB           = 3,
112         MC_CLIENT_EPP           = 4,
113         MC_CLIENT_G2            = 5,
114         MC_CLIENT_HC            = 6,
115         MC_CLIENT_HDA           = 7,
116         MC_CLIENT_ISP           = 8,
117         MC_CLIENT_MPCORE        = 9,
118         MC_CLIENT_MPCORELP      = 10,
119         MC_CLIENT_MSENC         = 11,
120         MC_CLIENT_NV            = 12,
121         MC_CLIENT_PPCS          = 14,
122         MC_CLIENT_VDE           = 16,
123         MC_CLIENT_VI            = 17,
124         MC_CLIENT_XUSB_HOST     = 19,
125         MC_CLIENT_XUSB_DEV      = 20,
126         MC_CLIENT_EMUCIF        = 21,
127         MC_CLIENT_TSEC          = 22,
128         MC_CLIENT_LAST          = -1,
129         MC_CLIENT_AFI           = MC_CLIENT_LAST,
130         MC_CLIENT_MPE           = MC_CLIENT_LAST,
131         MC_CLIENT_NV2           = MC_CLIENT_LAST,
132         MC_CLIENT_SATA          = MC_CLIENT_LAST,
133 };
134 #endif
135
136 #define MAX_CLK_EN_NUM                  9
137
138 static int tegra_num_powerdomains;
139 static int tegra_num_cpu_domains;
140 static u8 *tegra_cpu_domains;
141 static u8 tegra_quad_cpu_domains[] = {
142         TEGRA_POWERGATE_CPU0,
143         TEGRA_POWERGATE_CPU1,
144         TEGRA_POWERGATE_CPU2,
145         TEGRA_POWERGATE_CPU3,
146 };
147
148 static DEFINE_SPINLOCK(tegra_powergate_lock);
149
150 #define MAX_HOTRESET_CLIENT_NUM         4
151
152 enum clk_type {
153         CLK_AND_RST,
154         RST_ONLY,
155         CLK_ONLY,
156 };
157
158 struct partition_clk_info {
159         const char *clk_name;
160         enum clk_type clk_type;
161         /* true if clk is only used in assert/deassert reset and not while enable-den*/
162         struct clk *clk_ptr;
163 };
164
165 struct powergate_partition {
166         const char *name;
167         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
168         struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
169 };
170
171 static struct powergate_partition powergate_partition_info[TEGRA_NUM_POWERGATE] = {
172         [TEGRA_POWERGATE_CPU]   = { "cpu0",     {MC_CLIENT_LAST}, },
173         [TEGRA_POWERGATE_L2]    = { "l2",       {MC_CLIENT_LAST}, },
174 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
175         [TEGRA_POWERGATE_3D]    = { "3d0",
176 #else
177         [TEGRA_POWERGATE_3D]    = { "3d",
178 #endif
179                                                 {MC_CLIENT_NV, MC_CLIENT_LAST},
180                                                 {{"3d", CLK_AND_RST} }, },
181 /* T11x does not have pcie */
182 #if !defined(CONFIG_ARCH_TEGRA_11x_SOC)
183 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
184         [TEGRA_POWERGATE_PCIE]  = { "pcie",
185                                                 {MC_CLIENT_AFI, MC_CLIENT_LAST},
186                                                 {{"afi", CLK_AND_RST},
187                                                 {"pcie", CLK_AND_RST},
188 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
189                                                 {"cml0", CLK_ONLY},
190 #endif
191                                                 {"pciex", RST_ONLY} }, },
192 #endif
193 #endif
194         [TEGRA_POWERGATE_VDEC]  = { "vde",
195                                                 {MC_CLIENT_VDE, MC_CLIENT_LAST},
196                                                 {{"vde", CLK_AND_RST} }, },
197         [TEGRA_POWERGATE_MPE]   = { "mpe",
198 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
199                                         {
200                                                 MC_CLIENT_MPE,
201                                                 MC_CLIENT_LAST
202                                         },
203 #elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
204                                                 {MC_CLIENT_MPEA, MC_CLIENT_MPEB,
205                                                  MC_CLIENT_MPEC, MC_CLIENT_LAST},
206 #else
207                                         {
208                                                 MC_CLIENT_MSENC,
209                                                 MC_CLIENT_LAST
210                                         },
211 #endif
212 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
213                                         {
214                                                 {"mpe", CLK_AND_RST}
215                                         },
216 #else
217                                         {
218                                                 {"msenc", CLK_AND_RST}
219                                         },
220 #endif
221                                 },
222         [TEGRA_POWERGATE_VENC]  = { "ve",
223                                         {
224                                                 MC_CLIENT_ISP,
225                                                 MC_CLIENT_VI,
226                                                 MC_CLIENT_LAST
227                                         },
228                                         {
229                                                 {"isp", CLK_AND_RST},
230                                                 {"vi", CLK_AND_RST},
231                                                 {"csi", CLK_AND_RST}
232                                         },
233                                 },
234 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
235         [TEGRA_POWERGATE_CPU1]  = { "cpu1",     {MC_CLIENT_LAST}, },
236         [TEGRA_POWERGATE_CPU2]  = { "cpu2",     {MC_CLIENT_LAST}, },
237         [TEGRA_POWERGATE_CPU3]  = { "cpu3",     {MC_CLIENT_LAST}, },
238         [TEGRA_POWERGATE_CELP]  = { "celp",     {MC_CLIENT_LAST}, },
239 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
240 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
241         [TEGRA_POWERGATE_SATA]  = { "sata",     {MC_CLIENT_SATA, MC_CLIENT_LAST},
242                                                 {{"sata", CLK_AND_RST},
243                                                 {"sata_oob", CLK_AND_RST},
244                                                 {"cml1", CLK_ONLY},
245                                                 {"sata_cold", RST_ONLY} }, },
246 #endif
247 #ifdef CONFIG_ARCH_TEGRA_HAS_DUAL_3D
248         [TEGRA_POWERGATE_3D1]   = { "3d1",
249                                                 {MC_CLIENT_NV2, MC_CLIENT_LAST},
250                                                 {{"3d2", CLK_AND_RST} }, },
251 #endif
252 #endif
253         [TEGRA_POWERGATE_HEG]   = { "heg",
254                                         {
255                                                 MC_CLIENT_G2,
256                                                 MC_CLIENT_EPP,
257 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
258                                                 MC_CLIENT_HC,
259 #endif
260                                                 MC_CLIENT_LAST
261                                         },
262                                         {
263                                                 {"2d", CLK_AND_RST},
264                                                 {"epp", CLK_AND_RST},
265 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
266                                                 {"host1x", CLK_AND_RST},
267                                                 {"3d", RST_ONLY}
268 #endif
269                                         },
270                                 },
271 #endif
272 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
273         [TEGRA_POWERGATE_CRAIL] = { "crail",    {MC_CLIENT_LAST}, },
274         [TEGRA_POWERGATE_C0NC]  = { "c0nc",     {MC_CLIENT_LAST}, },
275         [TEGRA_POWERGATE_C1NC]  = { "c1nc",     {MC_CLIENT_LAST}, },
276         [TEGRA_POWERGATE_DISA]  = { "disa",
277                                         {
278                                                 MC_CLIENT_DC,
279                                                 MC_CLIENT_LAST
280                                         },
281                                         {
282                                                 {"disp1", CLK_AND_RST},
283                                                 {"dsia", CLK_AND_RST},
284                                                 {"dsib", CLK_AND_RST},
285                                                 {"csi", CLK_AND_RST},
286                                                 {"mipi-cal", CLK_AND_RST}
287                                         },
288                                 },
289         [TEGRA_POWERGATE_DISB]  = { "disb",
290                                         {
291                                                 MC_CLIENT_DCB,
292                                                 MC_CLIENT_LAST
293                                         },
294                                         {
295                                                 {"disp2", CLK_AND_RST},
296                                                 {"hdmi", CLK_AND_RST}
297                                         },
298                                 },
299         [TEGRA_POWERGATE_XUSBA] = { "xusba",
300                                         { MC_CLIENT_LAST },
301                                         {
302                                                 {"xusb_ss", CLK_AND_RST}
303                                         },
304                                 },
305         [TEGRA_POWERGATE_XUSBB] = { "xusbb",
306                                         {
307                                                 MC_CLIENT_XUSB_DEV,
308                                                 MC_CLIENT_LAST
309                                         },
310                                         {
311                                                 {"xusb_dev", CLK_AND_RST},
312                                         },
313                                 },
314         [TEGRA_POWERGATE_XUSBC] = { "xusbc",
315                                         {
316                                                 MC_CLIENT_XUSB_HOST,
317                                                 MC_CLIENT_LAST
318                                         },
319                                         {
320                                                 {"xusb_host", CLK_AND_RST},
321                                         },
322                                 },
323 #endif
324
325 };
326
327 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
328
329 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
330 static void __iomem *mipi_cal = IO_ADDRESS(TEGRA_MIPI_CAL_BASE);
331
332 static u32 mipi_cal_read(unsigned long reg)
333 {
334         return readl(mipi_cal + reg);
335 }
336
337 static void mipi_cal_write(u32 val, unsigned long reg)
338 {
339         writel(val, mipi_cal + reg);
340 }
341
342 static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
343
344 static u32 clk_rst_read(unsigned long reg)
345 {
346         return readl(clk_rst + reg);
347 }
348 #endif
349
350 static u32 pmc_read(unsigned long reg)
351 {
352         return readl(pmc + reg);
353 }
354
355 static void pmc_write(u32 val, unsigned long reg)
356 {
357         writel(val, pmc + reg);
358 }
359
360 static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
361
362 static u32 mc_read(unsigned long reg)
363 {
364         return readl(mc + reg);
365 }
366
367 static void mc_write(u32 val, unsigned long reg)
368 {
369         writel(val, mc + reg);
370 }
371
372 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
373         !defined(CONFIG_TEGRA_SIMULATION_PLATFORM)
374
375 #define MC_CLIENT_HOTRESET_CTRL 0x200
376 #define MC_CLIENT_HOTRESET_STAT 0x204
377
378 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
379         !defined(CONFIG_ARCH_TEGRA_3x_SOC)
380 /* FIXME: this is sw workaround for unstable hotreset status
381  * for T11x.
382  */
383 #define HOTRESET_READ_COUNT 5
384 static bool tegra11x_stable_hotreset_check(u32 *stat)
385 {
386         int i;
387         u32 cur_stat;
388         u32 prv_stat;
389         unsigned long flags;
390
391         spin_lock_irqsave(&tegra_powergate_lock, flags);
392         prv_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
393         for (i = 0; i < HOTRESET_READ_COUNT; i++) {
394                 cur_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
395                 if (cur_stat != prv_stat) {
396                         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
397                         return false;
398                 }
399         }
400         *stat = cur_stat;
401         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
402         return true;
403 }
404 #endif
405
406 static void mc_flush(int id)
407 {
408         u32 idx, rst_ctrl, rst_stat;
409         enum mc_client mcClientBit;
410         unsigned long flags;
411 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && \
412         !defined(CONFIG_ARCH_TEGRA_3x_SOC)
413         bool ret;
414 #endif
415
416         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
417
418         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
419                 mcClientBit =
420                         powergate_partition_info[id].hot_reset_clients[idx];
421                 if (mcClientBit == MC_CLIENT_LAST)
422                         break;
423
424                 spin_lock_irqsave(&tegra_powergate_lock, flags);
425                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
426                 rst_ctrl |= (1 << mcClientBit);
427                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
428
429                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
430
431                 do {
432                         udelay(10);
433 #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
434                         rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
435 #else
436                         rst_stat = 0;
437                         ret = tegra11x_stable_hotreset_check(&rst_stat);
438                         if (!ret)
439                                 continue;
440 #endif
441                 } while (!(rst_stat & (1 << mcClientBit)));
442         }
443 }
444
445 static void mc_flush_done(int id)
446 {
447         u32 idx, rst_ctrl;
448         enum mc_client mcClientBit;
449         unsigned long flags;
450
451         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
452
453         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
454                 mcClientBit =
455                         powergate_partition_info[id].hot_reset_clients[idx];
456                 if (mcClientBit == MC_CLIENT_LAST)
457                         break;
458
459                 spin_lock_irqsave(&tegra_powergate_lock, flags);
460
461                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
462                 rst_ctrl &= ~(1 << mcClientBit);
463                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
464
465                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
466         }
467
468         wmb();
469 }
470
471 int tegra_powergate_mc_flush(int id)
472 {
473         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
474                 return -EINVAL;
475         mc_flush(id);
476         return 0;
477 }
478
479 int tegra_powergate_mc_flush_done(int id)
480 {
481         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
482                 return -EINVAL;
483         mc_flush_done(id);
484         return 0;
485 }
486
487 int tegra_powergate_mc_disable(int id)
488 {
489         return 0;
490 }
491
492 int tegra_powergate_mc_enable(int id)
493 {
494         return 0;
495 }
496
497 #else
498
499 #define MC_CLIENT_CTRL          0x100
500 #define MC_CLIENT_HOTRESETN     0x104
501 #define MC_CLIENT_ORRC_BASE     0x140
502
503 int tegra_powergate_mc_disable(int id)
504 {
505         u32 idx, clt_ctrl, orrc_reg;
506         enum mc_client mcClientBit;
507         unsigned long flags;
508
509         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
510                 WARN_ON(1);
511                 return -EINVAL;
512         }
513
514         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
515                 mcClientBit =
516                         powergate_partition_info[id].hot_reset_clients[idx];
517                 if (mcClientBit == MC_CLIENT_LAST)
518                         break;
519
520                 spin_lock_irqsave(&tegra_powergate_lock, flags);
521
522                 /* clear client enable bit */
523                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
524                 clt_ctrl &= ~(1 << mcClientBit);
525                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
526
527                 /* read back to flush write */
528                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
529
530                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
531
532                 /* wait for outstanding requests to reach 0 */
533                 orrc_reg = MC_CLIENT_ORRC_BASE + (mcClientBit * 4);
534                 while (mc_read(orrc_reg) != 0)
535                         udelay(10);
536         }
537         return 0;
538 }
539
540 int tegra_powergate_mc_flush(int id)
541 {
542         u32 idx, hot_rstn;
543         enum mc_client mcClientBit;
544         unsigned long flags;
545
546         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
547                 WARN_ON(1);
548                 return -EINVAL;
549         }
550
551         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
552                 mcClientBit =
553                         powergate_partition_info[id].hot_reset_clients[idx];
554                 if (mcClientBit == MC_CLIENT_LAST)
555                         break;
556
557                 spin_lock_irqsave(&tegra_powergate_lock, flags);
558
559                 /* assert hotreset (client module is currently in reset) */
560                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
561                 hot_rstn &= ~(1 << mcClientBit);
562                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
563
564                 /* read back to flush write */
565                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
566
567                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
568         }
569         return 0;
570 }
571
572 int tegra_powergate_mc_flush_done(int id)
573 {
574         u32 idx, hot_rstn;
575         enum mc_client mcClientBit;
576         unsigned long flags;
577
578         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
579                 WARN_ON(1);
580                 return -EINVAL;
581         }
582
583         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
584                 mcClientBit =
585                         powergate_partition_info[id].hot_reset_clients[idx];
586                 if (mcClientBit == MC_CLIENT_LAST)
587                         break;
588
589                 spin_lock_irqsave(&tegra_powergate_lock, flags);
590
591                 /* deassert hotreset */
592                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
593                 hot_rstn |= (1 << mcClientBit);
594                 mc_write(hot_rstn, MC_CLIENT_HOTRESETN);
595
596                 /* read back to flush write */
597                 hot_rstn = mc_read(MC_CLIENT_HOTRESETN);
598
599                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
600         }
601         return 0;
602 }
603
604 int tegra_powergate_mc_enable(int id)
605 {
606         u32 idx, clt_ctrl;
607         enum mc_client mcClientBit;
608         unsigned long flags;
609
610         if (id < 0 || id >= TEGRA_NUM_POWERGATE) {
611                 WARN_ON(1);
612                 return -EINVAL;
613         }
614
615         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
616                 mcClientBit =
617                         powergate_partition_info[id].hot_reset_clients[idx];
618                 if (mcClientBit == MC_CLIENT_LAST)
619                         break;
620
621                 spin_lock_irqsave(&tegra_powergate_lock, flags);
622
623                 /* enable client */
624                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
625                 clt_ctrl |= (1 << mcClientBit);
626                 mc_write(clt_ctrl, MC_CLIENT_CTRL);
627
628                 /* read back to flush write */
629                 clt_ctrl = mc_read(MC_CLIENT_CTRL);
630
631                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
632         }
633         return 0;
634 }
635
636 static void mc_flush(int id) {}
637 static void mc_flush_done(int id) {}
638 #endif
639
640 static int tegra_powergate_set(int id, bool new_state)
641 {
642 #ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
643         bool status;
644         unsigned long flags;
645         /* 10us timeout for toggle operation if it takes affect*/
646         int toggle_timeout = 10;
647         /* 100 * 10 = 1000us timeout for toggle command to take affect in case
648            of contention with h/w initiated CPU power gating */
649         int contention_timeout = 100;
650
651         spin_lock_irqsave(&tegra_powergate_lock, flags);
652
653         status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
654
655         if (status == new_state) {
656                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
657                 return 0;
658         }
659
660         if (TEGRA_IS_CPU_POWERGATE_ID(id)) {
661                 /* CPU ungated in s/w only during boot/resume with outer
662                    waiting loop and no contention from other CPUs */
663                 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
664                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
665                 return 0;
666         }
667
668         do {
669                 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
670                 do {
671                         udelay(1);
672                         status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
673
674                         toggle_timeout--;
675                 } while ((status != new_state) && (toggle_timeout > 0));
676
677                 contention_timeout--;
678         } while ((status != new_state) && (contention_timeout > 0));
679
680         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
681
682         if (status != new_state) {
683                 WARN(1, "Could not set powergate %d to %d", id, new_state);
684                 return -EBUSY;
685         }
686
687         trace_power_domain_target(powergate_partition_info[id].name, new_state,
688                         smp_processor_id());
689 #endif
690
691         return 0;
692 }
693
694 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
695 static bool tegra11x_check_plld_plld2_disable(void)
696 {
697         /* FIXME:
698          * add check for plld and plld2 disable
699          */
700 #define CLK_RST_CONTROLLER_PLLD_BASE_0 0xd0
701 #define CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE_LSB 30
702 #define CLK_RST_CONTROLLER_PLLD2_BASE_0 0x4b8
703 #define CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE_LSB 30
704         u32 status;
705         status = clk_rst_read(CLK_RST_CONTROLLER_PLLD_BASE_0);
706         if (status & (1 << CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE_LSB))
707                 return false;
708         status = clk_rst_read(CLK_RST_CONTROLLER_PLLD2_BASE_0);
709         if (status & (1 << CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE_LSB))
710                 return false;
711         return true;
712 }
713
714 static bool tegra11x_pg_sw_war_missing(int id)
715 {
716         bool ret;
717
718         switch (id) {
719         case TEGRA_POWERGATE_DISA:
720                 /* FIXME:
721                  * [SW WAR bug 954988]:
722                  * Disable PLLD and PLLD2 by clearing bits:
723 a.      CLK_RST_CONTROLLER_PLLD_BASE_0_PLLD_ENABLE
724 b.      CLK_RST_CONTROLLER_PLLD2_BASE_0_PLLD2_ENABLE
725                  * We should not need to disable PLLD and PLLD2
726                  * for linux/android implementation
727                  * adding check in case PLLD or PLLD2 is/are ON
728                  */
729                 ret = tegra11x_check_plld_plld2_disable();
730                 if (!ret)
731                         return true;
732
733                 break;
734         }
735         return false;
736 }
737 #endif
738
739 static int unpowergate_module(int id)
740 {
741         if (id < 0 || id >= tegra_num_powerdomains)
742                 return -EINVAL;
743         return tegra_powergate_set(id, true);
744 }
745
746 static int powergate_module(int id)
747 {
748 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
749         bool need_sw_war;
750 #endif
751         if (id < 0 || id >= tegra_num_powerdomains)
752                 return -EINVAL;
753
754         mc_flush(id);
755 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
756         need_sw_war = tegra11x_pg_sw_war_missing(id);
757         if (need_sw_war) {
758                 pr_err("Error: missing powergate sw war in file: %s, func: %s, line=%d\n",
759                 __FILE__, __func__, __LINE__);
760                 return -1;
761         }
762 #endif
763         return tegra_powergate_set(id, false);
764 }
765
766 bool tegra_powergate_is_powered(int id)
767 {
768         u32 status;
769
770         if (id < 0 || id >= tegra_num_powerdomains)
771                 return -EINVAL;
772
773         status = pmc_read(PWRGATE_STATUS) & (1 << id);
774         return !!status;
775 }
776 EXPORT_SYMBOL(tegra_powergate_is_powered);
777
778 int tegra_powergate_remove_clamping(int id)
779 {
780         u32 mask;
781
782         if (id < 0 || id >= tegra_num_powerdomains)
783                 return -EINVAL;
784
785         /*
786          * PCIE and VDE clamping masks are swapped with respect to their
787          * partition ids
788          */
789         if (id ==  TEGRA_POWERGATE_VDEC)
790                 mask = (1 << TEGRA_POWERGATE_PCIE);
791         else if (id == TEGRA_POWERGATE_PCIE)
792                 mask = (1 << TEGRA_POWERGATE_VDEC);
793         else
794                 mask = (1 << id);
795
796         pmc_write(mask, REMOVE_CLAMPING);
797
798         return 0;
799 }
800
801 static void get_clk_info(int id)
802 {
803         int idx;
804
805         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
806                 if (!powergate_partition_info[id].clk_info[idx].clk_name)
807                         break;
808                 powergate_partition_info[id].
809                                 clk_info[idx].clk_ptr =
810                                         tegra_get_clock_by_name(
811                         powergate_partition_info[id].clk_info[idx].clk_name);
812         }
813 }
814
815 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
816 static bool tegra11x_pug_clk_n_rst_skip(int id, u32 idx)
817 {
818         switch (id) {
819         case TEGRA_POWERGATE_VENC:
820                 if ((!powergate_partition_info[id].clk_info[idx].clk_name) &&
821                         (!(strncmp("csi",
822                         powergate_partition_info[id].clk_info[idx].clk_name,
823                         3)))) {
824                                 /* DIS powered ON then do clk enable CSI */
825                                 if (!tegra_powergate_is_powered(
826                                                 TEGRA_POWERGATE_DISA))
827                                         return true;
828                 }
829                 break;
830         case TEGRA_POWERGATE_DISA:
831                 if ((!powergate_partition_info[id].clk_info[idx].clk_name) &&
832                         (!(strncmp("csi",
833                         powergate_partition_info[id].clk_info[idx].clk_name,
834                         3)))) {
835                                 /* DIS powered ON then do clk enable CSI */
836                                 if (!tegra_powergate_is_powered(
837                                                 TEGRA_POWERGATE_VENC))
838                                         return true;
839                 }
840                 break;
841         }
842         return false;
843 }
844 #endif
845
846 static int partition_clk_enable(int id)
847 {
848         int ret;
849         u32 idx;
850         struct clk *clk;
851         struct partition_clk_info *clk_info;
852 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
853         bool skip_enable;
854 #endif
855
856         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
857
858         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
859 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
860                 skip_enable = tegra11x_pug_clk_n_rst_skip(id, idx);
861                 if (skip_enable)
862                         continue;
863 #endif
864                 clk_info = &powergate_partition_info[id].clk_info[idx];
865                 clk = clk_info->clk_ptr;
866                 if (!clk)
867                         break;
868
869                 if (clk_info->clk_type != RST_ONLY) {
870                         ret = clk_prepare_enable(clk);
871                         if (ret)
872                                 goto err_clk_en;
873                 }
874         }
875
876         return 0;
877
878 err_clk_en:
879         WARN(1, "Could not enable clk %s", clk->name);
880         while (idx--) {
881                 clk_info = &powergate_partition_info[id].clk_info[idx];
882                 if (clk_info->clk_type != RST_ONLY)
883                         clk_disable_unprepare(clk_info->clk_ptr);
884         }
885
886         return ret;
887 }
888
889 static int is_partition_clk_disabled(int id)
890 {
891         u32 idx;
892         struct clk *clk;
893         struct partition_clk_info *clk_info;
894         int ret = 0;
895
896         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
897
898         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
899                 clk_info = &powergate_partition_info[id].clk_info[idx];
900                 clk = clk_info->clk_ptr;
901                 if (!clk)
902                         break;
903
904                 if (clk_info->clk_type != RST_ONLY) {
905                         if (tegra_is_clk_enabled(clk)) {
906                                 ret = -1;
907                                 break;
908                         }
909                 }
910         }
911
912         return ret;
913 }
914
915 static void partition_clk_disable(int id)
916 {
917         u32 idx;
918         struct clk *clk;
919         struct partition_clk_info *clk_info;
920 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
921         bool skip_disable;
922 #endif
923
924         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
925
926         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
927 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
928                 if (id == TEGRA_POWERGATE_DISA) {
929                         skip_disable = tegra11x_pug_clk_n_rst_skip(id, idx);
930                         if (skip_disable)
931                                 continue;
932                 }
933 #endif
934                 clk_info = &powergate_partition_info[id].clk_info[idx];
935                 clk = clk_info->clk_ptr;
936                 if (!clk)
937                         break;
938
939                 if (clk_info->clk_type != RST_ONLY)
940                         clk_disable_unprepare(clk);
941         }
942 }
943
944 static void powergate_partition_assert_reset(int id)
945 {
946         u32 idx;
947         struct clk *clk_ptr;
948         struct partition_clk_info *clk_info;
949 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
950         bool skip_reset;
951 #endif
952
953         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
954
955         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
956 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
957                 if (id == TEGRA_POWERGATE_DISA) {
958                         skip_reset = tegra11x_pug_clk_n_rst_skip(id, idx);
959                         if (skip_reset)
960                                 continue;
961                 }
962 #endif
963                 clk_info = &powergate_partition_info[id].clk_info[idx];
964                 clk_ptr = clk_info->clk_ptr;
965                 if (!clk_ptr)
966                         break;
967                 if (clk_info->clk_type != CLK_ONLY)
968                         tegra_periph_reset_assert(clk_ptr);
969         }
970 }
971
972 static void powergate_partition_deassert_reset(int id)
973 {
974         u32 idx;
975         struct clk *clk_ptr;
976         struct partition_clk_info *clk_info;
977 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
978         bool skip_reset;
979 #endif
980
981         BUG_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
982
983         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
984 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
985                 skip_reset = tegra11x_pug_clk_n_rst_skip(id, idx);
986                 if (skip_reset)
987                         continue;
988 #endif
989                 clk_info = &powergate_partition_info[id].clk_info[idx];
990                 clk_ptr = clk_info->clk_ptr;
991                 if (!clk_ptr)
992                         break;
993                 if (clk_info->clk_type != CLK_ONLY)
994                         tegra_periph_reset_deassert(clk_ptr);
995         }
996 }
997
998 /* Must be called with clk disabled, and returns with clk disabled */
999 static int tegra_powergate_reset_module(int id)
1000 {
1001         int ret;
1002
1003         powergate_partition_assert_reset(id);
1004
1005         udelay(10);
1006
1007         ret = partition_clk_enable(id);
1008         if (ret)
1009                 return ret;
1010
1011         udelay(10);
1012
1013         powergate_partition_deassert_reset(id);
1014
1015         partition_clk_disable(id);
1016
1017         return 0;
1018 }
1019
1020 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
1021 /*
1022  * FIXME: sw war for mipi-cal calibration when unpowergating DISA partition
1023  */
1024 static void tegra11x_mipical_calibrate(void)
1025 {
1026         struct reg_offset_val {
1027                 u32 offset;
1028                 u32 por_value;
1029         };
1030         u32 status;
1031         unsigned long flags;
1032 #define MIPI_CAL_MIPI_CAL_CTRL_0 0x0
1033 #define MIPI_CAL_CIL_MIPI_CAL_STATUS_0 0x8
1034 #define MIPI_CAL_CILA_MIPI_CAL_CONFIG_0 0x14
1035 #define MIPI_CAL_CILB_MIPI_CAL_CONFIG_0 0x18
1036 #define MIPI_CAL_CILC_MIPI_CAL_CONFIG_0 0x1c
1037 #define MIPI_CAL_CILD_MIPI_CAL_CONFIG_0 0x20
1038 #define MIPI_CAL_CILE_MIPI_CAL_CONFIG_0 0x24
1039 #define MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0 0x38
1040 #define MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0 0x3c
1041 #define MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0 0x40
1042 #define MIPI_CAL_DSID_MIPI_CAL_CONFIG_0 0x44
1043         static struct reg_offset_val mipi_cal_por_values[] = {
1044                 { MIPI_CAL_MIPI_CAL_CTRL_0, 0x2a000000 },
1045                 { MIPI_CAL_CILA_MIPI_CAL_CONFIG_0, 0x00200000 },
1046                 { MIPI_CAL_CILB_MIPI_CAL_CONFIG_0, 0x00200000 },
1047                 { MIPI_CAL_CILC_MIPI_CAL_CONFIG_0, 0x00200000 },
1048                 { MIPI_CAL_CILD_MIPI_CAL_CONFIG_0, 0x00200000 },
1049                 { MIPI_CAL_CILE_MIPI_CAL_CONFIG_0, 0x00000000 },
1050                 { MIPI_CAL_DSIA_MIPI_CAL_CONFIG_0, 0x00200000 },
1051                 { MIPI_CAL_DSIB_MIPI_CAL_CONFIG_0, 0x00200000 },
1052                 { MIPI_CAL_DSIC_MIPI_CAL_CONFIG_0, 0x00200000 },
1053                 { MIPI_CAL_DSID_MIPI_CAL_CONFIG_0, 0x00200000 },
1054         };
1055         int i;
1056
1057         spin_lock_irqsave(&tegra_powergate_lock, flags);
1058         /* mipi cal por restore */
1059         for (i = 0; i < ARRAY_SIZE(mipi_cal_por_values); i++) {
1060                 mipi_cal_write(mipi_cal_por_values[i].por_value,
1061                         mipi_cal_por_values[i].offset);
1062         }
1063         /* mipi cal status clear */
1064         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
1065         mipi_cal_write(status, MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
1066         /* mipi cal status read - to flush writes */
1067         status = mipi_cal_read(MIPI_CAL_CIL_MIPI_CAL_STATUS_0);
1068         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
1069         if (status)
1070                 pr_err("Error: mipi_cal calibration failed at file: %s, func: %s, line=%d\n",
1071                 __FILE__, __func__, __LINE__);
1072 }
1073 #endif
1074
1075 /*
1076  * Must be called with clk disabled, and returns with clk disabled
1077  * Drivers should enable clks for partition. Unpowergates only the
1078  * partition.
1079  */
1080 int tegra_unpowergate_partition(int id)
1081 {
1082         int ret;
1083
1084 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
1085         ret = tegra11x_check_partition_pug_seq(id);
1086         if (ret)
1087                 return ret;
1088 #endif
1089         /* If first clk_ptr is null, fill clk info for the partition */
1090         if (!powergate_partition_info[id].clk_info[0].clk_ptr)
1091                 get_clk_info(id);
1092
1093         if (tegra_powergate_is_powered(id))
1094                 return tegra_powergate_reset_module(id);
1095
1096         ret = unpowergate_module(id);
1097         if (ret)
1098                 goto err_power;
1099
1100         powergate_partition_assert_reset(id);
1101
1102         /* Un-Powergating fails if all clks are not enabled */
1103         ret = partition_clk_enable(id);
1104         if (ret)
1105                 goto err_clk_on;
1106
1107         udelay(10);
1108
1109         ret = tegra_powergate_remove_clamping(id);
1110         if (ret)
1111                 goto err_clamp;
1112
1113         udelay(10);
1114
1115 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
1116         tegra11x_mipical_calibrate();
1117 #endif
1118         powergate_partition_deassert_reset(id);
1119
1120         mc_flush_done(id);
1121
1122         /* Disable all clks enabled earlier. Drivers should enable clks */
1123         partition_clk_disable(id);
1124
1125         return 0;
1126
1127 err_clamp:
1128         partition_clk_disable(id);
1129 err_clk_on:
1130         powergate_module(id);
1131 err_power:
1132         WARN(1, "Could not Un-Powergate %d", id);
1133         return ret;
1134 }
1135
1136 int tegra_cpu_powergate_id(int cpuid)
1137 {
1138         if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
1139                 return tegra_cpu_domains[cpuid];
1140
1141         return -EINVAL;
1142 }
1143
1144 int __init tegra_powergate_init(void)
1145 {
1146         switch (tegra_chip_id) {
1147         case TEGRA20:
1148                 tegra_num_powerdomains = 7;
1149                 break;
1150         case TEGRA30:
1151                 tegra_num_powerdomains = 14;
1152                 tegra_num_cpu_domains = 4;
1153                 tegra_cpu_domains = tegra_quad_cpu_domains;
1154                 break;
1155         case TEGRA11X:
1156                 tegra_num_powerdomains = 23;
1157                 tegra_num_cpu_domains = 4;
1158                 tegra_cpu_domains = tegra_quad_cpu_domains;
1159                 break;
1160         default:
1161                 /* Unknown Tegra variant. Disable powergating */
1162                 tegra_num_powerdomains = 0;
1163                 break;
1164         }
1165
1166 #if defined(DEBUG_T11x_POWERGATE)
1167         test_powergate_parts();
1168 #endif
1169 #if defined(DEBUG_T11x_POWERUNGATE)
1170         test_unpowergate_parts();
1171 #endif
1172 #if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
1173         test_powergate_clk_off_parts();
1174 #endif
1175 #if defined(DEBUG_T11x_POWERUNGATE_CLK_ON)
1176         test_unpowergate_clk_on_parts();
1177 #endif
1178         return 0;
1179 }
1180
1181 /*
1182  * Must be called with clk disabled, and returns with clk enabled
1183  * Unpowergates the partition and enables all required clks.
1184  */
1185 int tegra_unpowergate_partition_with_clk_on(int id)
1186 {
1187         int ret = 0;
1188
1189 #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
1190         /* Restrict this functions use to few partitions */
1191         BUG_ON(id != TEGRA_POWERGATE_SATA && id != TEGRA_POWERGATE_PCIE);
1192 #elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
1193         /* Restrict this functions use to few partitions */
1194         BUG_ON(id != TEGRA_POWERGATE_PCIE);
1195 #endif
1196
1197         ret = tegra_unpowergate_partition(id);
1198         if (ret)
1199                 goto err_unpowergating;
1200
1201         /* Enable clks for the partition */
1202         ret = partition_clk_enable(id);
1203         if (ret)
1204                 goto err_unpowergate_clk;
1205
1206         return ret;
1207
1208 err_unpowergate_clk:
1209         tegra_powergate_partition(id);
1210         WARN(1, "Could not Un-Powergate %d, err in enabling clk", id);
1211 err_unpowergating:
1212         WARN(1, "Could not Un-Powergate %d", id);
1213         return ret;
1214 }
1215
1216 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
1217 static int tegra11x_powergate_partition(int id)
1218 {
1219         int ret;
1220
1221         if (tegra_powergate_is_powered(id)) {
1222                 ret = is_partition_clk_disabled(id);
1223                 if (ret < 0) {
1224                         /* clock enabled */
1225                         ret = tegra_powergate_partition_with_clk_off(id);
1226                         if (ret < 0)
1227                                 return ret;
1228                 } else {
1229                         ret = tegra_powergate_partition(id);
1230                         if (ret < 0)
1231                                 return ret;
1232                 }
1233         }
1234         return 0;
1235 }
1236
1237 static int tegra11x_unpowergate_partition(int id)
1238 {
1239         int ret;
1240
1241         if (!tegra_powergate_is_powered(id)) {
1242                 ret = is_partition_clk_disabled(id);
1243                 if (ret) {
1244                         /* clock disabled */
1245                         ret = tegra_unpowergate_partition_with_clk_on(id);
1246                         if (ret < 0)
1247                                 return ret;
1248                 } else {
1249                         ret = tegra_unpowergate_partition(id);
1250                         if (ret < 0)
1251                                 return ret;
1252                 }
1253         }
1254         return 0;
1255 }
1256
1257 static int tegra11x_check_partition_pg_seq(int id)
1258 {
1259         int ret;
1260
1261         switch (id) {
1262         case TEGRA_POWERGATE_DISA:
1263                 ret = tegra11x_powergate_partition(TEGRA_POWERGATE_VENC);
1264                 if (ret < 0)
1265                         return ret;
1266                 ret = tegra11x_powergate_partition(TEGRA_POWERGATE_DISB);
1267                 if (ret < 0)
1268                         return ret;
1269
1270                 break;
1271         }
1272         return 0;
1273 }
1274
1275 static int tegra11x_check_partition_pug_seq(int id)
1276 {
1277         int ret;
1278
1279         switch (id) {
1280         case TEGRA_POWERGATE_DISB:
1281         case TEGRA_POWERGATE_VENC:
1282                 ret = tegra11x_unpowergate_partition(TEGRA_POWERGATE_DISA);
1283                 if (ret < 0)
1284                         return ret;
1285
1286                 break;
1287         }
1288         return 0;
1289 }
1290 #endif
1291
1292 /*
1293  * Must be called with clk disabled. Powergates the partition only
1294  */
1295 int tegra_powergate_partition(int id)
1296 {
1297         int ret;
1298
1299 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
1300         ret = tegra11x_check_partition_pg_seq(id);
1301         if (ret)
1302                 return ret;
1303 #endif
1304         /* If first clk_ptr is null, fill clk info for the partition */
1305         if (powergate_partition_info[id].clk_info[0].clk_ptr)
1306                 get_clk_info(id);
1307         powergate_partition_assert_reset(id);
1308
1309         /* Powergating is done only if refcnt of all clks is 0 */
1310         ret = is_partition_clk_disabled(id);
1311         if (ret)
1312                 goto err_clk_off;
1313
1314         ret = powergate_module(id);
1315         if (ret)
1316                 goto err_power_off;
1317
1318         return 0;
1319
1320 err_power_off:
1321         WARN(1, "Could not Powergate Partition %d", id);
1322 err_clk_off:
1323         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
1324         return ret;
1325 }
1326
1327 int tegra_powergate_partition_with_clk_off(int id)
1328 {
1329         int ret = 0;
1330
1331 #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
1332         /* Restrict functions use to selected partitions */
1333         BUG_ON(id != TEGRA_POWERGATE_PCIE && id != TEGRA_POWERGATE_SATA);
1334 #elif defined(CONFIG_ARCH_TEGRA_2x_SOC)
1335         /* Restrict functions use to selected partitions */
1336         BUG_ON(id != TEGRA_POWERGATE_PCIE);
1337 #endif
1338         /* Disable clks for the partition */
1339         partition_clk_disable(id);
1340
1341         ret = is_partition_clk_disabled(id);
1342         if (ret)
1343                 goto err_powergate_clk;
1344
1345         ret = tegra_powergate_partition(id);
1346         if (ret)
1347                 goto err_powergating;
1348
1349         return ret;
1350
1351 err_powergate_clk:
1352         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
1353 err_powergating:
1354         partition_clk_enable(id);
1355         WARN(1, "Could not Powergate Partition %d", id);
1356         return ret;
1357 }
1358
1359 #if defined(DEBUG_T11x_POWERGATE)
1360 static void test_powergate_parts(void)
1361 {
1362         int i;
1363
1364         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1365                 tegra_powergate_partition(i);
1366 }
1367 #endif
1368
1369 #if defined(DEBUG_T11x_POWERUNGATE)
1370 static void test_powerungate_parts(void)
1371 {
1372         int i;
1373
1374         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1375                 tegra_unpowergate_partition(i);
1376 }
1377 #endif
1378
1379 #if defined(DEBUG_T11x_POWERGATE_CLK_OFF)
1380 static void test_powergate_clk_off_parts(void)
1381 {
1382         int i;
1383
1384         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1385                 tegra_powergate_partition_with_clk_off(i);
1386 }
1387 #endif
1388
1389 #if defined(DEBUG_T11x_POWERUNGATE_CLK_OFF)
1390 static void test_unpowergate_clk_on_parts(void)
1391 {
1392         int i;
1393
1394         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1395                 tegra_unpowergate_partition_with_clk_on(i);
1396 }
1397 #endif
1398
1399 const char *tegra_powergate_get_name(int id)
1400 {
1401         if (id < 0 || id >= TEGRA_NUM_POWERGATE)
1402                 return "invalid";
1403
1404         return powergate_partition_info[id].name;
1405 }
1406
1407 #ifdef CONFIG_DEBUG_FS
1408
1409 static int powergate_show(struct seq_file *s, void *data)
1410 {
1411         int i;
1412         const char *name;
1413
1414         seq_printf(s, " powergate powered\n");
1415         seq_printf(s, "------------------\n");
1416
1417         for (i = 0; i < tegra_num_powerdomains; i++) {
1418                 name = tegra_powergate_get_name(i);
1419                 if (name)
1420                         seq_printf(s, " %9s %7s\n", name,
1421                                 tegra_powergate_is_powered(i) ? "yes" : "no");
1422         }
1423
1424         return 0;
1425 }
1426
1427 static int powergate_open(struct inode *inode, struct file *file)
1428 {
1429         return single_open(file, powergate_show, inode->i_private);
1430 }
1431
1432 static const struct file_operations powergate_fops = {
1433         .open           = powergate_open,
1434         .read           = seq_read,
1435         .llseek         = seq_lseek,
1436         .release        = single_release,
1437 };
1438
1439 int __init tegra_powergate_debugfs_init(void)
1440 {
1441         struct dentry *d;
1442
1443         if (powergate_name) {
1444                 d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
1445                         &powergate_fops);
1446                 if (!d)
1447                         return -ENOMEM;
1448         }
1449
1450         return 0;
1451 }
1452
1453 #endif