mt_spm_sodi3p0.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/spinlock.h>
  5. #include <linux/delay.h>
  6. #include <linux/slab.h>
  7. #include <mach/irqs.h>
  8. #include <mach/mt_gpt.h>
  9. #ifdef CONFIG_MTK_WD_KICKER
  10. #include <mach/wd_api.h>
  11. #endif
  12. #include <mt-plat/mt_boot.h>
  13. #if defined(CONFIG_MTK_SYS_CIRQ)
  14. #include <mt-plat/mt_cirq.h>
  15. #endif
  16. #include <mt-plat/upmu_common.h>
  17. #include <mt-plat/mt_io.h>
  18. #include <mt_spm_sodi3.h>
  19. /**************************************
  20. * only for internal debug
  21. **************************************/
  22. #define SODI3_TAG "[SODI3] "
  23. #define sodi3_err(fmt, args...) pr_err(SODI3_TAG fmt, ##args)
  24. #define sodi3_warn(fmt, args...) pr_warn(SODI3_TAG fmt, ##args)
  25. #define sodi3_debug(fmt, args...) pr_debug(SODI3_TAG fmt, ##args)
  26. #define SPM_BYPASS_SYSPWREQ 0
  27. #define LOG_BUF_SIZE (256)
  28. #define SODI3_LOGOUT_TIMEOUT_CRITERIA (20)
  29. #define SODI3_LOGOUT_INTERVAL_CRITERIA (5000U) /* unit:ms */
  30. static struct pwr_ctrl sodi3_ctrl = {
  31. .wake_src = WAKE_SRC_FOR_SODI3,
  32. .wake_src_md32 = WAKE_SRC_FOR_MD32,
  33. .r0_ctrl_en = 1,
  34. .r7_ctrl_en = 1,
  35. .infra_dcm_lock = 1, /* set to be 1 if SODI 3.0 */
  36. .wfi_op = WFI_OP_AND,
  37. /* SPM_AP_STANDBY_CON */
  38. .mp0top_idle_mask = 0,
  39. .mp1top_idle_mask = 0,
  40. .mcusys_idle_mask = 0,
  41. .md_ddr_dbc_en = 0,
  42. .md1_req_mask_b = 1,
  43. .md2_req_mask_b = 0, /* bit 20 */
  44. #if defined(CONFIG_ARCH_MT6755)
  45. .scp_req_mask_b = 0, /* bit 21 */
  46. #elif defined(CONFIG_ARCH_MT6797)
  47. .scp_req_mask_b = 1, /* bit 21 */
  48. #endif
  49. .lte_mask_b = 0,
  50. .md_apsrc1_sel = 0, /* bit 24, set to be 1 for SODI CG mode */
  51. .md_apsrc0_sel = 0, /* bit 25, set to be 1 for SODI CG mode */
  52. .conn_mask_b = 1,
  53. .conn_apsrc_sel = 0, /* bit 27, set to be 1 for SODI CG mode */
  54. /* SPM_SRC_REQ */
  55. .spm_apsrc_req = 0,
  56. .spm_f26m_req = 0,
  57. .spm_lte_req = 0,
  58. .spm_infra_req = 0,
  59. .spm_vrf18_req = 0,
  60. .spm_dvfs_req = 0,
  61. .spm_dvfs_force_down = 0,
  62. .spm_ddren_req = 0,
  63. .cpu_md_dvfs_sop_force_on = 0,
  64. /* SPM_SRC_MASK */
  65. .ccif0_to_md_mask_b = 1,
  66. .ccif0_to_ap_mask_b = 1,
  67. .ccif1_to_md_mask_b = 1,
  68. .ccif1_to_ap_mask_b = 1,
  69. .ccifmd_md1_event_mask_b = 1,
  70. .ccifmd_md2_event_mask_b = 1,
  71. .vsync_mask_b = 0, /* 5-bit */
  72. .md_srcclkena_0_infra_mask_b = 0, /* bit 12 */
  73. .md_srcclkena_1_infra_mask_b = 0, /* bit 13 */
  74. .conn_srcclkena_infra_mask_b = 0, /* bit 14 */
  75. .md32_srcclkena_infra_mask_b = 0, /* bit 15 */
  76. .srcclkeni_infra_mask_b = 0, /* bit 16 */
  77. .md_apsrcreq_0_infra_mask_b = 1,
  78. .md_apsrcreq_1_infra_mask_b = 0,
  79. .conn_apsrcreq_infra_mask_b = 1,
  80. #if defined(CONFIG_ARCH_MT6755)
  81. .md32_apsrcreq_infra_mask_b = 0,
  82. #elif defined(CONFIG_ARCH_MT6797)
  83. .md32_apsrcreq_infra_mask_b = 1,
  84. #endif
  85. .md_ddr_en_0_mask_b = 1,
  86. .md_ddr_en_1_mask_b = 0, /* bit 22 */
  87. .md_vrf18_req_0_mask_b = 1,
  88. .md_vrf18_req_1_mask_b = 0, /* bit 24 */
  89. .emi_bw_dvfs_req_mask = 1,
  90. .md_srcclkena_0_dvfs_req_mask_b = 0,
  91. .md_srcclkena_1_dvfs_req_mask_b = 0,
  92. .conn_srcclkena_dvfs_req_mask_b = 0,
  93. /* SPM_SRC2_MASK */
  94. .dvfs_halt_mask_b = 0x1f, /* 5-bit */
  95. .vdec_req_mask_b = 0, /* bit 6 */
  96. .gce_req_mask_b = 1, /* bit 7, set to be 1 for SODI */
  97. .cpu_md_dvfs_erq_merge_mask_b = 0,
  98. .md1_ddr_en_dvfs_halt_mask_b = 0,
  99. .md2_ddr_en_dvfs_halt_mask_b = 0,
  100. .vsync_dvfs_halt_mask_b = 0, /* 5-bit, bit 11 ~ 15 */
  101. .conn_ddr_en_mask_b = 1,
  102. .disp_req_mask_b = 1, /* bit 17, set to be 1 for SODI */
  103. .disp1_req_mask_b = 1, /* bit 18, set to be 1 for SODI */
  104. #if defined(CONFIG_ARCH_MT6755)
  105. .mfg_req_mask_b = 0, /* bit 19 */
  106. #elif defined(CONFIG_ARCH_MT6797)
  107. .mfg_req_mask_b = 1, /* bit 19, set to be 1 for SODI */
  108. #endif
  109. .c2k_ps_rccif_wake_mask_b = 1,
  110. .c2k_l1_rccif_wake_mask_b = 1,
  111. .ps_c2k_rccif_wake_mask_b = 1,
  112. .l1_c2k_rccif_wake_mask_b = 1,
  113. .sdio_on_dvfs_req_mask_b = 0,
  114. .emi_boost_dvfs_req_mask_b = 0,
  115. .cpu_md_emi_dvfs_req_prot_dis = 0,
  116. #if defined(CONFIG_ARCH_MT6797)
  117. .disp_od_req_mask_b = 1, /* bit 27, set to be 1 for SODI */
  118. #endif
  119. /* SPM_CLK_CON */
  120. .srclkenai_mask = 1,
  121. .mp1_cpu0_wfi_en = 1,
  122. .mp1_cpu1_wfi_en = 1,
  123. .mp1_cpu2_wfi_en = 1,
  124. .mp1_cpu3_wfi_en = 1,
  125. .mp0_cpu0_wfi_en = 1,
  126. .mp0_cpu1_wfi_en = 1,
  127. .mp0_cpu2_wfi_en = 1,
  128. .mp0_cpu3_wfi_en = 1,
  129. #if SPM_BYPASS_SYSPWREQ
  130. .syspwreq_mask = 1,
  131. #endif
  132. };
  133. struct spm_lp_scen __spm_sodi3 = {
  134. .pwrctrl = &sodi3_ctrl,
  135. };
  136. static bool gSpm_sodi3_en;
  137. static unsigned long int sodi3_logout_prev_time;
  138. static int pre_emi_refresh_cnt;
  139. static int memPllCG_prev_status = 1; /* 1:CG, 0:pwrdn */
  140. static unsigned int logout_sodi3_cnt;
  141. static unsigned int logout_selfrefresh_cnt;
  142. static void spm_sodi3_pre_process(void)
  143. {
  144. #if defined(CONFIG_ARCH_MT6755)
  145. u32 val;
  146. #endif
  147. __spm_pmic_pg_force_on();
  148. spm_disable_mmu_smi_async();
  149. spm_pmic_power_mode(PMIC_PWR_SODI3, 0, 0);
  150. spm_bypass_boost_gpio_set();
  151. #if defined(CONFIG_ARCH_MT6755)
  152. pmic_read_interface_nolock(MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_ADDR,
  153. &val,
  154. MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_MASK,
  155. MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_SHIFT);
  156. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE, IDX_DI_VSRAM_NORMAL, val);
  157. pmic_read_interface_nolock(MT6351_TOP_CON, &val, 0x037F, 0);
  158. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE,
  159. IDX_DI_SRCCLKEN_IN2_NORMAL,
  160. val | (1 << MT6351_PMIC_RG_SRCLKEN_IN2_EN_SHIFT));
  161. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE,
  162. IDX_DI_SRCCLKEN_IN2_SLEEP,
  163. val & ~(1 << MT6351_PMIC_RG_SRCLKEN_IN2_EN_SHIFT));
  164. #endif
  165. /* set PMIC WRAP table for deepidle power control */
  166. mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_DEEPIDLE);
  167. /* Do more low power setting when MD1/C2K/CONN off */
  168. if (is_md_c2k_conn_power_off())
  169. __spm_bsi_top_init_setting();
  170. }
  171. static void spm_sodi3_post_process(void)
  172. {
  173. /* set PMIC WRAP table for normal power control */
  174. mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_NORMAL);
  175. spm_enable_mmu_smi_async();
  176. __spm_pmic_pg_force_off();
  177. }
  178. static wake_reason_t
  179. spm_sodi3_output_log(struct wake_status *wakesta, struct pcm_desc *pcmdesc, int vcore_status, u32 sodi3_flags)
  180. {
  181. wake_reason_t wr = WR_NONE;
  182. unsigned long int sodi3_logout_curr_time = 0;
  183. int need_log_out = 0;
  184. if (sodi3_flags&SODI_FLAG_NO_LOG) {
  185. if (wakesta->assert_pc != 0) {
  186. sodi3_err("PCM ASSERT AT %u (%s), r13 = 0x%x, debug_flag = 0x%x\n",
  187. wakesta->assert_pc, pcmdesc->version, wakesta->r13, wakesta->debug_flag);
  188. wr = WR_PCM_ASSERT;
  189. }
  190. } else if (!(sodi3_flags&SODI_FLAG_REDUCE_LOG) || (sodi3_flags & SODI_FLAG_RESIDENCY)) {
  191. sodi3_warn("vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  192. vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  193. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  194. wr = __spm_output_wake_reason(wakesta, pcmdesc, false);
  195. } else {
  196. sodi3_logout_curr_time = spm_get_current_time_ms();
  197. if (wakesta->assert_pc != 0) {
  198. need_log_out = 1;
  199. } else if ((wakesta->r12 & (0x1 << 4)) == 0) {
  200. /* not wakeup by GPT */
  201. need_log_out = 1;
  202. } else if (wakesta->timer_out <= SODI3_LOGOUT_TIMEOUT_CRITERIA) {
  203. need_log_out = 1;
  204. } else if ((spm_read(SPM_PASR_DPD_0) == 0 && pre_emi_refresh_cnt > 0) ||
  205. (spm_read(SPM_PASR_DPD_0) > 0 && pre_emi_refresh_cnt == 0)) {
  206. need_log_out = 1;
  207. } else if ((sodi3_logout_curr_time - sodi3_logout_prev_time) > SODI3_LOGOUT_INTERVAL_CRITERIA) {
  208. /* previous logout time > SODI3_LOGOUT_INTERVAL_CRITERIA */
  209. need_log_out = 1;
  210. } else {
  211. /* check CG/pwrdn status is changed */
  212. int mem_status = 0;
  213. /* check mempll CG/pwrdn status change */
  214. if (((spm_read(SPM_SW_FLAG) & SPM_FLAG_SODI_CG_MODE) != 0) ||
  215. ((spm_read(DUMMY1_PWR_CON) & DUMMY1_PWR_ISO_LSB) != 0))
  216. mem_status = 1;
  217. if (memPllCG_prev_status != mem_status) {
  218. memPllCG_prev_status = mem_status;
  219. need_log_out = 1;
  220. }
  221. }
  222. logout_sodi3_cnt++;
  223. logout_selfrefresh_cnt += spm_read(SPM_PASR_DPD_0);
  224. pre_emi_refresh_cnt = spm_read(SPM_PASR_DPD_0);
  225. if (need_log_out == 1) {
  226. sodi3_logout_prev_time = sodi3_logout_curr_time;
  227. if (wakesta->assert_pc != 0) {
  228. sodi3_err("wake up by SPM assert, vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  229. vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  230. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  231. sodi3_err("sodi3_cnt = %d, self_refresh_cnt = 0x%x, spm_pc = 0x%0x, r13 = 0x%x, debug_flag = 0x%x\n",
  232. logout_sodi3_cnt, logout_selfrefresh_cnt,
  233. wakesta->assert_pc, wakesta->r13, wakesta->debug_flag);
  234. sodi3_err("r12 = 0x%x, r12_e = 0x%x, raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
  235. wakesta->r12, wakesta->r12_ext, wakesta->raw_sta, wakesta->idle_sta,
  236. wakesta->event_reg, wakesta->isr);
  237. } else {
  238. char buf[LOG_BUF_SIZE] = { 0 };
  239. int i;
  240. if (wakesta->r12 & WAKE_SRC_R12_PCM_TIMER) {
  241. if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER)
  242. strcat(buf, " PCM_TIMER");
  243. if (wakesta->wake_misc & WAKE_MISC_TWAM)
  244. strcat(buf, " TWAM");
  245. if (wakesta->wake_misc & WAKE_MISC_CPU_WAKE)
  246. strcat(buf, " CPU");
  247. }
  248. for (i = 1; i < 32; i++) {
  249. if (wakesta->r12 & (1U << i)) {
  250. strcat(buf, wakesrc_str[i]);
  251. wr = WR_WAKE_SRC;
  252. }
  253. }
  254. BUG_ON(strlen(buf) >= LOG_BUF_SIZE);
  255. sodi3_warn("wake up by %s, vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  256. buf, vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  257. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  258. sodi3_warn("sodi3_cnt = %d, self_refresh_cnt = 0x%x, timer_out = %u, r13 = 0x%x, debug_flag = 0x%x\n",
  259. logout_sodi3_cnt, logout_selfrefresh_cnt,
  260. wakesta->timer_out, wakesta->r13, wakesta->debug_flag);
  261. sodi3_warn("r12 = 0x%x, r12_e = 0x%x, raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
  262. wakesta->r12, wakesta->r12_ext, wakesta->raw_sta, wakesta->idle_sta,
  263. wakesta->event_reg, wakesta->isr);
  264. }
  265. logout_sodi3_cnt = 0;
  266. logout_selfrefresh_cnt = 0;
  267. }
  268. }
  269. return wr;
  270. }
  271. wake_reason_t spm_go_to_sodi3(u32 spm_flags, u32 spm_data, u32 sodi3_flags)
  272. {
  273. u32 sec = 2;
  274. #ifdef CONFIG_MTK_WD_KICKER
  275. int wd_ret;
  276. struct wd_api *wd_api;
  277. #endif
  278. u32 con1;
  279. struct wake_status wakesta;
  280. unsigned long flags;
  281. struct mtk_irq_mask *mask;
  282. wake_reason_t wr = WR_NONE;
  283. struct pcm_desc *pcmdesc;
  284. struct pwr_ctrl *pwrctrl = __spm_sodi3.pwrctrl;
  285. int vcore_status = vcorefs_get_curr_ddr();
  286. u32 cpu = spm_data;
  287. u32 sodi_idx;
  288. #if defined(CONFIG_ARCH_MT6797)
  289. sodi_idx = spm_get_sodi_pcm_index() + cpu / 4;
  290. #else
  291. sodi_idx = DYNA_LOAD_PCM_SODI + cpu / 4;
  292. #endif
  293. if (!dyna_load_pcm[sodi_idx].ready) {
  294. sodi3_err("error: load firmware fail\n");
  295. BUG();
  296. }
  297. pcmdesc = &(dyna_load_pcm[sodi_idx].desc);
  298. spm_sodi3_footprint(SPM_SODI3_ENTER);
  299. if (spm_get_sodi_mempll() == 1)
  300. spm_flags |= SPM_FLAG_SODI_CG_MODE; /* CG mode */
  301. else
  302. spm_flags &= ~SPM_FLAG_SODI_CG_MODE; /* PDN mode */
  303. update_pwrctrl_pcm_flags(&spm_flags);
  304. set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
  305. pwrctrl->timer_val = sec * 32768;
  306. #ifdef CONFIG_MTK_WD_KICKER
  307. wd_ret = get_wd_api(&wd_api);
  308. if (!wd_ret)
  309. wd_api->wd_suspend_notify();
  310. #endif
  311. /* enable APxGPT timer */
  312. soidle3_before_wfi(cpu);
  313. lockdep_off();
  314. spin_lock_irqsave(&__spm_lock, flags);
  315. mask = kmalloc(sizeof(struct mtk_irq_mask), GFP_ATOMIC);
  316. if (!mask) {
  317. wr = -ENOMEM;
  318. goto UNLOCK_SPM;
  319. }
  320. mt_irq_mask_all(mask);
  321. mt_irq_unmask_for_sleep(SPM_IRQ0_ID);
  322. #if defined(CONFIG_MTK_SYS_CIRQ)
  323. mt_cirq_clone_gic();
  324. mt_cirq_enable();
  325. #endif
  326. spm_sodi3_footprint(SPM_SODI3_ENTER_UART_SLEEP);
  327. if (request_uart_to_sleep()) {
  328. wr = WR_UART_BUSY;
  329. goto RESTORE_IRQ;
  330. }
  331. spm_sodi3_footprint(SPM_SODI3_ENTER_SPM_FLOW);
  332. __spm_reset_and_init_pcm(pcmdesc);
  333. __spm_kick_im_to_fetch(pcmdesc);
  334. __spm_init_pcm_register();
  335. __spm_init_event_vector(pcmdesc);
  336. #if defined(CONFIG_ARCH_MT6755)
  337. __spm_check_md_pdn_power_control(pwrctrl);
  338. #endif
  339. __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcore_dvfs.pwrctrl);
  340. if (spm_read(SPM_SW_FLAG) & SPM_FLAG_SODI_CG_MODE) {
  341. /* the following masks set to be 1 only for SODI CG mode */
  342. pwrctrl->md_apsrc1_sel = 1;
  343. pwrctrl->md_apsrc0_sel = 1;
  344. pwrctrl->conn_apsrc_sel = 1;
  345. } else {
  346. /* the following masks set to be 0 which dynamic switch by FW */
  347. pwrctrl->md_apsrc1_sel = 0;
  348. pwrctrl->md_apsrc0_sel = 0;
  349. pwrctrl->conn_apsrc_sel = 0;
  350. }
  351. __spm_set_power_control(pwrctrl);
  352. __spm_set_wakeup_event(pwrctrl);
  353. /* PCM WDT WAKE MODE for lastPC */
  354. con1 = spm_read(PCM_CON1) & ~(PCM_WDT_WAKE_MODE_LSB | PCM_WDT_EN_LSB);
  355. spm_write(PCM_CON1, SPM_REGWR_CFG_KEY | con1);
  356. if (spm_read(PCM_TIMER_VAL) > PCM_TIMER_MAX)
  357. spm_write(PCM_TIMER_VAL, PCM_TIMER_MAX);
  358. spm_write(PCM_WDT_VAL, spm_read(PCM_TIMER_VAL) + PCM_WDT_TIMEOUT);
  359. if (pwrctrl->timer_val_cust == 0)
  360. spm_write(PCM_CON1, con1 | SPM_REGWR_CFG_KEY | PCM_WDT_EN_LSB | PCM_TIMER_EN_LSB);
  361. else
  362. spm_write(PCM_CON1, con1 | SPM_REGWR_CFG_KEY | PCM_WDT_EN_LSB);
  363. spm_sodi3_pre_process();
  364. __spm_kick_pcm_to_run(pwrctrl);
  365. spm_sodi3_footprint_val((1 << SPM_SODI3_ENTER_WFI) |
  366. (1 << SPM_SODI3_B3) | (1 << SPM_SODI3_B4) |
  367. (1 << SPM_SODI3_B5) | (1 << SPM_SODI3_B6));
  368. #ifdef SPM_SODI3_PROFILE_TIME
  369. gpt_get_cnt(SPM_SODI3_PROFILE_APXGPT, &soidle3_profile[1]);
  370. #endif
  371. spm_trigger_wfi_for_sodi(pwrctrl);
  372. #ifdef SPM_SODI3_PROFILE_TIME
  373. gpt_get_cnt(SPM_SODI3_PROFILE_APXGPT, &soidle3_profile[2]);
  374. #endif
  375. spm_sodi3_footprint(SPM_SODI3_LEAVE_WFI);
  376. spm_sodi3_post_process();
  377. __spm_get_wakeup_status(&wakesta);
  378. /* disable PCM WDT to stop count if needed */
  379. spm_write(PCM_CON1, SPM_REGWR_CFG_KEY | (spm_read(PCM_CON1) & ~PCM_WDT_EN_LSB));
  380. __spm_clean_after_wakeup();
  381. spm_sodi3_footprint(SPM_SODI3_ENTER_UART_AWAKE);
  382. request_uart_to_wakeup();
  383. wr = spm_sodi3_output_log(&wakesta, pcmdesc, vcore_status, sodi3_flags);
  384. spm_sodi3_footprint(SPM_SODI3_LEAVE_SPM_FLOW);
  385. RESTORE_IRQ:
  386. #if defined(CONFIG_MTK_SYS_CIRQ)
  387. mt_cirq_flush();
  388. mt_cirq_disable();
  389. #endif
  390. mt_irq_mask_restore(mask);
  391. kfree(mask);
  392. UNLOCK_SPM:
  393. spin_unlock_irqrestore(&__spm_lock, flags);
  394. lockdep_on();
  395. /* stop APxGPT timer and enable caore0 local timer */
  396. soidle3_after_wfi(cpu);
  397. #ifdef CONFIG_MTK_WD_KICKER
  398. if (!wd_ret)
  399. wd_api->wd_resume_notify();
  400. #endif
  401. spm_sodi3_reset_footprint();
  402. return wr;
  403. }
  404. void spm_enable_sodi3(bool en)
  405. {
  406. gSpm_sodi3_en = en;
  407. }
  408. bool spm_get_sodi3_en(void)
  409. {
  410. return gSpm_sodi3_en;
  411. }
  412. void spm_sodi3_init(void)
  413. {
  414. sodi3_debug("spm_sodi3_init\n");
  415. spm_sodi3_aee_init();
  416. }
  417. MODULE_DESCRIPTION("SPM-SODI3 Driver v0.1");