Merge tag 'v3.10.55' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / mt_spm_idle.c
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/spinlock.h>
5 #include <linux/proc_fs.h>
6 #include <linux/platform_device.h>
7 #include <linux/earlysuspend.h>
8 #include <linux/sched.h>
9 #include <linux/kthread.h>
10 #include <linux/err.h>
11 #include <linux/delay.h>
12 #include <linux/aee.h>
13
14 #include <mach/irqs.h>
15 #include <mach/mt_spm.h>
16 #include <mach/mt_spm_idle.h>
17 #include <mach/mt_dormant.h>
18 #include <mach/mt_gpt.h>
19 #include <mach/mt_reg_base.h>
20 #include <mach/mt_spm_sleep.h>
21
22 #include <asm/hardware/gic.h>
23
24 //#include <mach/wd_api.h>
25
26 #ifdef SPM_SODI_ENABLED
27
28 #define SPM_MCDI_DEBUG 0
29 #define SPM_MCDI_BYPASS_SYSPWREQ 1
30
31
32 //DEFINE_SPINLOCK(spm_sodi_lock);
33
34 s32 gSpm_Sodi_Disable_Counter = 0;
35 bool gSpm_IsLcmVideoMode = TRUE;
36 u32 gSPM_SODI_EN = 0; // flag for idle task
37
38 #define PCM_WDT_TIMEOUT (30 * 32768) /* 30s */
39 #define PCM_TIMER_MAX_FOR_WDT (0xffffffff - PCM_WDT_TIMEOUT)
40
41
42 #define mcdi_wfi_with_sync() \
43 do { \
44 isb(); \
45 dsb(); \
46 __asm__ __volatile__("wfi" : : : "memory"); \
47 } while (0)
48
49
50 //TODO: need check
51 #if SPM_MCDI_BYPASS_SYSPWREQ
52 #define WAKE_SRC_FOR_MCDI \
53 (WAKE_SRC_GPT | WAKE_SRC_THERM | WAKE_SRC_CIRQ | WAKE_SRC_CPU0_IRQ | WAKE_SRC_CPU1_IRQ | WAKE_SRC_SYSPWREQ )
54 //(WAKE_SRC_PCM_TIMER | WAKE_SRC_GPT | WAKE_SRC_THERM | WAKE_SRC_CIRQ | WAKE_SRC_CPU0_IRQ | WAKE_SRC_CPU1_IRQ | WAKE_SRC_SYSPWREQ )
55 #else
56 #define WAKE_SRC_FOR_MCDI \
57 (WAKE_SRC_GPT | WAKE_SRC_THERM | WAKE_SRC_CIRQ | WAKE_SRC_CPU0_IRQ | WAKE_SRC_CPU1_IRQ )
58 // (WAKE_SRC_PCM_TIMER | WAKE_SRC_GPT | WAKE_SRC_THERM | WAKE_SRC_CIRQ | WAKE_SRC_CPU0_IRQ | WAKE_SRC_CPU1_IRQ )
59 #endif
60 #define WAKE_SRC_FOR_SODI \
61 (WAKE_SRC_KP | WAKE_SRC_GPT | WAKE_SRC_EINT | WAKE_SRC_CCIF_MD | \
62 WAKE_SRC_USB_CD | WAKE_SRC_USB_PDN | WAKE_SRC_AFE | \
63 WAKE_SRC_SYSPWREQ | WAKE_SRC_MD_WDT | WAKE_SRC_CONN_WDT | WAKE_SRC_CONN | WAKE_SRC_THERM| WAKE_SRC_CPU0_IRQ)
64
65
66 // ==========================================
67 // PCM code for SODI (Screen On Deep Idle) pcm_sodi_v0.15_20130802_MT6582
68 //
69 // core 0 : GPT 4
70 // ==========================================
71 static u32 __pcm_sodidle[] = {
72
73 0x88000000, 0xfffffffb, 0x89c00007, 0xfffffffd, 0x89c00007, 0xfffbfeff,
74 0x1950001f, 0x10006360, 0x02401409, 0xa9c00007, 0x00010400, 0x1b00001f,
75 0xbfffe7ff, 0xf0000000, 0x17c07c1f, 0x1b80001f, 0x20000020, 0x8980000d,
76 0x00000010, 0xd82002e6, 0x17c07c1f, 0x1b80001f, 0x20000fdf, 0x8880000d,
77 0x00000124, 0xd80005a2, 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0x8880000c,
78 0x3fffe7ff, 0xd80005a2, 0x17c07c1f, 0x89c00007, 0xfffeffff, 0xa1d40407,
79 0x1b80001f, 0x20000008, 0xa1d90407, 0xc0c00e80, 0x17c07c1f, 0xd80005a3,
80 0x17c07c1f, 0xa8000000, 0x00000004, 0x1b00001f, 0x7fffe7ff, 0xf0000000,
81 0x17c07c1f, 0xe0e00f16, 0x1380201f, 0xe0e00f1e, 0x1380201f, 0xe0e00f0e,
82 0x1380201f, 0xe0e00f0c, 0xe0e00f0d, 0xe0e00e0d, 0xe0e00c0d, 0xe0e0080d,
83 0xe0e0000d, 0xf0000000, 0x17c07c1f, 0x6aa00003, 0x10006234, 0xd800092a,
84 0x17c07c1f, 0xe0e00f0d, 0xe0e00f0f, 0xe0e00f1e, 0xe0e00f12, 0xd8200aaa,
85 0x17c07c1f, 0xe8208000, 0x10006234, 0x000f0f0d, 0xe8208000, 0x10006234,
86 0x000f0f0f, 0xe8208000, 0x10006234, 0x000f0f1e, 0xe8208000, 0x10006234,
87 0x000f0f12, 0xf0000000, 0x17c07c1f, 0xd8000bea, 0x17c07c1f, 0xe2e00036,
88 0x1380201f, 0xe2e0003e, 0x1380201f, 0xe2e0002e, 0x1380201f, 0xd8200cea,
89 0x17c07c1f, 0xe2e0006e, 0xe2e0004e, 0xe2e0004c, 0x1b80001f, 0x20000020,
90 0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xd8000daa, 0x17c07c1f, 0xe2e0006d,
91 0xe2e0002d, 0xd8200e4a, 0x17c07c1f, 0xe2e0002f, 0xe2e0003e, 0xe2e00032,
92 0xf0000000, 0x17c07c1f, 0x89c00007, 0xfffffbff, 0xa9c00007, 0x00000200,
93 0x1950001f, 0x100041dc, 0xba008005, 0xff00ffff, 0x000a0000, 0xe1000008,
94 0xa1d08407, 0x1b80001f, 0x20000020, 0x80eab401, 0x1a00001f, 0x10006814,
95 0xe2000003, 0xba008005, 0xff00ffff, 0x00640000, 0xe1000008, 0xf0000000,
96 0x17c07c1f, 0x1a00001f, 0x10006604, 0xd8001223, 0x17c07c1f, 0xd8201223,
97 0x17c07c1f, 0xf0000000, 0x17c07c1f, 0x1a10001f, 0x10002058, 0x1a80001f,
98 0x10002058, 0xaa000008, 0x80000000, 0xe2800008, 0xf0000000, 0x17c07c1f,
99 0xa1d40407, 0x1b80001f, 0x20000008, 0xa1d90407, 0xf0000000, 0x17c07c1f,
100 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
101 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
102 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
103 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
104 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
105 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
106 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
107 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
108 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
109 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
110 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
111 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
112 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
113 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
114 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
115 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001,
116 0x12407c1f, 0x1b00001f, 0x3fffe7ff, 0x1b80001f, 0xd00f0000, 0x8880000c,
117 0x3fffe7ff, 0xd8003242, 0x17c07c1f, 0x1950001f, 0x10006400, 0x80d70405,
118 0xd8002683, 0x17c07c1f, 0x89c00007, 0xffffefff, 0x18c0001f, 0x10006200,
119 0xc0c00d20, 0x12807c1f, 0xe8208000, 0x1000625c, 0x00000001, 0x1b80001f,
120 0x20000080, 0xc0c00d20, 0x1280041f, 0x18c0001f, 0x10006208, 0xc0c00d20,
121 0x12807c1f, 0xe8208000, 0x10006248, 0x00000000, 0x1b80001f, 0x20000080,
122 0xc0c00d20, 0x1280041f, 0xa9c00007, 0x00000080, 0xc0c01260, 0x17c07c1f,
123 0xa8000000, 0x00000002, 0xa8000000, 0x00000200, 0xa8000000, 0x00800000,
124 0xa8000000, 0x00020000, 0x1890001f, 0x10006400, 0x80868801, 0xd82027e2,
125 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0x1b80001f, 0xd0100000, 0xd0002d00,
126 0x17c07c1f, 0x1b00001f, 0xffffffff, 0x8880000c, 0x3fffe7ff, 0xd8002d02,
127 0x17c07c1f, 0x8880000c, 0x40000000, 0xd80027e2, 0x17c07c1f, 0x89c00007,
128 0xfffeffff, 0xc0c01380, 0x17c07c1f, 0xc0c00e80, 0x17c07c1f, 0xd8002ba3,
129 0x17c07c1f, 0xa8000000, 0x00000004, 0xe8208000, 0x10006310, 0x0b160038,
130 0x1b00001f, 0x7fffe7ff, 0x1b80001f, 0x90100000, 0xe8208000, 0x10006310,
131 0x0b160008, 0x88000000, 0xfffffffb, 0x89c00007, 0xfffffffd, 0x89c00007,
132 0xfffbfeff, 0x1950001f, 0x10006360, 0x02401409, 0xa9c00007, 0x00010400,
133 0x80d70405, 0xd8003243, 0x17c07c1f, 0x88000000, 0xfffdffff, 0x1b80001f,
134 0x20000300, 0x88000000, 0xff7fffff, 0x1b80001f, 0x20000300, 0x88000000,
135 0xfffffdff, 0x88000000, 0xfffffffd, 0x1b80001f, 0x2000049c, 0x89c00007,
136 0xffffff7f, 0x18c0001f, 0x10006208, 0x1212841f, 0xc0c00ae0, 0x12807c1f,
137 0xe8208000, 0x10006248, 0x00000001, 0x1b80001f, 0x20000080, 0xc0c00ae0,
138 0x1280041f, 0x18c0001f, 0x10006200, 0xc0c00ae0, 0x12807c1f, 0xe8208000,
139 0x1000625c, 0x00000000, 0x1b80001f, 0x20000080, 0xc0c00ae0, 0x1280041f,
140 0xa9c00007, 0x00011000, 0xe8208000, 0x10006b10, 0x00000000, 0x19c0001f,
141 0x00015820, 0x12c0241f, 0x10007c1f, 0x80cab001, 0x808cb401, 0x80800c02,
142 0xd8203422, 0x17c07c1f, 0xa1d78407, 0x1240301f, 0xe8208000, 0x100063e0,
143 0x00000001, 0x1b00001f, 0x00202000, 0x1b80001f, 0x80001000, 0x8880000c,
144 0x00200000, 0xd8003642, 0x17c07c1f, 0xe8208000, 0x100063e0, 0x00000002,
145 0x1b80001f, 0x00001000, 0x809c840d, 0xd82034a2, 0x17c07c1f, 0xa1d78407,
146 0x1890001f, 0x10006014, 0x18c0001f, 0x10006014, 0xa0978402, 0xe0c00002,
147 0x1b80001f, 0x00001000, 0xf0000000
148
149 };
150
151 #define MCDI_PCM_PC_0 0
152 #define MCDI_PCM_PC_1 15
153
154 static const pcm_desc_t pcm_sodidle = {
155 .base = __pcm_sodidle,
156 .size = 445,
157 .vec0 = EVENT_VEC(30, 1, 0, MCDI_PCM_PC_0), /* AP-wake event */
158 .vec1 = EVENT_VEC(31, 1, 0, MCDI_PCM_PC_1), /* AP-sleep event */
159 };
160
161
162 #define spm_error2(fmt, args...) \
163 do { \
164 aee_sram_printk(fmt, ##args); \
165 spm_error(fmt, ##args); \
166 } while (0)
167
168
169 typedef struct {
170 u32 debug_reg; /* PCM_REG_DATA_INI */
171 u32 r12; /* PCM_REG12_DATA */
172 u32 raw_sta; /* SLEEP_ISR_RAW_STA */
173 u32 cpu_wake; /* SLEEP_CPU_WAKEUP_EVENT */
174 u32 timer_out; /* PCM_TIMER_OUT */
175 u32 event_reg; /* PCM_EVENT_REG_STA */
176 u32 isr; /* SLEEP_ISR_STATUS */
177 u32 r13; /* PCM_REG13_DATA */
178 } wake_status_t;
179
180
181 //extern void mtk_wdt_suspend(void);
182 //extern void mtk_wdt_resume(void);
183 extern int mt_irq_mask_all(struct mtk_irq_mask *mask);
184 extern int mt_irq_mask_restore(struct mtk_irq_mask *mask);
185 //extern int mt_SPI_mask_all(struct mtk_irq_mask *mask);
186 //extern int mt_SPI_mask_restore(struct mtk_irq_mask *mask);
187 //extern int mt_PPI_mask_all(struct mtk_irq_mask *mask);
188 //extern int mt_PPI_mask_restore(struct mtk_irq_mask *mask);
189 //extern void mt_irq_mask_for_sleep(unsigned int irq);
190 extern void mt_irq_unmask_for_sleep(unsigned int irq);
191 extern void mt_cirq_enable(void);
192 extern void mt_cirq_disable(void);
193 extern void mt_cirq_clone_gic(void);
194 extern void mt_cirq_flush(void);
195 //extern void mt_cirq_mask(unsigned int cirq_num);
196 //extern void mt_cirq_mask_all(void);
197
198 extern void mcidle_before_wfi(int cpu);
199 extern void mcidle_after_wfi(int cpu);
200
201 void __attribute__((weak)) mcidle_before_wfi(int cpu)
202 {
203 }
204
205 void __attribute__((weak)) mcidle_after_wfi(int cpu)
206 {
207 }
208
209 extern spinlock_t spm_lock;
210
211 #if SPM_MCDI_DEBUG
212 static void spm_mcdi_dump_regs(void)
213 {
214 /* SPM register */
215 clc_notice("POWER_ON_VAL0 0x%x = 0x%x\n", SPM_POWER_ON_VAL0 , spm_read(SPM_POWER_ON_VAL0));
216 clc_notice("POWER_ON_VAL1 0x%x = 0x%x\n", SPM_POWER_ON_VAL1 , spm_read(SPM_POWER_ON_VAL1));
217 clc_notice("PCM_PWR_IO_EN 0x%x = 0x%x\n", SPM_PCM_PWR_IO_EN , spm_read(SPM_PCM_PWR_IO_EN));
218 clc_notice("CLK_CON 0x%x = 0x%x\n", SPM_CLK_CON , spm_read(SPM_CLK_CON));
219 clc_notice("AP_DVFS_CON 0x%x = 0x%x\n", SPM_AP_DVFS_CON_SET , spm_read(SPM_AP_DVFS_CON_SET));
220 clc_notice("PWR_STATUS 0x%x = 0x%x\n", SPM_PWR_STATUS , spm_read(SPM_PWR_STATUS));
221 clc_notice("PWR_STATUS_S 0x%x = 0x%x\n", SPM_PWR_STATUS_S , spm_read(SPM_PWR_STATUS_S));
222 clc_notice("SLEEP_TIMER_STA 0x%x = 0x%x\n", SPM_SLEEP_TIMER_STA , spm_read(SPM_SLEEP_TIMER_STA));
223 clc_notice("WAKE_EVENT_MASK 0x%x = 0x%x\n", SPM_SLEEP_WAKEUP_EVENT_MASK, spm_read(SPM_SLEEP_WAKEUP_EVENT_MASK));
224 clc_notice("SPM_SLEEP_CPU_WAKEUP_EVENT 0x%x = 0x%x\n", SPM_SLEEP_CPU_WAKEUP_EVENT, spm_read(SPM_SLEEP_CPU_WAKEUP_EVENT));
225 clc_notice("SPM_PCM_RESERVE 0x%x = 0x%x\n", SPM_PCM_RESERVE , spm_read(SPM_PCM_RESERVE));
226 clc_notice("SPM_AP_STANBY_CON 0x%x = 0x%x\n", SPM_AP_STANBY_CON , spm_read(SPM_AP_STANBY_CON));
227 clc_notice("SPM_PCM_TIMER_OUT 0x%x = 0x%x\n", SPM_PCM_TIMER_OUT , spm_read(SPM_PCM_TIMER_OUT));
228 clc_notice("SPM_PCM_CON1 0x%x = 0x%x\n", SPM_PCM_CON1 , spm_read(SPM_PCM_CON1));
229
230
231 // PCM register
232 clc_notice("PCM_REG0_DATA 0x%x = 0x%x\n", SPM_PCM_REG0_DATA , spm_read(SPM_PCM_REG0_DATA));
233 // clc_notice("PCM_REG1_DATA 0x%x = 0x%x\n", SPM_PCM_REG1_DATA , spm_read(SPM_PCM_REG1_DATA));
234 // clc_notice("PCM_REG2_DATA 0x%x = 0x%x\n", SPM_PCM_REG2_DATA , spm_read(SPM_PCM_REG2_DATA));
235 // clc_notice("PCM_REG3_DATA 0x%x = 0x%x\n", SPM_PCM_REG3_DATA , spm_read(SPM_PCM_REG3_DATA));
236 // clc_notice("PCM_REG4_DATA 0x%x = 0x%x\n", SPM_PCM_REG4_DATA , spm_read(SPM_PCM_REG4_DATA));
237 // clc_notice("PCM_REG5_DATA 0x%x = 0x%x\n", SPM_PCM_REG5_DATA , spm_read(SPM_PCM_REG5_DATA));
238 // clc_notice("PCM_REG6_DATA 0x%x = 0x%x\n", SPM_PCM_REG6_DATA , spm_read(SPM_PCM_REG6_DATA));
239 clc_notice("PCM_REG7_DATA 0x%x = 0x%x\n", SPM_PCM_REG7_DATA , spm_read(SPM_PCM_REG7_DATA));
240 // clc_notice("PCM_REG8_DATA 0x%x = 0x%x\n", SPM_PCM_REG8_DATA , spm_read(SPM_PCM_REG8_DATA));
241 clc_notice("PCM_REG9_DATA 0x%x = 0x%x\n", SPM_PCM_REG9_DATA , spm_read(SPM_PCM_REG9_DATA));
242 // clc_notice("PCM_REG10_DATA 0x%x = 0x%x\n", SPM_PCM_REG10_DATA , spm_read(SPM_PCM_REG10_DATA));
243 clc_notice("PCM_REG11_DATA 0x%x = 0x%x\n", SPM_PCM_REG11_DATA , spm_read(SPM_PCM_REG11_DATA));
244 clc_notice("PCM_REG12_DATA 0x%x = 0x%x\n", SPM_PCM_REG12_DATA , spm_read(SPM_PCM_REG12_DATA));
245 clc_notice("PCM_REG13_DATA 0x%x = 0x%x\n", SPM_PCM_REG13_DATA , spm_read(SPM_PCM_REG13_DATA));
246 // clc_notice("PCM_REG14_DATA 0x%x = 0x%x\n", SPM_PCM_REG14_DATA , spm_read(SPM_PCM_REG14_DATA));
247 clc_notice("PCM_REG15_DATA 0x%x = 0x%x\n", SPM_PCM_REG15_DATA , spm_read(SPM_PCM_REG15_DATA));
248
249 }
250 #endif
251
252
253 static void spm_direct_disable_sodi(void)
254 {
255 u32 clc_temp;
256
257 clc_temp = spm_read(SPM_CLK_CON);
258 clc_temp |= (0x1<<13);
259
260 spm_write(SPM_CLK_CON, clc_temp);
261 }
262
263
264 static void spm_direct_enable_sodi(void)
265 {
266 u32 clc_temp;
267
268 clc_temp = spm_read(SPM_CLK_CON);
269 clc_temp &= 0xffffdfff; // ~(0x1<<13);
270
271 spm_write(SPM_CLK_CON, clc_temp);
272 }
273
274
275 static void spm_reset_and_init_pcm(void)
276 {
277 u32 con1;
278
279 /* reset PCM */
280 spm_write(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET);
281 spm_write(SPM_PCM_CON0, CON0_CFG_KEY);
282
283 /* init PCM_CON0 (disable event vector) */
284 spm_write(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS);
285
286 /* init PCM_CON1 (disable PCM timer but keep PCM WDT setting) */
287 con1 = spm_read(SPM_PCM_CON1) & (CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN);
288 spm_write(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_SPM_SRAM_ISO_B |
289 CON1_SPM_SRAM_SLP_B | CON1_IM_NONRP_EN | CON1_MIF_APBEN);
290 }
291
292
293 static void spm_kick_im_to_fetch(const pcm_desc_t *pcmdesc)
294 {
295 u32 ptr, len, con0;
296
297 /* tell IM where is PCM code (use slave mode if code existed) */
298 ptr = spm_get_base_phys(pcmdesc->base);
299 len = pcmdesc->size - 1;
300 if (spm_read(SPM_PCM_IM_PTR) != ptr || spm_read(SPM_PCM_IM_LEN) != len) {
301 spm_write(SPM_PCM_IM_PTR, ptr);
302 spm_write(SPM_PCM_IM_LEN, len);
303 } else {
304 spm_write(SPM_PCM_CON1, spm_read(SPM_PCM_CON1) | CON1_CFG_KEY | CON1_IM_SLAVE);
305 }
306
307 /* kick IM to fetch (only toggle IM_KICK) */
308 con0 = spm_read(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
309 spm_write(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_IM_KICK);
310 spm_write(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
311 }
312
313
314 static void spm_init_pcm_register(void)
315 {
316 /* init r0 with POWER_ON_VAL0 */
317 spm_write(SPM_PCM_REG_DATA_INI, spm_read(SPM_POWER_ON_VAL0));
318 spm_write(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R0);
319 spm_write(SPM_PCM_PWR_IO_EN, 0);
320
321
322 /* init r7 with POWER_ON_VAL1 */
323 spm_write(SPM_PCM_REG_DATA_INI, spm_read(SPM_POWER_ON_VAL1));
324 spm_write(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R7);
325 spm_write(SPM_PCM_PWR_IO_EN, 0);
326
327 /* clear REG_DATA_INI for PCM after init rX */
328 spm_write(SPM_PCM_REG_DATA_INI, 0);
329 }
330
331
332 static void spm_init_event_vector(const pcm_desc_t *pcmdesc)
333 {
334 /* init event vector register */
335 spm_write(SPM_PCM_EVENT_VECTOR0, pcmdesc->vec0);
336 spm_write(SPM_PCM_EVENT_VECTOR1, pcmdesc->vec1);
337 #if 0
338 spm_write(SPM_PCM_EVENT_VECTOR2, pcmdesc->vec2);
339 spm_write(SPM_PCM_EVENT_VECTOR3, pcmdesc->vec3);
340 spm_write(SPM_PCM_EVENT_VECTOR4, pcmdesc->vec4);
341 spm_write(SPM_PCM_EVENT_VECTOR5, pcmdesc->vec5);
342 spm_write(SPM_PCM_EVENT_VECTOR6, pcmdesc->vec6);
343 spm_write(SPM_PCM_EVENT_VECTOR7, pcmdesc->vec7);
344 #endif
345 /* event vector will be enabled by PCM itself */
346 }
347
348
349 static void spm_set_ap_standbywfi(bool IsMcdi)
350 {
351
352 spm_write(SPM_AP_STANBY_CON, (1 << 19) | /* unmask MD*/
353 (1 << 20) | /* unmask CONN */
354 (1 << 16) | /* unmask DISP */
355 (0 << 17) | /* mask MFG */
356 (0 << 6) | /* check SCU idle */
357 (0 << 5) | /* check L2C idle */
358 (1U << 4)); /* Reduce AND */
359 if (IsMcdi == TRUE)
360 {
361 spm_write(SPM_CORE0_WFI_SEL, 0x1);
362 spm_write(SPM_CORE1_WFI_SEL, 0x1);
363 spm_write(SPM_CORE2_WFI_SEL, 0x1);
364 spm_write(SPM_CORE3_WFI_SEL, 0x1);
365 }
366 else
367 {
368 #if 0
369 spm_write(SPM_CORE0_WFI_SEL, 0x0);
370 //spm_write(SPM_CORE1_WFI_SEL, 0x0);
371 //spm_write(SPM_CORE2_WFI_SEL, 0x0);
372 //spm_write(SPM_CORE3_WFI_SEL, 0x0);
373 #endif
374 }
375
376 }
377
378
379 /*
380 * timer_val: PCM timer value (0 = disable)
381 * wake_src : WAKE_SRC_XXX
382 */
383 static void spm_set_wakeup_event(u32 wake_src)
384 {
385 u32 isr;
386
387 /* unmask wakeup source */
388 #if SPM_MCDI_BYPASS_SYSPWREQ
389 wake_src &= ~WAKE_SRC_SYSPWREQ; /* make 26M off when attach ICE */
390 #endif
391 spm_write(SPM_SLEEP_WAKEUP_EVENT_MASK, ~wake_src);
392
393 /* unmask SPM ISR (keep TWAM setting) */
394 isr = spm_read(SPM_SLEEP_ISR_MASK) & ISR_TWAM;
395 spm_write(SPM_SLEEP_ISR_MASK, isr | ISRM_PCM_IRQ_AUX);
396
397
398 //mask CPU IRQ
399 spm_write(SPM_SLEEP_CPU_IRQ_MASK,0xf);
400 }
401
402
403 static void spm_kick_pcm_to_run(bool cpu_pdn, bool infra_pdn)
404 {
405 u32 clk, con0;
406
407 /*enable SODI*/
408 //spm_direct_enable_sodi();
409
410 /* keep CPU or INFRA/DDRPHY power if needed and lock INFRA DCM */
411 clk = spm_read(SPM_CLK_CON) & ~(CC_DISABLE_DORM_PWR | CC_DISABLE_INFRA_PWR);
412 if (!cpu_pdn)
413 clk |= CC_DISABLE_DORM_PWR;
414 if (!infra_pdn)
415 clk |= CC_DISABLE_INFRA_PWR;
416 spm_write(SPM_CLK_CON, clk | CC_LOCK_INFRA_DCM);
417
418 /* init pause request mask for PCM */
419 spm_write(SPM_PCM_MAS_PAUSE_MASK, 0xffffffff);
420
421 /* enable r0 and r7 to control power */
422 spm_write(SPM_PCM_PWR_IO_EN, PCM_PWRIO_EN_R0 | PCM_PWRIO_EN_R7);
423
424 /* SRCLKENA: r7 (PWR_IO_EN[7]=1) */
425 spm_write(SPM_CLK_CON, spm_read(SPM_CLK_CON) | CC_SRCLKENA_MASK);
426
427 /* kick PCM to run (only toggle PCM_KICK) */
428 con0 = spm_read(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
429 spm_write(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_PCM_KICK);
430 spm_write(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
431 }
432
433
434 static void spm_trigger_wfi_for_mcdi(bool cpu_pdn)
435 {
436 if (cpu_pdn) {
437 if (!cpu_power_down(DORMANT_MODE)) {
438 switch_to_amp();
439 mcdi_wfi_with_sync();
440 }
441 switch_to_smp();
442 cpu_check_dormant_abort();
443 } else {
444 mcdi_wfi_with_sync();
445 }
446 }
447
448
449 static void spm_get_wakeup_status(wake_status_t *wakesta)
450 {
451 /* get PC value if PCM assert (pause abort) */
452 wakesta->debug_reg = spm_read(SPM_PCM_REG_DATA_INI);
453
454 /* get wakeup event */
455 wakesta->r12 = spm_read(SPM_PCM_REG9_DATA); /* r9 = r12 for pcm_normal */
456 wakesta->raw_sta = spm_read(SPM_SLEEP_ISR_RAW_STA);
457 wakesta->cpu_wake = spm_read(SPM_SLEEP_CPU_WAKEUP_EVENT);
458
459 /* get sleep time */
460 wakesta->timer_out = spm_read(SPM_PCM_TIMER_OUT);
461
462 /* get special pattern (0xf0000 or 0x10000) if sleep abort */
463 wakesta->event_reg = spm_read(SPM_PCM_EVENT_REG_STA);
464
465 /* get ISR status */
466 wakesta->isr = spm_read(SPM_SLEEP_ISR_STATUS);
467
468 /* get MD/CONN and co-clock status */
469 wakesta->r13 = spm_read(SPM_PCM_REG13_DATA);
470 }
471
472
473 static void spm_clean_after_wakeup(void)
474 {
475 /* PCM has cleared uart_clk_off_req and now clear it in POWER_ON_VAL1 */
476 spm_write(SPM_POWER_ON_VAL1, spm_read(SPM_POWER_ON_VAL1) & ~R7_UART_CLK_OFF_REQ);
477
478 /* SRCLKENA: POWER_ON_VAL1|r7 (PWR_IO_EN[7]=1) */
479 spm_write(SPM_CLK_CON, spm_read(SPM_CLK_CON) & ~CC_SRCLKENA_MASK);
480
481 /* re-enable POWER_ON_VAL0/1 to control power */
482 spm_write(SPM_PCM_PWR_IO_EN, 0);
483
484 /* unlock INFRA DCM */
485 spm_write(SPM_CLK_CON, spm_read(SPM_CLK_CON) & ~CC_LOCK_INFRA_DCM);
486
487 /* clean CPU wakeup event (pause abort) */
488 spm_write(SPM_SLEEP_CPU_WAKEUP_EVENT, 0);
489
490 /* clean wakeup event raw status (except THERM) */
491 spm_write(SPM_SLEEP_WAKEUP_EVENT_MASK, ~WAKE_SRC_THERM);
492
493 /* clean ISR status (except TWAM) */
494 spm_write(SPM_SLEEP_ISR_MASK, spm_read(SPM_SLEEP_ISR_MASK) | ISRM_ALL_EXC_TWAM);
495 spm_write(SPM_SLEEP_ISR_STATUS, ISRC_ALL_EXC_TWAM);
496 spm_write(SPM_PCM_SW_INT_CLEAR, PCM_SW_INT0);
497 }
498
499
500 static wake_reason_t spm_output_wake_reason(const wake_status_t *wakesta)
501 {
502 if (wakesta->debug_reg != 0) {
503 spm_error2("PCM ASSERT AND PC = %u (0x%x)(0x%x)\n",
504 wakesta->debug_reg, wakesta->r13, wakesta->event_reg);
505 return WR_PCM_ASSERT;
506 }
507
508 return WR_WAKE_SRC;
509 }
510
511
512 void spm_go_to_sodi(bool cpu_pdn)
513 {
514 wake_status_t wakesta;
515 unsigned long flags;
516 struct mtk_irq_mask mask;
517 wake_reason_t wr = WR_NONE;
518 const pcm_desc_t *pcmdesc = &pcm_sodidle;
519
520 spin_lock_irqsave(&spm_lock, flags);
521
522 gSPM_SODI_EN =1;
523
524 mt_irq_mask_all(&mask);
525 mt_irq_unmask_for_sleep(MT_SPM_IRQ_ID);
526
527 mt_cirq_clone_gic();
528 mt_cirq_enable();
529
530 spm_reset_and_init_pcm();
531
532 spm_kick_im_to_fetch(pcmdesc);
533
534 spm_init_pcm_register();
535
536 spm_init_event_vector(pcmdesc);
537
538 spm_set_ap_standbywfi(FALSE);
539
540 spm_set_wakeup_event(WAKE_SRC_FOR_SODI);
541
542 spm_kick_pcm_to_run(cpu_pdn, false); /* keep INFRA/DDRPHY power */
543
544 #if SPM_MCDI_DEBUG
545 //clc_notice("============SODI Before============\n");
546 //spm_mcdi_dump_regs(); //dump debug info
547 #endif
548
549 mcidle_before_wfi(0);
550
551 spm_trigger_wfi_for_mcdi(cpu_pdn);
552
553 mcidle_after_wfi(0);
554
555 #if SPM_MCDI_DEBUG
556 //clc_notice("============SODI After=============\n");
557 spm_mcdi_dump_regs();//dump debug info
558 #endif
559 spm_get_wakeup_status(&wakesta);
560
561 spm_clean_after_wakeup();
562
563 wr = spm_output_wake_reason(&wakesta);
564
565 mt_cirq_flush();
566 mt_cirq_disable();
567 mt_irq_mask_restore(&mask);
568
569 gSPM_SODI_EN =0;
570
571 spin_unlock_irqrestore(&spm_lock, flags);
572
573 //return wr;
574 }
575
576 void spm_sodi_lcm_video_mode(bool IsLcmVideoMode)
577 {
578 gSpm_IsLcmVideoMode = IsLcmVideoMode;
579
580 #if SPM_SODI_DEBUG
581 printk("spm_sodi_lcm_video_mode() : gSpm_IsLcmVideoMode = %x\n", gSpm_IsLcmVideoMode);
582 #endif
583
584 }
585
586 void spm_disable_sodi(void)
587 {
588 //spin_lock(&spm_sodi_lock);
589
590 gSpm_Sodi_Disable_Counter++;
591
592 #if SPM_SODI_DEBUG
593 printk("spm_disable_sodi() : spm_sodi_disable_counter = 0x%x\n", gSpm_Sodi_Disable_Counter);
594 #endif
595
596 if(gSpm_Sodi_Disable_Counter > 0)
597 {
598 spm_direct_disable_sodi();
599 }
600
601 //spin_unlock(&spm_sodi_lock);
602 }
603
604 void spm_enable_sodi(void)
605 {
606 //spin_lock(&spm_sodi_lock);
607
608 gSpm_Sodi_Disable_Counter--;
609
610 #if SPM_SODI_DEBUG
611 printk("spm_enable_sodi() : spm_sodi_disable_counter = 0x%x\n", gSpm_Sodi_Disable_Counter);
612 #endif
613
614 if(gSpm_Sodi_Disable_Counter <= 0)
615 {
616 spm_direct_enable_sodi();
617 }
618
619 //spin_unlock(&spm_sodi_lock);
620 }
621 #endif //SPM_SODI_ENABLED
622
623
624 MODULE_DESCRIPTION("MT6582 SPM-Idle Driver v1.2");