Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
[pandora-kernel.git] / arch / arm / mach-shmobile / pm-sh7372.c
1 /*
2  * sh7372 Power management support
3  *
4  *  Copyright (C) 2011 Magnus Damm
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10
11 #include <linux/pm.h>
12 #include <linux/suspend.h>
13 #include <linux/cpuidle.h>
14 #include <linux/module.h>
15 #include <linux/list.h>
16 #include <linux/err.h>
17 #include <linux/slab.h>
18 #include <asm/system.h>
19 #include <asm/io.h>
20 #include <asm/tlbflush.h>
21 #include <mach/common.h>
22
23 #define SMFRAM 0xe6a70000
24 #define SYSTBCR 0xe6150024
25 #define SBAR 0xe6180020
26 #define APARMBAREA 0xe6f10020
27
28 static void sh7372_enter_core_standby(void)
29 {
30         void __iomem *smfram = (void __iomem *)SMFRAM;
31
32         __raw_writel(0, APARMBAREA); /* translate 4k */
33         __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
34         __raw_writel(0x10, SYSTBCR); /* enable core standby */
35
36         __raw_writel(0, smfram + 0x3c); /* clear page table address */
37
38         sh7372_cpu_suspend();
39         cpu_init();
40
41         /* if page table address is non-NULL then we have been powered down */
42         if (__raw_readl(smfram + 0x3c)) {
43                 __raw_writel(__raw_readl(smfram + 0x40),
44                              __va(__raw_readl(smfram + 0x3c)));
45
46                 flush_tlb_all();
47                 set_cr(__raw_readl(smfram + 0x38));
48         }
49
50         __raw_writel(0, SYSTBCR); /* disable core standby */
51         __raw_writel(0, SBAR); /* disable reset vector translation */
52 }
53
54 #ifdef CONFIG_CPU_IDLE
55 static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
56 {
57         struct cpuidle_state *state;
58         int i = dev->state_count;
59
60         state = &dev->states[i];
61         snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
62         strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
63         state->exit_latency = 10;
64         state->target_residency = 20 + 10;
65         state->power_usage = 1; /* perhaps not */
66         state->flags = 0;
67         state->flags |= CPUIDLE_FLAG_TIME_VALID;
68         shmobile_cpuidle_modes[i] = sh7372_enter_core_standby;
69
70         dev->state_count = i + 1;
71 }
72
73 static void sh7372_cpuidle_init(void)
74 {
75         shmobile_cpuidle_setup = sh7372_cpuidle_setup;
76 }
77 #else
78 static void sh7372_cpuidle_init(void) {}
79 #endif
80
81 #ifdef CONFIG_SUSPEND
82 static int sh7372_enter_suspend(suspend_state_t suspend_state)
83 {
84         sh7372_enter_core_standby();
85         return 0;
86 }
87
88 static void sh7372_suspend_init(void)
89 {
90         shmobile_suspend_ops.enter = sh7372_enter_suspend;
91 }
92 #else
93 static void sh7372_suspend_init(void) {}
94 #endif
95
96 #define DBGREG1 0xe6100020
97 #define DBGREG9 0xe6100040
98
99 void __init sh7372_pm_init(void)
100 {
101         /* enable DBG hardware block to kick SYSC */
102         __raw_writel(0x0000a500, DBGREG9);
103         __raw_writel(0x0000a501, DBGREG9);
104         __raw_writel(0x00000000, DBGREG1);
105
106         sh7372_suspend_init();
107         sh7372_cpuidle_init();
108 }