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>
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>
22 #include <asm/hardware/gic.h>
24 //#include <mach/wd_api.h>
26 #ifdef SPM_SODI_ENABLED
28 #define SPM_MCDI_DEBUG 0
29 #define SPM_MCDI_BYPASS_SYSPWREQ 1
32 //DEFINE_SPINLOCK(spm_sodi_lock);
34 s32 gSpm_Sodi_Disable_Counter
= 0;
35 bool gSpm_IsLcmVideoMode
= TRUE
;
36 u32 gSPM_SODI_EN
= 0; // flag for idle task
38 #define PCM_WDT_TIMEOUT (30 * 32768) /* 30s */
39 #define PCM_TIMER_MAX_FOR_WDT (0xffffffff - PCM_WDT_TIMEOUT)
42 #define mcdi_wfi_with_sync() \
46 __asm__ __volatile__("wfi" : : : "memory"); \
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 )
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 )
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)
66 // ==========================================
67 // PCM code for SODI (Screen On Deep Idle) pcm_sodi_v0.15_20130802_MT6582
70 // ==========================================
71 static u32 __pcm_sodidle
[] = {
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
151 #define MCDI_PCM_PC_0 0
152 #define MCDI_PCM_PC_1 15
154 static const pcm_desc_t pcm_sodidle
= {
155 .base
= __pcm_sodidle
,
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 */
162 #define spm_error2(fmt, args...) \
164 aee_sram_printk(fmt, ##args); \
165 spm_error(fmt, ##args); \
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 */
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);
198 extern void mcidle_before_wfi(int cpu
);
199 extern void mcidle_after_wfi(int cpu
);
201 void __attribute__((weak
)) mcidle_before_wfi(int cpu
)
205 void __attribute__((weak
)) mcidle_after_wfi(int cpu
)
209 extern spinlock_t spm_lock
;
212 static void spm_mcdi_dump_regs(void)
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
));
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
));
253 static void spm_direct_disable_sodi(void)
257 clc_temp
= spm_read(SPM_CLK_CON
);
258 clc_temp
|= (0x1<<13);
260 spm_write(SPM_CLK_CON
, clc_temp
);
264 static void spm_direct_enable_sodi(void)
268 clc_temp
= spm_read(SPM_CLK_CON
);
269 clc_temp
&= 0xffffdfff; // ~(0x1<<13);
271 spm_write(SPM_CLK_CON
, clc_temp
);
275 static void spm_reset_and_init_pcm(void)
280 spm_write(SPM_PCM_CON0
, CON0_CFG_KEY
| CON0_PCM_SW_RESET
);
281 spm_write(SPM_PCM_CON0
, CON0_CFG_KEY
);
283 /* init PCM_CON0 (disable event vector) */
284 spm_write(SPM_PCM_CON0
, CON0_CFG_KEY
| CON0_IM_SLEEP_DVS
);
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
);
293 static void spm_kick_im_to_fetch(const pcm_desc_t
*pcmdesc
)
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
);
304 spm_write(SPM_PCM_CON1
, spm_read(SPM_PCM_CON1
) | CON1_CFG_KEY
| CON1_IM_SLAVE
);
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
);
314 static void spm_init_pcm_register(void)
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);
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);
327 /* clear REG_DATA_INI for PCM after init rX */
328 spm_write(SPM_PCM_REG_DATA_INI
, 0);
332 static void spm_init_event_vector(const pcm_desc_t
*pcmdesc
)
334 /* init event vector register */
335 spm_write(SPM_PCM_EVENT_VECTOR0
, pcmdesc
->vec0
);
336 spm_write(SPM_PCM_EVENT_VECTOR1
, pcmdesc
->vec1
);
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
);
345 /* event vector will be enabled by PCM itself */
349 static void spm_set_ap_standbywfi(bool IsMcdi
)
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 */
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);
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);
380 * timer_val: PCM timer value (0 = disable)
381 * wake_src : WAKE_SRC_XXX
383 static void spm_set_wakeup_event(u32 wake_src
)
387 /* unmask wakeup source */
388 #if SPM_MCDI_BYPASS_SYSPWREQ
389 wake_src
&= ~WAKE_SRC_SYSPWREQ
; /* make 26M off when attach ICE */
391 spm_write(SPM_SLEEP_WAKEUP_EVENT_MASK
, ~wake_src
);
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
);
399 spm_write(SPM_SLEEP_CPU_IRQ_MASK
,0xf);
403 static void spm_kick_pcm_to_run(bool cpu_pdn
, bool infra_pdn
)
408 //spm_direct_enable_sodi();
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
);
413 clk
|= CC_DISABLE_DORM_PWR
;
415 clk
|= CC_DISABLE_INFRA_PWR
;
416 spm_write(SPM_CLK_CON
, clk
| CC_LOCK_INFRA_DCM
);
418 /* init pause request mask for PCM */
419 spm_write(SPM_PCM_MAS_PAUSE_MASK
, 0xffffffff);
421 /* enable r0 and r7 to control power */
422 spm_write(SPM_PCM_PWR_IO_EN
, PCM_PWRIO_EN_R0
| PCM_PWRIO_EN_R7
);
424 /* SRCLKENA: r7 (PWR_IO_EN[7]=1) */
425 spm_write(SPM_CLK_CON
, spm_read(SPM_CLK_CON
) | CC_SRCLKENA_MASK
);
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
);
434 static void spm_trigger_wfi_for_mcdi(bool cpu_pdn
)
437 if (!cpu_power_down(DORMANT_MODE
)) {
439 mcdi_wfi_with_sync();
442 cpu_check_dormant_abort();
444 mcdi_wfi_with_sync();
449 static void spm_get_wakeup_status(wake_status_t
*wakesta
)
451 /* get PC value if PCM assert (pause abort) */
452 wakesta
->debug_reg
= spm_read(SPM_PCM_REG_DATA_INI
);
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
);
460 wakesta
->timer_out
= spm_read(SPM_PCM_TIMER_OUT
);
462 /* get special pattern (0xf0000 or 0x10000) if sleep abort */
463 wakesta
->event_reg
= spm_read(SPM_PCM_EVENT_REG_STA
);
466 wakesta
->isr
= spm_read(SPM_SLEEP_ISR_STATUS
);
468 /* get MD/CONN and co-clock status */
469 wakesta
->r13
= spm_read(SPM_PCM_REG13_DATA
);
473 static void spm_clean_after_wakeup(void)
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
);
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
);
481 /* re-enable POWER_ON_VAL0/1 to control power */
482 spm_write(SPM_PCM_PWR_IO_EN
, 0);
484 /* unlock INFRA DCM */
485 spm_write(SPM_CLK_CON
, spm_read(SPM_CLK_CON
) & ~CC_LOCK_INFRA_DCM
);
487 /* clean CPU wakeup event (pause abort) */
488 spm_write(SPM_SLEEP_CPU_WAKEUP_EVENT
, 0);
490 /* clean wakeup event raw status (except THERM) */
491 spm_write(SPM_SLEEP_WAKEUP_EVENT_MASK
, ~WAKE_SRC_THERM
);
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
);
500 static wake_reason_t
spm_output_wake_reason(const wake_status_t
*wakesta
)
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
;
512 void spm_go_to_sodi(bool cpu_pdn
)
514 wake_status_t wakesta
;
516 struct mtk_irq_mask mask
;
517 wake_reason_t wr
= WR_NONE
;
518 const pcm_desc_t
*pcmdesc
= &pcm_sodidle
;
520 spin_lock_irqsave(&spm_lock
, flags
);
524 mt_irq_mask_all(&mask
);
525 mt_irq_unmask_for_sleep(MT_SPM_IRQ_ID
);
530 spm_reset_and_init_pcm();
532 spm_kick_im_to_fetch(pcmdesc
);
534 spm_init_pcm_register();
536 spm_init_event_vector(pcmdesc
);
538 spm_set_ap_standbywfi(FALSE
);
540 spm_set_wakeup_event(WAKE_SRC_FOR_SODI
);
542 spm_kick_pcm_to_run(cpu_pdn
, false); /* keep INFRA/DDRPHY power */
545 //clc_notice("============SODI Before============\n");
546 //spm_mcdi_dump_regs(); //dump debug info
549 mcidle_before_wfi(0);
551 spm_trigger_wfi_for_mcdi(cpu_pdn
);
556 //clc_notice("============SODI After=============\n");
557 spm_mcdi_dump_regs();//dump debug info
559 spm_get_wakeup_status(&wakesta
);
561 spm_clean_after_wakeup();
563 wr
= spm_output_wake_reason(&wakesta
);
567 mt_irq_mask_restore(&mask
);
571 spin_unlock_irqrestore(&spm_lock
, flags
);
576 void spm_sodi_lcm_video_mode(bool IsLcmVideoMode
)
578 gSpm_IsLcmVideoMode
= IsLcmVideoMode
;
581 printk("spm_sodi_lcm_video_mode() : gSpm_IsLcmVideoMode = %x\n", gSpm_IsLcmVideoMode
);
586 void spm_disable_sodi(void)
588 //spin_lock(&spm_sodi_lock);
590 gSpm_Sodi_Disable_Counter
++;
593 printk("spm_disable_sodi() : spm_sodi_disable_counter = 0x%x\n", gSpm_Sodi_Disable_Counter
);
596 if(gSpm_Sodi_Disable_Counter
> 0)
598 spm_direct_disable_sodi();
601 //spin_unlock(&spm_sodi_lock);
604 void spm_enable_sodi(void)
606 //spin_lock(&spm_sodi_lock);
608 gSpm_Sodi_Disable_Counter
--;
611 printk("spm_enable_sodi() : spm_sodi_disable_counter = 0x%x\n", gSpm_Sodi_Disable_Counter
);
614 if(gSpm_Sodi_Disable_Counter
<= 0)
616 spm_direct_enable_sodi();
619 //spin_unlock(&spm_sodi_lock);
621 #endif //SPM_SODI_ENABLED
624 MODULE_DESCRIPTION("MT6582 SPM-Idle Driver v1.2");