mt_spm_sodi.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  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. #ifdef CONFIG_OF
  8. #include <linux/of.h>
  9. #include <linux/of_irq.h>
  10. #include <linux/of_address.h>
  11. #endif
  12. #include <mach/irqs.h>
  13. #include <mach/mt_gpt.h>
  14. #include <mach/mt_secure_api.h>
  15. #include <mt-plat/mt_boot.h>
  16. #if defined(CONFIG_MTK_SYS_CIRQ)
  17. #include <mt-plat/mt_cirq.h>
  18. #endif
  19. #include <mt-plat/upmu_common.h>
  20. #include <mt-plat/mt_io.h>
  21. #include <mt_spm_sodi.h>
  22. /**************************************
  23. * only for internal debug
  24. **************************************/
  25. #define SODI_TAG "[SODI] "
  26. #define sodi_err(fmt, args...) pr_err(SODI_TAG fmt, ##args)
  27. #define sodi_warn(fmt, args...) pr_warn(SODI_TAG fmt, ##args)
  28. #define sodi_debug(fmt, args...) pr_debug(SODI_TAG fmt, ##args)
  29. #define SPM_BYPASS_SYSPWREQ 0
  30. #define LOG_BUF_SIZE (256)
  31. #define SODI_LOGOUT_TIMEOUT_CRITERIA (20)
  32. #define SODI_LOGOUT_INTERVAL_CRITERIA (5000U) /* unit:ms */
  33. #if defined(CONFIG_OF)
  34. #define MCUCFG_NODE "mediatek,MCUCFG"
  35. static unsigned long mcucfg_base;
  36. static unsigned long mcucfg_phys_base;
  37. #undef MCUCFG_BASE
  38. #define MCUCFG_BASE (mcucfg_base)
  39. #define M4U_NODE "mediatek,M4U"
  40. static unsigned long m4u_base;
  41. static unsigned long m4u_phys_base;
  42. #undef M4U_BASE
  43. #define M4U_BASE (m4u_base)
  44. #else /* #if defined (CONFIG_OF) */
  45. #undef MCUCFG_BASE
  46. #define MCUCFG_BASE 0xF0200000 /* 0x1020_0000 */
  47. #undef M4U_BASE
  48. #define M4U_BASE 0xF0205000 /* 0x1020_5000 */
  49. #endif /* #if defined (CONFIG_OF) */
  50. /* MCUCFG registers */
  51. #define MP0_AXI_CONFIG (MCUCFG_BASE + 0x2C)
  52. #define MP0_AXI_CONFIG_PHYS (mcucfg_phys_base + 0x2C)
  53. #define MP1_AXI_CONFIG (MCUCFG_BASE + 0x22C)
  54. #define MP1_AXI_CONFIG_PHYS (mcucfg_phys_base + 0x22C)
  55. #define ACINACTM (1 << 4)
  56. /* M4U registers */
  57. #define MMU_SMI_ASYNC_CFG (M4U_BASE + 0xB80)
  58. #define MMU_SMI_ASYNC_CFG_PHYS (m4u_phys_base + 0xB80)
  59. #define SMI_COMMON_ASYNC_DCM (0x3 << 14)
  60. static struct pwr_ctrl sodi_ctrl = {
  61. .wake_src = WAKE_SRC_FOR_SODI,
  62. .wake_src_md32 = WAKE_SRC_FOR_MD32,
  63. .r0_ctrl_en = 1,
  64. .r7_ctrl_en = 1,
  65. #if defined(CONFIG_ARCH_MT6755)
  66. .infra_dcm_lock = 1,
  67. #elif defined(CONFIG_ARCH_MT6797)
  68. .infra_dcm_lock = 0, /* set to be 0 if SODI original */
  69. #endif
  70. .wfi_op = WFI_OP_AND,
  71. /* SPM_AP_STANDBY_CON */
  72. .mp0top_idle_mask = 0,
  73. .mp1top_idle_mask = 0,
  74. .mcusys_idle_mask = 0,
  75. .md_ddr_dbc_en = 0,
  76. .md1_req_mask_b = 1,
  77. .md2_req_mask_b = 0, /* bit 20 */
  78. #if defined(CONFIG_ARCH_MT6755)
  79. .scp_req_mask_b = 0, /* bit 21 */
  80. #elif defined(CONFIG_ARCH_MT6797)
  81. .scp_req_mask_b = 1, /* bit 21 */
  82. #endif
  83. .lte_mask_b = 0,
  84. .md_apsrc1_sel = 0, /* bit 24 */
  85. .md_apsrc0_sel = 0, /* bit 25 */
  86. .conn_mask_b = 1,
  87. .conn_apsrc_sel = 0, /* bit 27 */
  88. /* SPM_SRC_REQ */
  89. .spm_apsrc_req = 0,
  90. .spm_f26m_req = 0,
  91. .spm_lte_req = 0,
  92. .spm_infra_req = 0,
  93. .spm_vrf18_req = 0,
  94. .spm_dvfs_req = 0,
  95. .spm_dvfs_force_down = 0,
  96. .spm_ddren_req = 0,
  97. .cpu_md_dvfs_sop_force_on = 0,
  98. /* SPM_SRC_MASK */
  99. .ccif0_to_md_mask_b = 1,
  100. .ccif0_to_ap_mask_b = 1,
  101. .ccif1_to_md_mask_b = 1,
  102. .ccif1_to_ap_mask_b = 1,
  103. .ccifmd_md1_event_mask_b = 1,
  104. .ccifmd_md2_event_mask_b = 1,
  105. .vsync_mask_b = 0, /* 5-bit */
  106. .md_srcclkena_0_infra_mask_b = 0, /* bit 12 */
  107. .md_srcclkena_1_infra_mask_b = 0, /* bit 13 */
  108. .conn_srcclkena_infra_mask_b = 0, /* bit 14 */
  109. .md32_srcclkena_infra_mask_b = 0, /* bit 15 */
  110. .srcclkeni_infra_mask_b = 0, /* bit 16 */
  111. .md_apsrcreq_0_infra_mask_b = 1,
  112. .md_apsrcreq_1_infra_mask_b = 0,
  113. .conn_apsrcreq_infra_mask_b = 1,
  114. #if defined(CONFIG_ARCH_MT6755)
  115. .md32_apsrcreq_infra_mask_b = 0,
  116. #elif defined(CONFIG_ARCH_MT6797)
  117. .md32_apsrcreq_infra_mask_b = 1,
  118. #endif
  119. .md_ddr_en_0_mask_b = 1,
  120. .md_ddr_en_1_mask_b = 0, /* bit 22 */
  121. .md_vrf18_req_0_mask_b = 1,
  122. .md_vrf18_req_1_mask_b = 0, /* bit 24 */
  123. .emi_bw_dvfs_req_mask = 1,
  124. .md_srcclkena_0_dvfs_req_mask_b = 0,
  125. .md_srcclkena_1_dvfs_req_mask_b = 0,
  126. .conn_srcclkena_dvfs_req_mask_b = 0,
  127. /* SPM_SRC2_MASK */
  128. .dvfs_halt_mask_b = 0x1f, /* 5-bit */
  129. .vdec_req_mask_b = 0, /* bit 6 */
  130. .gce_req_mask_b = 1, /* bit 7, set to be 1 for SODI */
  131. .cpu_md_dvfs_erq_merge_mask_b = 0,
  132. .md1_ddr_en_dvfs_halt_mask_b = 0,
  133. .md2_ddr_en_dvfs_halt_mask_b = 0,
  134. .vsync_dvfs_halt_mask_b = 0, /* 5-bit, bit 11 ~ 15 */
  135. .conn_ddr_en_mask_b = 1,
  136. .disp_req_mask_b = 1, /* bit 17, set to be 1 for SODI */
  137. .disp1_req_mask_b = 1, /* bit 18, set to be 1 for SODI */
  138. #if defined(CONFIG_ARCH_MT6755)
  139. .mfg_req_mask_b = 0, /* bit 19 */
  140. #elif defined(CONFIG_ARCH_MT6797)
  141. .mfg_req_mask_b = 1, /* bit 19, set to be 1 for SODI */
  142. #endif
  143. .c2k_ps_rccif_wake_mask_b = 1,
  144. .c2k_l1_rccif_wake_mask_b = 1,
  145. .ps_c2k_rccif_wake_mask_b = 1,
  146. .l1_c2k_rccif_wake_mask_b = 1,
  147. .sdio_on_dvfs_req_mask_b = 0,
  148. .emi_boost_dvfs_req_mask_b = 0,
  149. .cpu_md_emi_dvfs_req_prot_dis = 0,
  150. #if defined(CONFIG_ARCH_MT6797)
  151. .disp_od_req_mask_b = 1, /* bit 27, set to be 1 for SODI */
  152. #endif
  153. /* SPM_CLK_CON */
  154. .srclkenai_mask = 1,
  155. .mp1_cpu0_wfi_en = 1,
  156. .mp1_cpu1_wfi_en = 1,
  157. .mp1_cpu2_wfi_en = 1,
  158. .mp1_cpu3_wfi_en = 1,
  159. .mp0_cpu0_wfi_en = 1,
  160. .mp0_cpu1_wfi_en = 1,
  161. .mp0_cpu2_wfi_en = 1,
  162. .mp0_cpu3_wfi_en = 1,
  163. #if SPM_BYPASS_SYSPWREQ
  164. .syspwreq_mask = 1,
  165. #endif
  166. };
  167. /* please put firmware to vendor/mediatek/proprietary/hardware/spm/mtxxxx/ */
  168. struct spm_lp_scen __spm_sodi = {
  169. .pwrctrl = &sodi_ctrl,
  170. };
  171. /* 0:power-down mode, 1:CG mode */
  172. static bool gSpm_SODI_mempll_pwr_mode;
  173. static bool gSpm_sodi_en;
  174. static unsigned long int sodi_logout_prev_time;
  175. static int pre_emi_refresh_cnt;
  176. static int memPllCG_prev_status = 1; /* 1:CG, 0:pwrdn */
  177. static unsigned int logout_sodi_cnt;
  178. static unsigned int logout_selfrefresh_cnt;
  179. void spm_trigger_wfi_for_sodi(struct pwr_ctrl *pwrctrl)
  180. {
  181. u32 v0, v1;
  182. if (is_cpu_pdn(pwrctrl->pcm_flags)) {
  183. mt_cpu_dormant(CPU_SODI_MODE);
  184. } else {
  185. /* backup MPx_AXI_CONFIG */
  186. v0 = reg_read(MP0_AXI_CONFIG);
  187. v1 = reg_read(MP1_AXI_CONFIG);
  188. /* disable snoop function */
  189. MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, v0 | ACINACTM);
  190. MCUSYS_SMC_WRITE(MP1_AXI_CONFIG, v1 | ACINACTM);
  191. sodi_debug("enter legacy WFI, MP0_AXI_CONFIG=0x%x, MP1_AXI_CONFIG=0x%x\n",
  192. reg_read(MP0_AXI_CONFIG), reg_read(MP1_AXI_CONFIG));
  193. /* enter WFI */
  194. wfi_with_sync();
  195. /* restore MP0_AXI_CONFIG */
  196. MCUSYS_SMC_WRITE(MP0_AXI_CONFIG, v0);
  197. MCUSYS_SMC_WRITE(MP1_AXI_CONFIG, v1);
  198. sodi_debug("exit legacy WFI, MP0_AXI_CONFIG=0x%x, MP1_AXI_CONFIG=0x%x\n",
  199. reg_read(MP0_AXI_CONFIG), reg_read(MP1_AXI_CONFIG));
  200. }
  201. }
  202. static u32 mmu_smi_async_cfg;
  203. void spm_disable_mmu_smi_async(void)
  204. {
  205. mmu_smi_async_cfg = reg_read(MMU_SMI_ASYNC_CFG);
  206. reg_write(MMU_SMI_ASYNC_CFG, mmu_smi_async_cfg | SMI_COMMON_ASYNC_DCM);
  207. }
  208. void spm_enable_mmu_smi_async(void)
  209. {
  210. reg_write(MMU_SMI_ASYNC_CFG, mmu_smi_async_cfg);
  211. }
  212. static void spm_sodi_pre_process(void)
  213. {
  214. #if defined(CONFIG_ARCH_MT6755)
  215. u32 val;
  216. #endif
  217. __spm_pmic_pg_force_on();
  218. spm_disable_mmu_smi_async();
  219. spm_bypass_boost_gpio_set();
  220. #if defined(CONFIG_ARCH_MT6755)
  221. pmic_read_interface_nolock(MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_ADDR,
  222. &val,
  223. MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_MASK,
  224. MT6351_PMIC_BUCK_VSRAM_PROC_VOSEL_ON_SHIFT);
  225. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE, IDX_DI_VSRAM_NORMAL, val);
  226. pmic_read_interface_nolock(MT6351_TOP_CON, &val, 0x037F, 0);
  227. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE,
  228. IDX_DI_SRCCLKEN_IN2_NORMAL,
  229. val | (1 << MT6351_PMIC_RG_SRCLKEN_IN2_EN_SHIFT));
  230. mt_spm_pmic_wrap_set_cmd(PMIC_WRAP_PHASE_DEEPIDLE,
  231. IDX_DI_SRCCLKEN_IN2_SLEEP,
  232. val & ~(1 << MT6351_PMIC_RG_SRCLKEN_IN2_EN_SHIFT));
  233. #endif
  234. /* set PMIC WRAP table for deepidle power control */
  235. mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_DEEPIDLE);
  236. /* Do more low power setting when MD1/C2K/CONN off */
  237. if (is_md_c2k_conn_power_off())
  238. __spm_bsi_top_init_setting();
  239. }
  240. static void spm_sodi_post_process(void)
  241. {
  242. /* set PMIC WRAP table for normal power control */
  243. mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_NORMAL);
  244. spm_enable_mmu_smi_async();
  245. __spm_pmic_pg_force_off();
  246. }
  247. static wake_reason_t
  248. spm_sodi_output_log(struct wake_status *wakesta, struct pcm_desc *pcmdesc, int vcore_status, u32 sodi_flags)
  249. {
  250. wake_reason_t wr = WR_NONE;
  251. unsigned long int sodi_logout_curr_time = 0;
  252. int need_log_out = 0;
  253. if (sodi_flags&SODI_FLAG_NO_LOG) {
  254. if (wakesta->assert_pc != 0) {
  255. sodi_err("PCM ASSERT AT %u (%s), r13 = 0x%x, debug_flag = 0x%x\n",
  256. wakesta->assert_pc, pcmdesc->version, wakesta->r13, wakesta->debug_flag);
  257. wr = WR_PCM_ASSERT;
  258. }
  259. } else if (!(sodi_flags&SODI_FLAG_REDUCE_LOG) || (sodi_flags & SODI_FLAG_RESIDENCY)) {
  260. sodi_warn("vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  261. vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  262. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  263. wr = __spm_output_wake_reason(wakesta, pcmdesc, false);
  264. } else {
  265. sodi_logout_curr_time = spm_get_current_time_ms();
  266. if (wakesta->assert_pc != 0) {
  267. need_log_out = 1;
  268. } else if ((wakesta->r12 & (0x1 << 4)) == 0) {
  269. /* not wakeup by GPT */
  270. need_log_out = 1;
  271. } else if (wakesta->timer_out <= SODI_LOGOUT_TIMEOUT_CRITERIA) {
  272. need_log_out = 1;
  273. } else if ((spm_read(SPM_PASR_DPD_0) == 0 && pre_emi_refresh_cnt > 0) ||
  274. (spm_read(SPM_PASR_DPD_0) > 0 && pre_emi_refresh_cnt == 0)) {
  275. need_log_out = 1;
  276. } else if ((sodi_logout_curr_time - sodi_logout_prev_time) > SODI_LOGOUT_INTERVAL_CRITERIA) {
  277. /* previous logout time > SODI_LOGOUT_INTERVAL_CRITERIA */
  278. need_log_out = 1;
  279. } else {
  280. /* check CG/pwrdn status is changed */
  281. int mem_status = 0;
  282. /* check mempll CG/pwrdn status change */
  283. if (((spm_read(SPM_SW_FLAG) & SPM_FLAG_SODI_CG_MODE) != 0) ||
  284. ((spm_read(DUMMY1_PWR_CON) & DUMMY1_PWR_ISO_LSB) != 0))
  285. mem_status = 1;
  286. if (memPllCG_prev_status != mem_status) {
  287. memPllCG_prev_status = mem_status;
  288. need_log_out = 1;
  289. }
  290. }
  291. logout_sodi_cnt++;
  292. logout_selfrefresh_cnt += spm_read(SPM_PASR_DPD_0);
  293. pre_emi_refresh_cnt = spm_read(SPM_PASR_DPD_0);
  294. if (need_log_out == 1) {
  295. sodi_logout_prev_time = sodi_logout_curr_time;
  296. if (wakesta->assert_pc != 0) {
  297. sodi_err("wake up by SPM assert, vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  298. vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  299. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  300. sodi_err("sodi_cnt = %d, self_refresh_cnt = 0x%x, spm_pc = 0x%0x, r13 = 0x%x, debug_flag = 0x%x\n",
  301. logout_sodi_cnt, logout_selfrefresh_cnt,
  302. wakesta->assert_pc, wakesta->r13, wakesta->debug_flag);
  303. sodi_err("r12 = 0x%x, r12_e = 0x%x, raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
  304. wakesta->r12, wakesta->r12_ext, wakesta->raw_sta, wakesta->idle_sta,
  305. wakesta->event_reg, wakesta->isr);
  306. } else {
  307. char buf[LOG_BUF_SIZE] = { 0 };
  308. int i;
  309. if (wakesta->r12 & WAKE_SRC_R12_PCM_TIMER) {
  310. if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER)
  311. strcat(buf, " PCM_TIMER");
  312. if (wakesta->wake_misc & WAKE_MISC_TWAM)
  313. strcat(buf, " TWAM");
  314. if (wakesta->wake_misc & WAKE_MISC_CPU_WAKE)
  315. strcat(buf, " CPU");
  316. }
  317. for (i = 1; i < 32; i++) {
  318. if (wakesta->r12 & (1U << i)) {
  319. strcat(buf, wakesrc_str[i]);
  320. wr = WR_WAKE_SRC;
  321. }
  322. }
  323. BUG_ON(strlen(buf) >= LOG_BUF_SIZE);
  324. sodi_warn("wake up by %s, vcore_status = %d, self_refresh = 0x%x, sw_flag = 0x%x, 0x%x, %s\n",
  325. buf, vcore_status, spm_read(SPM_PASR_DPD_0), spm_read(SPM_SW_FLAG),
  326. spm_read(DUMMY1_PWR_CON), pcmdesc->version);
  327. sodi_warn("sodi_cnt = %d, self_refresh_cnt = 0x%x, timer_out = %u, r13 = 0x%x, debug_flag = 0x%x\n",
  328. logout_sodi_cnt, logout_selfrefresh_cnt,
  329. wakesta->timer_out, wakesta->r13, wakesta->debug_flag);
  330. sodi_warn("r12 = 0x%x, r12_e = 0x%x, raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
  331. wakesta->r12, wakesta->r12_ext, wakesta->raw_sta, wakesta->idle_sta,
  332. wakesta->event_reg, wakesta->isr);
  333. }
  334. logout_sodi_cnt = 0;
  335. logout_selfrefresh_cnt = 0;
  336. }
  337. }
  338. return wr;
  339. }
  340. wake_reason_t spm_go_to_sodi(u32 spm_flags, u32 spm_data, u32 sodi_flags)
  341. {
  342. struct wake_status wakesta;
  343. unsigned long flags;
  344. struct mtk_irq_mask *mask;
  345. wake_reason_t wr = WR_NONE;
  346. struct pcm_desc *pcmdesc;
  347. struct pwr_ctrl *pwrctrl = __spm_sodi.pwrctrl;
  348. int vcore_status = vcorefs_get_curr_ddr();
  349. u32 cpu = spm_data;
  350. u32 sodi_idx;
  351. #if defined(CONFIG_ARCH_MT6797)
  352. sodi_idx = spm_get_sodi_pcm_index() + cpu / 4;
  353. #else
  354. sodi_idx = DYNA_LOAD_PCM_SODI + cpu / 4;
  355. #endif
  356. if (!dyna_load_pcm[sodi_idx].ready) {
  357. sodi_err("error: load firmware fail\n");
  358. BUG();
  359. }
  360. pcmdesc = &(dyna_load_pcm[sodi_idx].desc);
  361. spm_sodi_footprint(SPM_SODI_ENTER);
  362. if (gSpm_SODI_mempll_pwr_mode == 1)
  363. spm_flags |= SPM_FLAG_SODI_CG_MODE; /* CG mode */
  364. else
  365. spm_flags &= ~SPM_FLAG_SODI_CG_MODE; /* PDN mode */
  366. update_pwrctrl_pcm_flags(&spm_flags);
  367. set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
  368. /* enable APxGPT timer */
  369. soidle_before_wfi(cpu);
  370. lockdep_off();
  371. spin_lock_irqsave(&__spm_lock, flags);
  372. mask = kmalloc(sizeof(struct mtk_irq_mask), GFP_ATOMIC);
  373. if (!mask) {
  374. wr = -ENOMEM;
  375. goto UNLOCK_SPM;
  376. }
  377. mt_irq_mask_all(mask);
  378. mt_irq_unmask_for_sleep(SPM_IRQ0_ID);
  379. #if defined(CONFIG_MTK_SYS_CIRQ)
  380. mt_cirq_clone_gic();
  381. mt_cirq_enable();
  382. #endif
  383. spm_sodi_footprint(SPM_SODI_ENTER_UART_SLEEP);
  384. if (request_uart_to_sleep()) {
  385. wr = WR_UART_BUSY;
  386. goto RESTORE_IRQ;
  387. }
  388. spm_sodi_footprint(SPM_SODI_ENTER_SPM_FLOW);
  389. __spm_reset_and_init_pcm(pcmdesc);
  390. __spm_kick_im_to_fetch(pcmdesc);
  391. __spm_init_pcm_register();
  392. __spm_init_event_vector(pcmdesc);
  393. __spm_check_md_pdn_power_control(pwrctrl);
  394. __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcore_dvfs.pwrctrl);
  395. #if defined(CONFIG_ARCH_MT6797)
  396. if (spm_read(SPM_SW_FLAG) & SPM_FLAG_SODI_CG_MODE) {
  397. /* the following masks set to be 1 only for SODI CG mode */
  398. pwrctrl->md_apsrc1_sel = 1;
  399. pwrctrl->md_apsrc0_sel = 1;
  400. pwrctrl->conn_apsrc_sel = 1;
  401. } else {
  402. /* the following masks set to be 0 which dynamic switch by FW */
  403. pwrctrl->md_apsrc1_sel = 0;
  404. pwrctrl->md_apsrc0_sel = 0;
  405. pwrctrl->conn_apsrc_sel = 0;
  406. }
  407. #endif
  408. __spm_set_power_control(pwrctrl);
  409. __spm_set_wakeup_event(pwrctrl);
  410. if (pwrctrl->timer_val_cust == 0) {
  411. if (spm_read(PCM_TIMER_VAL) > PCM_TIMER_MAX)
  412. spm_write(PCM_TIMER_VAL, PCM_TIMER_MAX);
  413. spm_write(PCM_CON1, spm_read(PCM_CON1) | SPM_REGWR_CFG_KEY | PCM_TIMER_EN_LSB);
  414. }
  415. spm_sodi_pre_process();
  416. __spm_kick_pcm_to_run(pwrctrl);
  417. spm_sodi_footprint_val((1 << SPM_SODI_ENTER_WFI) |
  418. (1 << SPM_SODI_B3) | (1 << SPM_SODI_B4) |
  419. (1 << SPM_SODI_B5) | (1 << SPM_SODI_B6));
  420. #ifdef SPM_SODI_PROFILE_TIME
  421. gpt_get_cnt(SPM_SODI_PROFILE_APXGPT, &soidle_profile[1]);
  422. #endif
  423. spm_trigger_wfi_for_sodi(pwrctrl);
  424. #ifdef SPM_SODI_PROFILE_TIME
  425. gpt_get_cnt(SPM_SODI_PROFILE_APXGPT, &soidle_profile[2]);
  426. #endif
  427. spm_sodi_footprint(SPM_SODI_LEAVE_WFI);
  428. spm_sodi_post_process();
  429. __spm_get_wakeup_status(&wakesta);
  430. __spm_clean_after_wakeup();
  431. spm_sodi_footprint(SPM_SODI_ENTER_UART_AWAKE);
  432. request_uart_to_wakeup();
  433. wr = spm_sodi_output_log(&wakesta, pcmdesc, vcore_status, sodi_flags);
  434. spm_sodi_footprint(SPM_SODI_LEAVE_SPM_FLOW);
  435. RESTORE_IRQ:
  436. #if defined(CONFIG_MTK_SYS_CIRQ)
  437. mt_cirq_flush();
  438. mt_cirq_disable();
  439. #endif
  440. mt_irq_mask_restore(mask);
  441. kfree(mask);
  442. UNLOCK_SPM:
  443. spin_unlock_irqrestore(&__spm_lock, flags);
  444. lockdep_on();
  445. /* stop APxGPT timer and enable caore0 local timer */
  446. soidle_after_wfi(cpu);
  447. spm_sodi_reset_footprint();
  448. return wr;
  449. }
  450. void spm_sodi_mempll_pwr_mode(bool pwr_mode)
  451. {
  452. gSpm_SODI_mempll_pwr_mode = pwr_mode;
  453. }
  454. bool spm_get_sodi_mempll(void)
  455. {
  456. return gSpm_SODI_mempll_pwr_mode;
  457. }
  458. void spm_enable_sodi(bool en)
  459. {
  460. gSpm_sodi_en = en;
  461. }
  462. bool spm_get_sodi_en(void)
  463. {
  464. return gSpm_sodi_en;
  465. }
  466. void spm_sodi_init(void)
  467. {
  468. #if defined(CONFIG_OF)
  469. struct device_node *node;
  470. struct resource r;
  471. /* mcucfg */
  472. node = of_find_compatible_node(NULL, NULL, MCUCFG_NODE);
  473. if (!node) {
  474. sodi_err("error: cannot find node " MCUCFG_NODE);
  475. goto mcucfg_exit;
  476. }
  477. if (of_address_to_resource(node, 0, &r)) {
  478. sodi_err("error: cannot get phys addr" MCUCFG_NODE);
  479. goto mcucfg_exit;
  480. }
  481. mcucfg_phys_base = r.start;
  482. mcucfg_base = (unsigned long)of_iomap(node, 0);
  483. if (!mcucfg_base) {
  484. sodi_err("error: cannot iomap " MCUCFG_NODE);
  485. goto mcucfg_exit;
  486. }
  487. sodi_debug("mcucfg_base = 0x%u\n", (unsigned int)mcucfg_base);
  488. mcucfg_exit:
  489. /* m4u */
  490. node = of_find_compatible_node(NULL, NULL, M4U_NODE);
  491. if (!node) {
  492. sodi_err("error: cannot find node " M4U_NODE);
  493. goto m4u_exit;
  494. }
  495. if (of_address_to_resource(node, 0, &r)) {
  496. sodi_err("error: cannot get phys addr" M4U_NODE);
  497. goto m4u_exit;
  498. }
  499. m4u_phys_base = r.start;
  500. m4u_base = (unsigned long)of_iomap(node, 0);
  501. if (!m4u_base) {
  502. sodi_err("error: cannot iomap " M4U_NODE);
  503. goto m4u_exit;
  504. }
  505. sodi_debug("m4u_base = 0x%u\n", (unsigned int)m4u_base);
  506. m4u_exit:
  507. sodi_debug("spm_sodi_init\n");
  508. #endif
  509. spm_sodi_aee_init();
  510. }
  511. MODULE_DESCRIPTION("SPM-SODI Driver v0.1");