ARM: tegra: power: Powergate PCIE and SATA partitions on tegra 3
[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  *
6  * Author:
7  *      Colin Cross <ccross@google.com>
8  *
9  * This software is licensed under the terms of the GNU General Public
10  * License version 2, as published by the Free Software Foundation, and
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/clk.h>
22 #include <linux/debugfs.h>
23 #include <linux/delay.h>
24 #include <linux/err.h>
25 #include <linux/init.h>
26 #include <linux/io.h>
27 #include <linux/seq_file.h>
28 #include <linux/spinlock.h>
29 #include <linux/clk/tegra.h>
30
31 #include <mach/powergate.h>
32
33 #include "clock.h"
34 #include "fuse.h"
35 #include "iomap.h"
36
37 #define PWRGATE_TOGGLE          0x30
38 #define PWRGATE_TOGGLE_START    (1 << 8)
39
40 #define REMOVE_CLAMPING         0x34
41
42 #define PWRGATE_STATUS          0x38
43
44 static int tegra_num_powerdomains;
45 static int tegra_num_cpu_domains;
46 static u8 *tegra_cpu_domains;
47 static u8 tegra30_cpu_domains[] = {
48         TEGRA_POWERGATE_CPU0,
49         TEGRA_POWERGATE_CPU1,
50         TEGRA_POWERGATE_CPU2,
51         TEGRA_POWERGATE_CPU3,
52 };
53
54 #define MC_CLIENT_HOTRESET_CTRL 0x200
55 #define MC_CLIENT_HOTRESET_STAT 0x204
56
57 enum mc_client {
58         MC_CLIENT_AFI   = 0,
59         MC_CLIENT_AVPC  = 1,
60         MC_CLIENT_DC    = 2,
61         MC_CLIENT_DCB   = 3,
62         MC_CLIENT_EPP   = 4,
63         MC_CLIENT_G2    = 5,
64         MC_CLIENT_HC    = 6,
65         MC_CLIENT_HDA   = 7,
66         MC_CLIENT_ISP   = 8,
67         MC_CLIENT_MPCORE        = 9,
68         MC_CLIENT_MPCORELP      = 10,
69         MC_CLIENT_MPE   = 11,
70         MC_CLIENT_NV    = 12,
71         MC_CLIENT_NV2   = 13,
72         MC_CLIENT_PPCS  = 14,
73         MC_CLIENT_SATA  = 15,
74         MC_CLIENT_VDE   = 16,
75         MC_CLIENT_VI    = 17,
76         MC_CLIENT_LAST  = -1,
77 };
78
79 #define MAX_CLK_EN_NUM                  4
80
81 static DEFINE_SPINLOCK(tegra_powergate_lock);
82
83 #define MAX_HOTRESET_CLIENT_NUM         3
84
85 struct partition_clk_info {
86         const char *clk_name;
87         bool only_reset;
88         /* true if clk is only used in assert/deassert reset and not while enable-den*/
89         struct clk *clk_ptr;
90 };
91
92 struct powergate_partition {
93         const char *name;
94         enum mc_client hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
95         struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
96 };
97
98 static struct powergate_partition powergate_partition_info[] = {
99         [TEGRA_POWERGATE_CPU]   = { "cpu0",     {MC_CLIENT_LAST}, },
100         [TEGRA_POWERGATE_L2]    = { "l2",       {MC_CLIENT_LAST}, },
101         [TEGRA_POWERGATE_3D]    = { "3d0",
102                                                 {MC_CLIENT_NV, MC_CLIENT_LAST},
103                                                 {{"3d", false} }, },
104         [TEGRA_POWERGATE_PCIE]  = { "pcie",
105                                                 {MC_CLIENT_AFI, MC_CLIENT_LAST},
106                                                 {{"afi", false},
107                                                 {"pcie", false},
108                                                 {"pciex", true} }, },
109         [TEGRA_POWERGATE_VDEC]  = { "vde",
110                                                 {MC_CLIENT_VDE, MC_CLIENT_LAST},
111                                                 {{"vde", false} }, },
112         [TEGRA_POWERGATE_MPE]   = { "mpe",
113                                                 {MC_CLIENT_MPE, MC_CLIENT_LAST},
114                                                 {{"mpe", false} }, },
115         [TEGRA_POWERGATE_VENC]  = { "ve",
116                                                 {MC_CLIENT_ISP, MC_CLIENT_VI, MC_CLIENT_LAST},
117                                                 {{"isp", false}, {"vi", false},
118                                                 {"csi", false} }, },
119         [TEGRA_POWERGATE_CPU1]  = { "cpu1",     {MC_CLIENT_LAST}, },
120         [TEGRA_POWERGATE_CPU2]  = { "cpu2",     {MC_CLIENT_LAST}, },
121         [TEGRA_POWERGATE_CPU3]  = { "cpu3",     {MC_CLIENT_LAST}, },
122         [TEGRA_POWERGATE_A9LP]  = { "a9lp",     {MC_CLIENT_LAST}, },
123         [TEGRA_POWERGATE_SATA]  = { "sata",     {MC_CLIENT_SATA, MC_CLIENT_LAST},
124                                                 {{"sata", false},
125                                                 {"sata_cold", true} }, },
126         [TEGRA_POWERGATE_3D1]   = { "3d1",
127                                                 {MC_CLIENT_NV2, MC_CLIENT_LAST},
128                                                 {{"3d2", false} }, },
129         [TEGRA_POWERGATE_HEG]   = { "heg",
130                                                 {MC_CLIENT_G2, MC_CLIENT_EPP, MC_CLIENT_HC},
131                                                 {{"2d", false}, {"epp", false},
132                                                 {"host1x", false},
133                                                 {"3d", true} }, },
134 };
135
136 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
137
138 static u32 pmc_read(unsigned long reg)
139 {
140         return readl(pmc + reg);
141 }
142
143 static void pmc_write(u32 val, unsigned long reg)
144 {
145         writel(val, pmc + reg);
146 }
147
148 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
149 static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
150
151 static u32 mc_read(unsigned long reg)
152 {
153         return readl(mc + reg);
154 }
155
156 static void mc_write(u32 val, unsigned long reg)
157 {
158         writel(val, mc + reg);
159 }
160
161 static void mc_flush(int id)
162 {
163         u32 idx, rst_ctrl, rst_stat;
164         enum mc_client mcClientBit;
165         unsigned long flags;
166
167         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
168
169         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
170                 mcClientBit = powergate_partition_info[id].hot_reset_clients[idx];
171                 if (mcClientBit == MC_CLIENT_LAST)
172                         break;
173
174                 spin_lock_irqsave(&tegra_powergate_lock, flags);
175
176                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
177                 rst_ctrl |= (1 << mcClientBit);
178                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
179
180                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
181
182                 do {
183                         udelay(10);
184                         rst_stat = mc_read(MC_CLIENT_HOTRESET_STAT);
185                 } while (!(rst_stat & (1 << mcClientBit)));
186         }
187 }
188
189 static void mc_flush_done(int id)
190 {
191         u32 idx, rst_ctrl;
192         enum mc_client mcClientBit;
193         unsigned long flags;
194
195         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
196
197         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
198                 mcClientBit = powergate_partition_info[id].hot_reset_clients[idx];
199                 if (mcClientBit == MC_CLIENT_LAST)
200                         break;
201
202                 spin_lock_irqsave(&tegra_powergate_lock, flags);
203
204                 rst_ctrl = mc_read(MC_CLIENT_HOTRESET_CTRL);
205                 rst_ctrl &= ~(1 << mcClientBit);
206                 mc_write(rst_ctrl, MC_CLIENT_HOTRESET_CTRL);
207
208                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
209         }
210
211         wmb();
212 }
213 #else
214 static void mc_flush(int id) {}
215 static void mc_flush_done(int id) {}
216 #endif
217
218 static int tegra_powergate_set(int id, bool new_state)
219 {
220         bool status;
221         unsigned long flags;
222
223         spin_lock_irqsave(&tegra_powergate_lock, flags);
224
225         status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
226
227         if (status == new_state) {
228                 spin_unlock_irqrestore(&tegra_powergate_lock, flags);
229                 return -EINVAL;
230         }
231
232         pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
233
234         spin_unlock_irqrestore(&tegra_powergate_lock, flags);
235
236         return 0;
237 }
238
239 static int unpowergate_module(int id)
240 {
241         if (id < 0 || id >= tegra_num_powerdomains)
242                 return -EINVAL;
243         return tegra_powergate_set(id, true);
244 }
245
246 static int powergate_module(int id)
247 {
248         if (id < 0 || id >= tegra_num_powerdomains)
249                 return -EINVAL;
250
251         mc_flush(id);
252         return tegra_powergate_set(id, false);
253 }
254
255 int tegra_powergate_is_powered(int id)
256 {
257         u32 status;
258
259         if (id < 0 || id >= tegra_num_powerdomains)
260                 return -EINVAL;
261
262         status = pmc_read(PWRGATE_STATUS) & (1 << id);
263         return !!status;
264 }
265
266 int tegra_powergate_remove_clamping(int id)
267 {
268         u32 mask;
269         if (id < 0 || id >= tegra_num_powerdomains)
270                 return -EINVAL;
271
272         /*
273          * PCIE and VDE clamping masks are swapped with respect to their
274          * partition ids
275          */
276         if (id ==  TEGRA_POWERGATE_VDEC)
277                 mask = (1 << TEGRA_POWERGATE_PCIE);
278         else if (id == TEGRA_POWERGATE_PCIE)
279                 mask = (1 << TEGRA_POWERGATE_VDEC);
280         else
281                 mask = (1 << id);
282
283         pmc_write(mask, REMOVE_CLAMPING);
284
285         return 0;
286 }
287
288 static void get_clk_info(int id)
289 {
290         int idx;
291
292         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
293                 if (!powergate_partition_info[id].clk_info[idx].clk_name)
294                         break;
295                 powergate_partition_info[id].
296                                 clk_info[idx].clk_ptr =
297                                         tegra_get_clock_by_name(
298                         powergate_partition_info[id].clk_info[idx].clk_name);
299         }
300 }
301
302 static int partition_clk_enable(int id)
303 {
304         int ret;
305         u32 idx;
306         struct clk *clk;
307
308         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
309
310         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
311                 clk = powergate_partition_info[id].clk_info[idx].clk_ptr;
312                 if (!clk)
313                         break;
314
315                 if (!powergate_partition_info[id].clk_info[idx].only_reset) {
316                         ret = clk_prepare_enable(clk);
317                         if (ret)
318                                 goto err_clk_en;
319                 }
320         }
321
322         return 0;
323
324 err_clk_en:
325         WARN(1, "Could not enable clk %s", clk->name);
326         while (idx--) {
327                 if (!powergate_partition_info[id].clk_info[idx].only_reset) {
328                         clk = powergate_partition_info[id].
329                                                 clk_info[idx].clk_ptr;
330                         clk_disable_unprepare(clk);
331                 }
332         }
333
334         return ret;
335 }
336
337 static int is_partition_clk_disabled(int id)
338 {
339         u32 idx;
340         struct clk *clk;
341         int ret = 0;
342
343         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
344
345         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
346                 clk = powergate_partition_info[id].clk_info[idx].clk_ptr;
347                 if (!clk)
348                         break;
349
350                 if (!powergate_partition_info[id].clk_info[idx].only_reset) {
351                         if (tegra_is_clk_enabled(clk)) {
352                                 ret = -1;
353                                 break;
354                         }
355                 }
356         }
357
358         return ret;
359 }
360
361 static void partition_clk_disable(int id)
362 {
363         u32 idx;
364         struct clk *clk;
365
366         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
367
368         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
369                 clk = powergate_partition_info[id].clk_info[idx].clk_ptr;
370                 if (!clk)
371                         break;
372
373                 if (!powergate_partition_info[id].clk_info[idx].only_reset)
374                         clk_disable_unprepare(clk);
375         }
376 }
377
378 static void powergate_partition_assert_reset(int id)
379 {
380         u32 idx;
381
382         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
383
384         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
385                 if (!powergate_partition_info[id].clk_info[idx].clk_ptr)
386                         break;
387                 tegra_periph_reset_assert(
388                         powergate_partition_info[id].
389                                                 clk_info[idx].clk_ptr);
390                 }
391 }
392
393 static void powergate_partition_deassert_reset(int id)
394 {
395         u32 idx;
396
397         BUG_ON(id < 0 || id >= tegra_num_powerdomains);
398
399         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
400                 if (!powergate_partition_info[id].clk_info[idx].clk_ptr)
401                         break;
402                 tegra_periph_reset_deassert(
403                         powergate_partition_info[id].clk_info[idx].clk_ptr);
404         }
405 }
406
407 /* Must be called with clk disabled, and returns with clk disabled */
408 static int tegra_powergate_reset_module(int id)
409 {
410         int ret;
411
412         powergate_partition_assert_reset(id);
413
414         udelay(10);
415
416         ret = partition_clk_enable(id);
417         if (ret)
418                 return ret;
419
420         udelay(10);
421
422         powergate_partition_deassert_reset(id);
423
424         partition_clk_disable(id);
425
426         return 0;
427 }
428
429 /*
430  * Must be called with clk disabled, and returns with clk disabled
431  * Drivers should enable clks for partition. Unpowergates only the
432  * partition.
433  */
434 int tegra_unpowergate_partition(int id)
435 {
436         int ret;
437
438         /* If first clk_ptr is null, fill clk info for the partition */
439         if (!powergate_partition_info[id].clk_info[0].clk_ptr)
440                 get_clk_info(id);
441
442         if (tegra_powergate_is_powered(id))
443                 return tegra_powergate_reset_module(id);
444
445         ret = unpowergate_module(id);
446         if (ret)
447                 goto err_power;
448
449         powergate_partition_assert_reset(id);
450
451         /* Un-Powergating fails if all clks are not enabled */
452         ret = partition_clk_enable(id);
453         if (ret)
454                 goto err_clk_on;
455
456         udelay(10);
457
458         ret = tegra_powergate_remove_clamping(id);
459         if (ret)
460                 goto err_clamp;
461
462         udelay(10);
463         powergate_partition_deassert_reset(id);
464
465         mc_flush_done(id);
466
467         /* Disable all clks enabled earlier. Drivers should enable clks */
468         partition_clk_disable(id);
469
470         return 0;
471
472 err_clamp:
473         partition_clk_disable(id);
474 err_clk_on:
475         powergate_module(id);
476 err_power:
477         WARN(1, "Could not Un-Powergate %d", id);
478         return ret;
479 }
480
481 /*
482  * Must be called with clk disabled, and returns with clk enabled
483  * Unpowergates the partition and enables all required clks.
484  */
485 int tegra_unpowergate_partition_with_clk_on(int id)
486 {
487         int ret = 0;
488
489 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
490         /* Restrict this functions use to few partitions */
491         BUG_ON(id != TEGRA_POWERGATE_SATA && id != TEGRA_POWERGATE_PCIE);
492 #else
493         /* Restrict this functions use to few partitions */
494         BUG_ON(id != TEGRA_POWERGATE_PCIE);
495 #endif
496
497         ret = tegra_unpowergate_partition(id);
498         if (ret)
499                 goto err_unpowergating;
500
501         /* Enable clks for the partition */
502         ret = partition_clk_enable(id);
503         if (ret)
504                 goto err_unpowergate_clk;
505
506         return ret;
507
508 err_unpowergate_clk:
509         tegra_powergate_partition(id);
510         WARN(1, "Could not Un-Powergate %d, err in enabling clk", id);
511 err_unpowergating:
512         WARN(1, "Could not Un-Powergate %d", id);
513         return ret;
514 }
515
516 /*
517  * Must be called with clk disabled. Powergates the partition only
518  */
519 int tegra_powergate_partition(int id)
520 {
521         int ret;
522
523         /* If first clk_ptr is null, fill clk info for the partition */
524         if (powergate_partition_info[id].clk_info[0].clk_ptr)
525                 get_clk_info(id);
526         powergate_partition_assert_reset(id);
527
528         /* Powergating is done only if refcnt of all clks is 0 */
529         ret = is_partition_clk_disabled(id);
530         if (ret)
531                 goto err_clk_off;
532
533         ret = powergate_module(id);
534         if (ret)
535                 goto err_power_off;
536
537         return 0;
538
539 err_power_off:
540         WARN(1, "Could not Powergate Partition %d", id);
541 err_clk_off:
542         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
543         return ret;
544 }
545
546 int tegra_powergate_partition_with_clk_off(int id)
547 {
548         int ret = 0;
549
550 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
551         /* Restrict functions use to selected partitions */
552         BUG_ON(id != TEGRA_POWERGATE_PCIE && id != TEGRA_POWERGATE_SATA);
553 #else
554         /* Restrict functions use to selected partitions */
555         BUG_ON(id != TEGRA_POWERGATE_PCIE);
556 #endif
557         /* Disable clks for the partition */
558         partition_clk_disable(id);
559
560         ret = is_partition_clk_disabled(id);
561         if (ret)
562                 goto err_powergate_clk;
563
564         ret = tegra_powergate_partition(id);
565         if (ret)
566                 goto err_powergating;
567
568         return ret;
569
570 err_powergate_clk:
571         WARN(1, "Could not Powergate Partition %d, all clks not disabled", id);
572 err_powergating:
573         partition_clk_enable(id);
574         WARN(1, "Could not Powergate Partition %d", id);
575         return ret;
576 }
577
578 int tegra_cpu_powergate_id(int cpuid)
579 {
580         if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
581                 return tegra_cpu_domains[cpuid];
582
583         return -EINVAL;
584 }
585
586 int __init tegra_powergate_init(void)
587 {
588         switch (tegra_chip_id) {
589         case TEGRA20:
590                 tegra_num_powerdomains = 7;
591                 break;
592         case TEGRA30:
593                 tegra_num_powerdomains = 14;
594                 tegra_num_cpu_domains = 4;
595                 tegra_cpu_domains = tegra30_cpu_domains;
596                 break;
597         default:
598                 /* Unknown Tegra variant. Disable powergating */
599                 tegra_num_powerdomains = 0;
600                 break;
601         }
602
603         return 0;
604 }
605
606 const char *tegra_powergate_get_name(int id)
607 {
608         if (id < 0 || id >= tegra_num_powerdomains)
609                 return "invalid";
610
611         return powergate_partition_info[id].name;
612 }
613
614 #ifdef CONFIG_DEBUG_FS
615
616 static int powergate_show(struct seq_file *s, void *data)
617 {
618         int i;
619
620         seq_printf(s, " powergate powered\n");
621         seq_printf(s, "------------------\n");
622
623         for (i = 0; i < tegra_num_powerdomains; i++)
624                 seq_printf(s, " %9s %7s\n", powergate_partition_info[i].name,
625                         tegra_powergate_is_powered(i) ? "yes" : "no");
626         return 0;
627 }
628
629 static int powergate_open(struct inode *inode, struct file *file)
630 {
631         return single_open(file, powergate_show, inode->i_private);
632 }
633
634 static const struct file_operations powergate_fops = {
635         .open           = powergate_open,
636         .read           = seq_read,
637         .llseek         = seq_lseek,
638         .release        = single_release,
639 };
640
641 int __init tegra_powergate_debugfs_init(void)
642 {
643         struct dentry *d;
644
645         if (powergate_name) {
646                 d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
647                         &powergate_fops);
648                 if (!d)
649                         return -ENOMEM;
650         }
651
652         return 0;
653 }
654
655 #endif