import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / mt_sleep.c
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/spinlock.h>
5 #include <linux/suspend.h>
6 #include <linux/console.h>
7 #include <linux/aee.h>
8
9 #include <mach/sync_write.h>
10 #include <mach/mt_sleep.h>
11 #include <mach/mt_spm.h>
12 #include <mach/mt_spm_sleep.h>
13 #include <mach/mt_spm_mtcmos.h>
14 #include <mach/mt_clkmgr.h>
15 #include <mach/mt_gpio.h>
16
17 /**************************************
18 * only for internal debug
19 **************************************/
20 #ifdef CONFIG_MTK_LDVT
21 #define SLP_SLEEP_DPIDLE_EN 1
22 #define SLP_REPLACE_DEF_WAKESRC 1
23 #define SLP_SUSPEND_LOG_EN 1
24 #else
25 #define SLP_SLEEP_DPIDLE_EN 1
26 #define SLP_REPLACE_DEF_WAKESRC 0
27 #define SLP_SUSPEND_LOG_EN 1
28 #endif
29
30
31 /**************************************
32 * SW code for suspend
33 **************************************/
34 #define slp_read(addr) (*(volatile u32 *)(addr))
35 #define slp_write(addr, val) mt65xx_reg_sync_writel(val, addr)
36
37 #define slp_emerg(fmt, args...) printk(KERN_EMERG "[SLP] " fmt, ##args)
38 #define slp_alert(fmt, args...) printk(KERN_ALERT "[SLP] " fmt, ##args)
39 #define slp_crit(fmt, args...) printk(KERN_CRIT "[SLP] " fmt, ##args)
40 #define slp_error(fmt, args...) printk(KERN_ERR "[SLP] " fmt, ##args)
41 #define slp_warning(fmt, args...) printk(KERN_WARNING "[SLP] " fmt, ##args)
42 #define slp_notice(fmt, args...) printk(KERN_NOTICE "[SLP] " fmt, ##args)
43 #define slp_info(fmt, args...) printk(KERN_INFO "[SLP] " fmt, ##args)
44 #define slp_debug(fmt, args...) printk(KERN_DEBUG "[SLP] " fmt, ##args)
45
46 #define slp_crit2(fmt, args...) \
47 do { \
48 aee_sram_printk(fmt, ##args); \
49 slp_crit(fmt, ##args); \
50 } while (0)
51
52 extern void mt_power_gs_dump_suspend(void);
53
54 static DEFINE_SPINLOCK(slp_lock);
55
56 static wake_reason_t slp_wake_reason = WR_NONE;
57
58 static bool slp_ck26m_on = 0;
59
60 /*
61 * SLEEP_DPIDLE_EN:1 && slp_ck26m_on=1
62 * 1 = CPU dormant
63 * 0 = CPU standby
64 * SLEEP_DPIDLE_EN:0 || slp_ck26m_on=0
65 * 1 = CPU shutdown
66 * 0 = CPU standby
67 */
68 static bool slp_cpu_pdn = 1;
69
70 /*
71 * SLEEP_DPIDLE_EN:0 || slp_ck26m_on=0
72 * 1 = INFRA/DDRPHY power down
73 * 0 = keep INFRA/DDRPHY power
74 */
75 #ifndef MTK_ALPS_BOX_SUPPORT
76 static bool slp_infra_pdn = 1;
77 #else
78 static bool slp_infra_pdn = 0;
79 #endif
80 /*
81 * SLEEP_DPIDLE_EN:1 && slp_ck26m_on=1
82 * 0 = AXI is off
83 * 1 = AXI is 26M
84 */
85 static u16 slp_pwrlevel = 0;
86
87 static int slp_pwake_time = -1; /* sec */
88
89 static bool slp_chk_golden = 0;
90 static bool slp_dump_gpio = 0;
91 static bool slp_dump_regs = 0;
92
93 static void slp_dump_pm_regs(void)
94 {
95 /* PLL/TOPCKGEN register */
96 slp_debug("AP_PLL_CON0 0x%x = 0x%x\n", AP_PLL_CON0 , slp_read(AP_PLL_CON0));
97 slp_debug("AP_PLL_CON1 0x%x = 0x%x\n", AP_PLL_CON1 , slp_read(AP_PLL_CON1));
98 slp_debug("AP_PLL_CON2 0x%x = 0x%x\n", AP_PLL_CON2 , slp_read(AP_PLL_CON2));
99 slp_debug("UNIVPLL_CON0 0x%x = 0x%x\n", UNIVPLL_CON0 , slp_read(UNIVPLL_CON0));
100 slp_debug("UNIVPLL_PWR_CON 0x%x = 0x%x\n", UNIVPLL_PWR_CON0 , slp_read(UNIVPLL_PWR_CON0));
101 slp_debug("MMPLL_CON0 0x%x = 0x%x\n", MMPLL_CON0 , slp_read(MMPLL_CON0));
102 slp_debug("MMPLL_PWR_CON 0x%x = 0x%x\n", MMPLL_PWR_CON0 , slp_read(MMPLL_PWR_CON0));
103 slp_debug("CLK_SCP_CFG_0 0x%x = 0x%x\n", CLK_SCP_CFG_0 , slp_read(CLK_SCP_CFG_0));
104 slp_debug("CLK_SCP_CFG_1 0x%x = 0x%x\n", CLK_SCP_CFG_1 , slp_read(CLK_SCP_CFG_1));
105
106 /* INFRA/PERICFG register */
107 slp_debug("INFRA_PDN_STA 0x%x = 0x%x\n", INFRA_PDN_STA , slp_read(INFRA_PDN_STA));
108 slp_debug("PERI_PDN0_STA 0x%x = 0x%x\n", PERI_PDN0_STA , slp_read(PERI_PDN0_STA));
109
110 /* SPM register */
111 slp_debug("POWER_ON_VAL0 0x%x = 0x%x\n", SPM_POWER_ON_VAL0 , slp_read(SPM_POWER_ON_VAL0));
112 slp_debug("POWER_ON_VAL1 0x%x = 0x%x\n", SPM_POWER_ON_VAL1 , slp_read(SPM_POWER_ON_VAL1));
113 slp_debug("SPM_PCM_CON1 0x%x = 0x%x\n", SPM_PCM_CON1 , slp_read(SPM_PCM_CON1));
114 slp_debug("PCM_PWR_IO_EN 0x%x = 0x%x\n", SPM_PCM_PWR_IO_EN , slp_read(SPM_PCM_PWR_IO_EN));
115 slp_debug("PCM_REG0_DATA 0x%x = 0x%x\n", SPM_PCM_REG0_DATA , slp_read(SPM_PCM_REG0_DATA));
116 slp_debug("PCM_REG7_DATA 0x%x = 0x%x\n", SPM_PCM_REG7_DATA , slp_read(SPM_PCM_REG7_DATA));
117 slp_debug("PCM_REG13_DATA 0x%x = 0x%x\n", SPM_PCM_REG13_DATA , slp_read(SPM_PCM_REG13_DATA));
118 slp_debug("CLK_CON 0x%x = 0x%x\n", SPM_CLK_CON , slp_read(SPM_CLK_CON));
119 slp_debug("AP_DVFS_CON 0x%x = 0x%x\n", SPM_AP_DVFS_CON_SET, slp_read(SPM_AP_DVFS_CON_SET));
120 slp_debug("PWR_STATUS 0x%x = 0x%x\n", SPM_PWR_STATUS , slp_read(SPM_PWR_STATUS));
121 slp_debug("SPM_PCM_SRC_REQ 0x%x = 0x%x\n", SPM_PCM_SRC_REQ , slp_read(SPM_PCM_SRC_REQ));
122 }
123
124 static int slp_suspend_ops_valid(suspend_state_t state)
125 {
126 return state == PM_SUSPEND_MEM;
127 }
128
129 static int slp_suspend_ops_begin(suspend_state_t state)
130 {
131 /* legacy log */
132 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
133 slp_notice("Chip_pm_begin(%u)(%u)\n", slp_cpu_pdn, slp_infra_pdn);
134 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
135
136 slp_wake_reason = WR_NONE;
137
138 return 0;
139 }
140
141 static int slp_suspend_ops_prepare(void)
142 {
143 /* legacy log */
144 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
145 slp_crit2("Chip_pm_prepare\n");
146 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
147
148 if (slp_chk_golden)
149 mt_power_gs_dump_suspend();
150
151 return 0;
152 }
153
154 static int slp_suspend_ops_enter(suspend_state_t state)
155 {
156 /* legacy log */
157 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
158 slp_crit2("Chip_pm_enter\n");
159 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
160
161 if (slp_dump_gpio)
162 gpio_dump_regs();
163
164 if (slp_dump_regs)
165 slp_dump_pm_regs();
166
167 if (!spm_cpusys_can_power_down()) {
168 slp_error("CANNOT SLEEP DUE TO CPU1/2/3 PON\n");
169 return -EPERM;
170 }
171
172 if (slp_infra_pdn && !slp_cpu_pdn) {
173 slp_error("CANNOT SLEEP DUE TO INFRA PDN BUT CPU PON\n");
174 return -EPERM;
175 }
176
177 #if SLP_SLEEP_DPIDLE_EN
178 if (slp_ck26m_on)
179 slp_wake_reason = spm_go_to_sleep_dpidle(slp_cpu_pdn, slp_pwrlevel, slp_pwake_time);
180 else
181 #endif
182 slp_wake_reason = spm_go_to_sleep(slp_cpu_pdn, slp_infra_pdn, slp_pwake_time);
183
184 return 0;
185 }
186
187 static void slp_suspend_ops_finish(void)
188 {
189 /* legacy log */
190 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
191 slp_crit2("Chip_pm_finish\n");
192 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
193 }
194
195 static void slp_suspend_ops_end(void)
196 {
197 /* legacy log */
198 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
199 slp_notice("Chip_pm_end\n");
200 slp_notice("@@@@@@@@@@@@@@@@@@@@\n");
201 }
202
203 static struct platform_suspend_ops slp_suspend_ops = {
204 .valid = slp_suspend_ops_valid,
205 .begin = slp_suspend_ops_begin,
206 .prepare = slp_suspend_ops_prepare,
207 .enter = slp_suspend_ops_enter,
208 .finish = slp_suspend_ops_finish,
209 .end = slp_suspend_ops_end,
210 };
211
212 /*
213 * wakesrc : WAKE_SRC_XXX
214 * enable : enable or disable @wakesrc
215 * ck26m_on: if true, mean @wakesrc needs 26M to work
216 */
217 int slp_set_wakesrc(u32 wakesrc, bool enable, bool ck26m_on)
218 {
219 int r;
220 unsigned long flags;
221
222 slp_notice("wakesrc = 0x%x, enable = %u, ck26m_on = %u\n",
223 wakesrc, enable, ck26m_on);
224
225 #if SLP_REPLACE_DEF_WAKESRC
226 if (wakesrc & WAKE_SRC_CFG_KEY)
227 #else
228 if (!(wakesrc & WAKE_SRC_CFG_KEY))
229 #endif
230 return -EPERM;
231
232 spin_lock_irqsave(&slp_lock, flags);
233 #if SLP_REPLACE_DEF_WAKESRC
234 r = spm_set_sleep_wakesrc(wakesrc, enable, true);
235 #else
236 r = spm_set_sleep_wakesrc(wakesrc & ~WAKE_SRC_CFG_KEY, enable, false);
237 #endif
238
239 if (!r)
240 slp_ck26m_on = ck26m_on;
241 spin_unlock_irqrestore(&slp_lock, flags);
242
243 return r;
244 }
245
246 wake_reason_t slp_get_wake_reason(void)
247 {
248 return slp_wake_reason;
249 }
250
251 bool slp_will_infra_pdn(void)
252 {
253 return slp_infra_pdn;
254 }
255
256 void slp_module_init(void)
257 {
258 spm_output_sleep_option();
259
260 slp_notice("SLEEP_DPIDLE_EN:%d, REPLACE_DEF_WAKESRC:%d, SUSPEND_LOG_EN:%d\n",
261 SLP_SLEEP_DPIDLE_EN, SLP_REPLACE_DEF_WAKESRC, SLP_SUSPEND_LOG_EN);
262
263 suspend_set_ops(&slp_suspend_ops);
264
265 #if SLP_SUSPEND_LOG_EN
266 console_suspend_enabled = 0;
267 #endif
268 }
269
270 module_param(slp_ck26m_on, bool, 0644);
271
272 module_param(slp_cpu_pdn, bool, 0644);
273 module_param(slp_infra_pdn, bool, 0644);
274 module_param(slp_pwrlevel, ushort, 0644);
275
276 module_param(slp_pwake_time, int, 0644);
277
278 module_param(slp_chk_golden, bool, 0644);
279 module_param(slp_dump_gpio, bool, 0644);
280 module_param(slp_dump_regs, bool, 0644);
281
282 MODULE_AUTHOR("Terry Chang <terry.chang@mediatek.com>");
283 MODULE_DESCRIPTION("Sleep Driver v0.4");