mt_spm_mcdi.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #include <linux/cpu.h>
  2. #include <linux/delay.h>
  3. #include <linux/init.h>
  4. #include <linux/kernel.h>
  5. #include <linux/module.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/proc_fs.h>
  8. #include <linux/spinlock.h>
  9. #include <mach/hotplug.h>
  10. #include <mach/irqs.h>
  11. #include <mach/mt_boot.h>
  12. #include <mach/mt_cirq.h>
  13. #include <mach/mt_cpuidle.h>
  14. #include <mach/mt_gpt.h>
  15. #include <mach/mt_spm_idle.h>
  16. #include <mach/mt_spm_misc.h>
  17. #include "mt_spm_internal.h"
  18. /**************************************
  19. * only for internal debug
  20. **************************************/
  21. /* FIXME: for FPGA early porting */
  22. /* #define CONFIG_MTK_LDVT */
  23. #ifdef CONFIG_MTK_LDVT
  24. #define SPM_BYPASS_SYSPWREQ 1
  25. #else
  26. #define SPM_BYPASS_SYSPWREQ 0
  27. #endif
  28. #define SPM_AEE_RR_REC 0
  29. #define WAKE_SRC_FOR_MCDI (WAKE_SRC_R12_CSYSPWREQ_B | WAKE_SRC_R12_CPU_IRQ_B)
  30. #define WAKE_SRC_FOR_MD32 0 /* (WAKE_SRC_AUD_MD32) */
  31. #define SPM_MCDI_CORE_MAX_EXIT_TIME 100000
  32. /*
  33. * MCDI DVT GPT test
  34. * GPT need to modify mt_idle.c and mt_spm_mcdi.c
  35. */
  36. #define MCDI_DVT_IPI 0 /*0:disable, 1: enable : mt_idle.c , mt_spm_mcdi.c and mt_cpuidle.c */
  37. #define MCDI_DVT_CPUxGPT 0 /*0:disable, 1: enable : GPT need to modify mt_idle.c and mt_spm_mcdi.c mt_cpuidle.c */
  38. #define MCDI_DVT_W_DORMANT 0 /*1: with dormant, 0: without dormant */
  39. #define __weak __attribute__((weak))
  40. __weak unsigned int mt_get_chip_sw_ver(void) {return 0; }
  41. /* TODO:[fixme:setting] */
  42. static struct pwr_ctrl mcdi_ctrl = {
  43. .wake_src = WAKE_SRC_FOR_MCDI,
  44. .wake_src_md32 = WAKE_SRC_FOR_MD32,
  45. .wfi_op = WFI_OP_OR,
  46. .mcusys_idle_mask = 1,
  47. .mp0top_idle_mask = 1,
  48. .mp1top_idle_mask = 1,
  49. .md1_req_mask_b = 1,
  50. .md2_req_mask_b = 1,
  51. .disp_req_mask_b = 1,
  52. .mfg_req_mask_b = 1,
  53. .scp_req_mask_b = 1,
  54. #if SPM_BYPASS_SYSPWREQ
  55. .syspwreq_mask = 1,
  56. #endif
  57. #if ((MCDI_DVT_CPUxGPT) || (MCDI_DVT_IPI)) && (!MCDI_DVT_W_DORMANT)
  58. .pcm_reserve = 0xff,
  59. #endif
  60. };
  61. static const u32 mcdi_binary[] = {
  62. 0x1840001f, 0x00000001, 0x1990001f, 0x10006600, 0x11407c1f, 0xe8208000,
  63. 0x10006614, 0x00000000, 0x1b00001f, 0x21000001, 0x1b80001f, 0xd0010000,
  64. 0x1880001f, 0x10006098, 0x18d0001f, 0x10006098, 0x69200003, 0xbeefbeef,
  65. 0xd8200444, 0x17c07c1f, 0x18c0001f, 0xdeaddead, 0xe0800003, 0x18d0001f,
  66. 0x10006098, 0x69200003, 0xabcdabcd, 0xd82002e4, 0x17c07c1f, 0x1880001f,
  67. 0x10006098, 0x18c0001f, 0x12345678, 0xe0800003, 0x60a07c05, 0xa9100004,
  68. 0x10006530, 0xa9100004, 0x10006534, 0xa9100004, 0x10006538, 0xa9100004,
  69. 0x1000653c, 0xa9100004, 0x10006540, 0xa9100004, 0x10006544, 0xa9100004,
  70. 0x10006548, 0xa9100004, 0x1000654c, 0x80a01002, 0x89100002, 0x10006614,
  71. 0x80801001, 0xd8003ee2, 0x17c07c1f, 0x1a10001f, 0x10006174, 0x82002001,
  72. 0x82201408, 0xd8200968, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82002001,
  73. 0xd8000948, 0x17c07c1f, 0x1a40001f, 0x10006208, 0x1a80001f, 0x10006248,
  74. 0xc2404300, 0x17c07c1f, 0xa1400405, 0x1a10001f, 0x10006174, 0x8200a001,
  75. 0x82209408, 0xd8200ba8, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x8200a001,
  76. 0xd8000b88, 0x17c07c1f, 0x1a40001f, 0x1000620c, 0x1a80001f, 0x1000624c,
  77. 0xc2404300, 0x17c07c1f, 0xa1508405, 0x1a10001f, 0x10006174, 0x82012001,
  78. 0x82211408, 0xd8200de8, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82012001,
  79. 0xd8000dc8, 0x17c07c1f, 0x1a40001f, 0x10006210, 0x1a80001f, 0x10006250,
  80. 0xc2404300, 0x17c07c1f, 0xa1510405, 0x1a10001f, 0x10006174, 0x8201a001,
  81. 0x82219408, 0xd8201028, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x8201a001,
  82. 0xd8001008, 0x17c07c1f, 0x1a40001f, 0x10006214, 0x1a80001f, 0x10006254,
  83. 0xc2404300, 0x17c07c1f, 0xa1518405, 0x1a10001f, 0x10006174, 0x88800008,
  84. 0x0000000f, 0x80c01402, 0x6a200003, 0x0000000f, 0x82241408, 0xd8201228,
  85. 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82042001, 0xd8001208, 0x17c07c1f,
  86. 0xa1540405, 0x1a10001f, 0x10006174, 0x82022001, 0x82221408, 0xd8201468,
  87. 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82022001, 0xd8001448, 0x17c07c1f,
  88. 0x1a40001f, 0x1000621c, 0x1a80001f, 0x10006260, 0xc2404300, 0x17c07c1f,
  89. 0xa1520405, 0x1a10001f, 0x10006174, 0x8202a001, 0x82229408, 0xd82016a8,
  90. 0x17c07c1f, 0x1a10001f, 0x10006608, 0x8202a001, 0xd8001688, 0x17c07c1f,
  91. 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006264, 0xc2404300, 0x17c07c1f,
  92. 0xa1528405, 0x1a10001f, 0x10006174, 0x82032001, 0x82231408, 0xd82018e8,
  93. 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82032001, 0xd80018c8, 0x17c07c1f,
  94. 0x1a40001f, 0x10006224, 0x1a80001f, 0x10006268, 0xc2404300, 0x17c07c1f,
  95. 0xa1530405, 0x1a10001f, 0x10006174, 0x8203a001, 0x82239408, 0xd8201b28,
  96. 0x17c07c1f, 0x1a10001f, 0x10006608, 0x8203a001, 0xd8001b08, 0x17c07c1f,
  97. 0x1a40001f, 0x10006228, 0x1a80001f, 0x1000626c, 0xc2404300, 0x17c07c1f,
  98. 0xa1538405, 0x1a10001f, 0x10006174, 0x88800008, 0x000000f0, 0x80c01402,
  99. 0x6a200003, 0x000000f0, 0x82249408, 0xd8201d28, 0x17c07c1f, 0x1a10001f,
  100. 0x10006608, 0x8204a001, 0xd8001d08, 0x17c07c1f, 0xa1548405, 0x1b80001f,
  101. 0x20000550, 0x1a10001f, 0x10006608, 0x820fa001, 0xd8003ea8, 0x17c07c1f,
  102. 0x81041401, 0xd8202044, 0x17c07c1f, 0x1a10001f, 0x10006164, 0x88800008,
  103. 0x00000f0f, 0x71207c02, 0xb1003081, 0xb10c3081, 0xd8202e64, 0x17c07c1f,
  104. 0x1a10001f, 0x10006608, 0x82042001, 0xd8002028, 0x17c07c1f, 0x81740405,
  105. 0x81001401, 0xd82023e4, 0x17c07c1f, 0xc28049c0, 0x1280041f, 0xb10c3081,
  106. 0xd82023e4, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82002001, 0xd80022a8,
  107. 0x17c07c1f, 0x1a40001f, 0x10006208, 0x1a80001f, 0x10006248, 0xc2404060,
  108. 0x17c07c1f, 0x81700405, 0xe8208000, 0x10006530, 0x00000000, 0xe8208000,
  109. 0x10006500, 0x00000000, 0xe8208000, 0x10006090, 0x00000001, 0x81009401,
  110. 0xd8202764, 0x17c07c1f, 0xc28049c0, 0x1290841f, 0xd8202764, 0x17c07c1f,
  111. 0x1a10001f, 0x10006608, 0x8200a001, 0xd8002628, 0x17c07c1f, 0x1a40001f,
  112. 0x1000620c, 0x1a80001f, 0x1000624c, 0xc2404060, 0x17c07c1f, 0x81708405,
  113. 0xe8208000, 0x10006534, 0x00000000, 0xe8208000, 0x10006504, 0x00000000,
  114. 0xe8208000, 0x10006090, 0x00000002, 0x81011401, 0xd8202ae4, 0x17c07c1f,
  115. 0xc28049c0, 0x1291041f, 0xd8202ae4, 0x17c07c1f, 0x1a10001f, 0x10006608,
  116. 0x82012001, 0xd80029a8, 0x17c07c1f, 0x1a40001f, 0x10006210, 0x1a80001f,
  117. 0x10006250, 0xc2404060, 0x17c07c1f, 0x81710405, 0xe8208000, 0x10006538,
  118. 0x00000000, 0xe8208000, 0x10006508, 0x00000000, 0xe8208000, 0x10006090,
  119. 0x00000004, 0x81019401, 0xd8202e64, 0x17c07c1f, 0xc28049c0, 0x1291841f,
  120. 0xd8202e64, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x8201a001, 0xd8002d28,
  121. 0x17c07c1f, 0x1a40001f, 0x10006214, 0x1a80001f, 0x10006254, 0xc2404060,
  122. 0x17c07c1f, 0x81718405, 0xe8208000, 0x1000653c, 0x00000000, 0xe8208000,
  123. 0x1000650c, 0x00000000, 0xe8208000, 0x10006090, 0x00000008, 0x81049401,
  124. 0xd82030a4, 0x17c07c1f, 0x1a10001f, 0x10006164, 0x88800008, 0x0000f0f0,
  125. 0x71207c02, 0xb1003081, 0xb10c3081, 0xd8203ea4, 0x17c07c1f, 0x1a10001f,
  126. 0x10006608, 0x8204a001, 0xd8003088, 0x17c07c1f, 0x81748405, 0x81021401,
  127. 0xd8203424, 0x17c07c1f, 0xc28049c0, 0x1292041f, 0xd8203424, 0x17c07c1f,
  128. 0x1a10001f, 0x10006608, 0x82022001, 0xd80032e8, 0x17c07c1f, 0x1a40001f,
  129. 0x1000621c, 0x1a80001f, 0x10006260, 0xc2404060, 0x17c07c1f, 0x81720405,
  130. 0xe8208000, 0x10006540, 0x00000000, 0xe8208000, 0x10006510, 0x00000000,
  131. 0xe8208000, 0x10006090, 0x00000010, 0x81029401, 0xd82037a4, 0x17c07c1f,
  132. 0xc28049c0, 0x1292841f, 0xd82037a4, 0x17c07c1f, 0x1a10001f, 0x10006608,
  133. 0x8202a001, 0xd8003668, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f,
  134. 0x10006264, 0xc2404060, 0x17c07c1f, 0x81728405, 0xe8208000, 0x10006544,
  135. 0x00000000, 0xe8208000, 0x10006514, 0x00000000, 0xe8208000, 0x10006090,
  136. 0x00000020, 0x81031401, 0xd8203b24, 0x17c07c1f, 0xc28049c0, 0x1293041f,
  137. 0xd8203b24, 0x17c07c1f, 0x1a10001f, 0x10006608, 0x82032001, 0xd80039e8,
  138. 0x17c07c1f, 0x1a40001f, 0x10006224, 0x1a80001f, 0x10006268, 0xc2404060,
  139. 0x17c07c1f, 0x81730405, 0xe8208000, 0x10006548, 0x00000000, 0xe8208000,
  140. 0x10006518, 0x00000000, 0xe8208000, 0x10006090, 0x00000040, 0x81039401,
  141. 0xd8203ea4, 0x17c07c1f, 0xc28049c0, 0x1293841f, 0xd8203ea4, 0x17c07c1f,
  142. 0x1a10001f, 0x10006608, 0x8203a001, 0xd8003d68, 0x17c07c1f, 0x1a40001f,
  143. 0x10006228, 0x1a80001f, 0x1000626c, 0xc2404060, 0x17c07c1f, 0x81738405,
  144. 0xe8208000, 0x1000654c, 0x00000000, 0xe8208000, 0x1000651c, 0x00000000,
  145. 0xe8208000, 0x10006090, 0x00000080, 0xd0000100, 0x17c07c1f, 0xe8208000,
  146. 0x10006614, 0x00000000, 0xe8208000, 0x10006608, 0x00000000, 0x1940001f,
  147. 0xaa55aa55, 0x1b80001f, 0x00001000, 0xf0000000, 0x17c07c1f, 0x1212841f,
  148. 0xe2e00036, 0x17c07c1f, 0x17c07c1f, 0xe2e0003e, 0x1380201f, 0xe2e0003c,
  149. 0xe2a00000, 0x18b0000a, 0x17c07c1f, 0x81040801, 0xd8004164, 0x17c07c1f,
  150. 0xe2e0007c, 0x1b80001f, 0x20000007, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d,
  151. 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xe2a00001,
  152. 0x18b0000a, 0x17c07c1f, 0x81040801, 0xd8204384, 0x17c07c1f, 0xe2e0002e,
  153. 0xe2e0003e, 0xe2e00032, 0xf0000000, 0x17c07c1f, 0x18f00002, 0x17c07c1f,
  154. 0xa0d98403, 0xe0800003, 0x18f00002, 0x17c07c1f, 0x81090c01, 0xd8204544,
  155. 0x17c07c1f, 0x80f98403, 0xe0800003, 0x18f00009, 0x17c07c1f, 0xa0d20403,
  156. 0xe2400003, 0x1a10001f, 0x10006174, 0x82002808, 0xd82046a8, 0x17c07c1f,
  157. 0x1880001f, 0x10001220, 0x18d0001f, 0x10001220, 0xa0d4a803, 0xe0800003,
  158. 0x1a10001f, 0x10001228, 0x8214a808, 0xd8204808, 0x17c07c1f, 0x1880001f,
  159. 0x10200684, 0x18d0001f, 0x10200684, 0xa0ca2803, 0xa0c92803, 0xe0800003,
  160. 0xf0000000, 0x17c07c1f, 0x1a10001f, 0x10006164, 0x81002808, 0xb1142888,
  161. 0xb1003081, 0xf0000000, 0x17c07c1f
  162. };
  163. static struct pcm_desc mcdi_pcm = {
  164. .version = "pcm_mcdi_ddrdfs_v6.1_20150629",
  165. .base = mcdi_binary,
  166. .size = 597,
  167. .sess = 1,
  168. .replace = 1,
  169. .addr_2nd = 0,
  170. };
  171. struct spm_lp_scen __spm_mcdi = {
  172. .pcmdesc = &mcdi_pcm,
  173. .pwrctrl = &mcdi_ctrl,
  174. };
  175. static unsigned int spm_mcdi_lock; /* offload MCDI */
  176. static bool SPM_MCDI_isKICK;
  177. #if SPM_AEE_RR_REC
  178. unsigned int *p_is_mcdi_wfi;
  179. #endif
  180. DEFINE_SPINLOCK(__spm_mcdi_lock);
  181. DEFINE_SPINLOCK(__mcdi_lock);
  182. #if (MCDI_DVT_IPI)
  183. unsigned int core0_IPI_issue_count = 0;
  184. u8 mcdi_enter = 0;
  185. int cpu0_enter_forLoop = 0;
  186. static void empty_function(void *info)
  187. {
  188. unsigned long flags;
  189. int cpu = smp_processor_id();
  190. spin_lock_irqsave(&__mcdi_lock, flags);
  191. mcdi_enter &= ~(1 << cpu);
  192. spin_unlock_irqrestore(&__mcdi_lock, flags);
  193. mdelay(1);
  194. spm_idle_dbg("core %x ipi received, core IPI command count: %d\n",
  195. cpu, core0_IPI_issue_count);
  196. }
  197. #endif
  198. unsigned int g_SPM_MCDI_Abnormal_WakeUp = 0;
  199. unsigned int g_pre_SPM_MCDI_Abnormal_WakeUp = 0;
  200. bool go_to_mcidle(int cpu)
  201. {
  202. bool ret = 0;
  203. #if (MCDI_DVT_IPI)
  204. while (1) {
  205. if (cpu == 0) {
  206. /* make sure cpu0 enter for loop first */
  207. cpu0_enter_forLoop = 1;
  208. /*check except core0 Standby WFI */
  209. if ((spm_read(CPU_IDLE_STA) & 0xfe) != 0x0) {
  210. mdelay(1);
  211. smp_call_function(empty_function, NULL, 0);
  212. spm_idle_dbg("core0 IPI\n");
  213. core0_IPI_issue_count++;
  214. }
  215. } else {
  216. if (cpu0_enter_forLoop) {
  217. if (spm_mcdi_wfi(cpu) == 1) {
  218. mdelay(1);
  219. spm_idle_dbg("CPU %d awake\n", cpu);
  220. ret = 1;
  221. } else
  222. return false;
  223. mdelay(1);
  224. } else
  225. return false;
  226. }
  227. }
  228. #elif (MCDI_DVT_CPUxGPT)
  229. while (1) {
  230. if (cpu != 0) {
  231. if (spm_mcdi_wfi(cpu) == 1) {
  232. mdelay(1);
  233. spm_idle_dbg("CPU %d awake\n", cpu);
  234. ret = 1;
  235. } else
  236. return false;
  237. }
  238. }
  239. #else
  240. if (spm_mcdi_wfi(cpu) == 1)
  241. ret = 1;
  242. if (g_SPM_MCDI_Abnormal_WakeUp != g_pre_SPM_MCDI_Abnormal_WakeUp) {
  243. spm_idle_dbg("SPM-MCDI Abnormal %x\n", g_SPM_MCDI_Abnormal_WakeUp);
  244. g_pre_SPM_MCDI_Abnormal_WakeUp = g_SPM_MCDI_Abnormal_WakeUp;
  245. }
  246. #endif
  247. return ret;
  248. }
  249. static void spm_mcdi_cpu_wake_up_event(bool wake_up_event, bool disable_dormant_power)
  250. {
  251. /* Use DUMMY1_PWR_CON[1] to decide if offload MCDI firmware */
  252. if (((spm_read(SPM_CPU_WAKEUP_EVENT) & 0x1) == 1)
  253. && ((spm_read(DUMMY1_PWR_CON) & 0x1) == 0)) {
  254. spm_idle_ver("spm_mcdi_cpu_wake_up_event: SPM_CPU_WAKEUP_EVENT:%x, DUMMY1_PWR_CON %x",
  255. spm_read(SPM_CPU_WAKEUP_EVENT), spm_read(DUMMY1_PWR_CON));
  256. return;
  257. }
  258. /* Inform SPM that CPU wants to program CPU_WAKEUP_EVENT and DISABLE_CPU_DROM */
  259. spm_write(SPM_SCP_MAILBOX, 0xbeefbeef);
  260. /* Wait SPM's response, can't use sleep api */
  261. while (spm_read(SPM_SCP_MAILBOX) != 0xdeaddead)
  262. ;
  263. if (disable_dormant_power) {
  264. spm_write(DUMMY1_PWR_CON, spm_read(DUMMY1_PWR_CON) | 0x1);
  265. while (spm_read(DUMMY1_PWR_CON) != (spm_read(DUMMY1_PWR_CON) | 0x1))
  266. ;
  267. } else {
  268. spm_write(DUMMY1_PWR_CON, spm_read(DUMMY1_PWR_CON) & ~0x1);
  269. while (spm_read(DUMMY1_PWR_CON) != (spm_read(DUMMY1_PWR_CON) & ~0x1))
  270. ;
  271. }
  272. spm_write(SPM_CPU_WAKEUP_EVENT, wake_up_event);
  273. while (spm_read(SPM_CPU_WAKEUP_EVENT) != wake_up_event)
  274. ;
  275. /* Inform SPM to see updated setting */
  276. spm_write(SPM_SCP_MAILBOX, 0xabcdabcd);
  277. while (spm_read(SPM_SCP_MAILBOX) != 0x12345678)
  278. ;
  279. /* END OF sequence */
  280. spm_write(SPM_SCP_MAILBOX, 0x0);
  281. }
  282. void spm_go_to_mcdi(u32 spm_flags, u32 spm_data)
  283. {
  284. unsigned long flags;
  285. struct pcm_desc *pcmdesc = __spm_mcdi.pcmdesc;
  286. struct pwr_ctrl *pwrctrl = __spm_mcdi.pwrctrl;
  287. spin_lock_irqsave(&__spm_mcdi_lock, flags);
  288. if (SPM_MCDI_isKICK != 0) {
  289. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  290. return;
  291. }
  292. set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
  293. #if SPM_AEE_RR_REC
  294. *p_is_mcdi_wfi = 0;
  295. #endif
  296. __spm_reset_and_init_pcm(pcmdesc);
  297. __spm_kick_im_to_fetch(pcmdesc);
  298. __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcore_dvfs.pwrctrl);
  299. __spm_set_power_control(pwrctrl);
  300. __spm_set_wakeup_event(pwrctrl);
  301. __spm_kick_pcm_to_run(pwrctrl);
  302. SPM_MCDI_isKICK = 1;
  303. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  304. spm_idle_ver("spm_go_to_mcdi()\n");
  305. }
  306. void spm_leave_MCDI(void)
  307. {
  308. unsigned long flags;
  309. spin_lock_irqsave(&__spm_mcdi_lock, flags);
  310. if (SPM_MCDI_isKICK == 0) {
  311. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  312. return;
  313. }
  314. SPM_MCDI_isKICK = 0;
  315. spm_mcdi_cpu_wake_up_event(1, 1);
  316. #if SPM_AEE_RR_REC
  317. u32 spm_counter = 0;
  318. while (*p_is_mcdi_wfi != 0) { /* don't use sleep command(wfi/wfe) */
  319. if (spm_counter >= SPM_MCDI_CORE_MAX_EXIT_TIME) {
  320. spm_idle_ver("spm_leave_MCDI: g_is_mcdi_wfi:%x\n", *p_is_mcdi_wfi);
  321. spm_counter = 0;
  322. }
  323. spm_counter++;
  324. }
  325. #endif
  326. /*offload MCDI F/W */
  327. spm_mcdi_cpu_wake_up_event(1, 0);
  328. __spm_clean_after_wakeup();
  329. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  330. spm_idle_ver("spm_leave_MCDI : OK\n");
  331. }
  332. static void spm_mcdi_wfi_sel_enter(int core_id)
  333. {
  334. int core_id_val = core_id;
  335. /*SPM WFI Select by core number */
  336. switch (core_id_val) {
  337. case 0:
  338. spm_write(MP0_CPU0_IRQ_MASK, 1);
  339. spm_write(MP0_CPU0_WFI_EN, 1);
  340. break;
  341. case 1:
  342. spm_write(MP0_CPU1_IRQ_MASK, 1);
  343. spm_write(MP0_CPU1_WFI_EN, 1);
  344. break;
  345. case 2:
  346. spm_write(MP0_CPU2_IRQ_MASK, 1);
  347. spm_write(MP0_CPU2_WFI_EN, 1);
  348. break;
  349. case 3:
  350. spm_write(MP0_CPU3_IRQ_MASK, 1);
  351. spm_write(MP0_CPU3_WFI_EN, 1);
  352. break;
  353. case 4:
  354. spm_write(MP1_CPU0_IRQ_MASK, 1);
  355. spm_write(MP1_CPU0_WFI_EN, 1);
  356. break;
  357. case 5:
  358. spm_write(MP1_CPU1_IRQ_MASK, 1);
  359. spm_write(MP1_CPU1_WFI_EN, 1);
  360. break;
  361. case 6:
  362. spm_write(MP1_CPU2_IRQ_MASK, 1);
  363. spm_write(MP1_CPU2_WFI_EN, 1);
  364. break;
  365. case 7:
  366. spm_write(MP1_CPU3_IRQ_MASK, 1);
  367. spm_write(MP1_CPU3_WFI_EN, 1);
  368. break;
  369. default:
  370. break;
  371. }
  372. }
  373. static void spm_mcdi_wfi_sel_leave(int core_id)
  374. {
  375. int core_id_val = core_id;
  376. /*SPM WFI Select by core number */
  377. switch (core_id_val) {
  378. case 0:
  379. spm_write(MP0_CPU0_WFI_EN, 0);
  380. spm_write(MP0_CPU0_IRQ_MASK, 0);
  381. break;
  382. case 1:
  383. spm_write(MP0_CPU1_WFI_EN, 0);
  384. spm_write(MP0_CPU1_IRQ_MASK, 0);
  385. break;
  386. case 2:
  387. spm_write(MP0_CPU2_WFI_EN, 0);
  388. spm_write(MP0_CPU2_IRQ_MASK, 0);
  389. break;
  390. case 3:
  391. spm_write(MP0_CPU3_WFI_EN, 0);
  392. spm_write(MP0_CPU3_IRQ_MASK, 0);
  393. break;
  394. case 4:
  395. spm_write(MP1_CPU0_WFI_EN, 0);
  396. spm_write(MP1_CPU0_IRQ_MASK, 0);
  397. break;
  398. case 5:
  399. spm_write(MP1_CPU1_WFI_EN, 0);
  400. spm_write(MP1_CPU1_IRQ_MASK, 0);
  401. break;
  402. case 6:
  403. spm_write(MP1_CPU2_WFI_EN, 0);
  404. spm_write(MP1_CPU2_IRQ_MASK, 0);
  405. break;
  406. case 7:
  407. spm_write(MP1_CPU3_WFI_EN, 0);
  408. spm_write(MP1_CPU3_IRQ_MASK, 0);
  409. break;
  410. default:
  411. break;
  412. }
  413. }
  414. bool spm_is_cpu_irq_occur(int core_id)
  415. {
  416. bool ret = 0;
  417. /* check COREn IRQ */
  418. if (spm_read(SPM_WAKEUP_MISC) & (1 << (core_id)))
  419. ret = 1;
  420. /* check COREn FIQ */
  421. if (spm_read(SPM_WAKEUP_MISC) & (1 << (core_id + 8)))
  422. ret = 1;
  423. #if (MCDI_DVT_IPI)
  424. if (ret == 1)
  425. spm_idle_ver("spm_read(SPM_WAKEUP_MISC)=0x%x\n", spm_read(SPM_WAKEUP_MISC));
  426. #endif
  427. return ret;
  428. }
  429. bool spm_mcdi_can_enter(void)
  430. {
  431. bool ret = 1;
  432. /*check is MCDI kick */
  433. if ((SPM_MCDI_isKICK == 0) || ((spm_read(SPM_CPU_WAKEUP_EVENT) & 0x1) == 1)
  434. || ((spm_read(SPM_SW_RSV_3) & 0x1) == 1))
  435. ret = 0;
  436. #ifndef CONFIG_CPU_ISOLATION
  437. if (atomic_read(&is_in_hotplug) >= 1)
  438. ret = 0;
  439. #endif
  440. #if (MCDI_DVT_IPI)
  441. if (ret == 0) {
  442. spm_idle_ver("SPM_MCDI_isKICK=%d\n", SPM_MCDI_isKICK);
  443. spm_idle_ver("spm_read(SPM_CPU_WAKEUP_EVENT)=%d\n", spm_read(SPM_CPU_WAKEUP_EVENT));
  444. spm_idle_ver("spm_read(MCU_PWR_CON)=%d\n", spm_read(MCU_PWR_CON));
  445. }
  446. #endif
  447. return ret;
  448. }
  449. bool spm_mcdi_wfi(int core_id)
  450. {
  451. bool ret = 0;
  452. unsigned long flags;
  453. int dmnt_ret = 0;
  454. int mcdi_core_id = core_id;
  455. #if SPM_AEE_RR_REC
  456. spin_lock_irqsave(&__spm_lock, flags);
  457. *p_is_mcdi_wfi = (*p_is_mcdi_wfi | (1 << core_id));
  458. spin_unlock_irqrestore(&__spm_lock, flags);
  459. #endif
  460. if (spm_mcdi_can_enter() == 0) {
  461. #if SPM_AEE_RR_REC
  462. spin_lock_irqsave(&__spm_lock, flags);
  463. *p_is_mcdi_wfi = (*p_is_mcdi_wfi & ~(1 << core_id));
  464. spin_unlock_irqrestore(&__spm_lock, flags);
  465. #endif
  466. return ret;
  467. }
  468. if ((spm_read(SPM_SW_RSV_0) & (1 << mcdi_core_id)) == 0) {
  469. if (spm_is_cpu_irq_occur(mcdi_core_id) == 0) {
  470. /*core wfi_sel & cpu mask */
  471. spm_mcdi_wfi_sel_enter(core_id);
  472. /*sync core1~n local timer to XGPT */
  473. mcidle_before_wfi(core_id);
  474. dmnt_ret = mt_cpu_dormant_interruptible(CPU_MCDI_MODE);
  475. if (dmnt_ret == MT_CPU_DORMANT_RESET) {
  476. ret = 1;
  477. /*check if MCDI abort by unkonw IRQ */
  478. while ((spm_read(SPM_IRQ_STA) & (1 << (mcdi_core_id + 4))) == 0) {
  479. spin_lock_irqsave(&__spm_lock, flags);
  480. g_SPM_MCDI_Abnormal_WakeUp |= (1 << core_id);
  481. spin_unlock_irqrestore(&__spm_lock, flags);
  482. }
  483. } else if (dmnt_ret == MT_CPU_DORMANT_ABORT)
  484. ret = 0;
  485. /*clear core wfi_sel & cpu unmask */
  486. spm_mcdi_wfi_sel_leave(core_id);
  487. mcidle_after_wfi(core_id);
  488. spin_lock_irqsave(&__spm_lock, flags);
  489. /*Clear SPM SW IRQ */
  490. spm_write(SPM_SW_INT_CLEAR, (0x1 << core_id)); /* PCM_SWINT_3 */
  491. spin_unlock_irqrestore(&__spm_lock, flags);
  492. }
  493. } else if (spm_is_cpu_irq_occur(core_id) == 0) {
  494. /*core wfi_sel & cpu mask */
  495. spm_mcdi_wfi_sel_enter(core_id);
  496. /*sync core1~n local timer to XGPT */
  497. mcidle_before_wfi(core_id);
  498. wfi_with_sync();
  499. mcidle_after_wfi(core_id);
  500. /*clear core wfi_sel & cpu unmask */
  501. spm_mcdi_wfi_sel_leave(core_id);
  502. /*Clear SPM SW IRQ */
  503. spm_write(SPM_SW_INT_CLEAR, (0x1 << core_id)); /* PCM_SWINT_3 */
  504. ret = 1;
  505. }
  506. #if SPM_AEE_RR_REC
  507. spin_lock_irqsave(&__spm_lock, flags);
  508. *p_is_mcdi_wfi = (*p_is_mcdi_wfi & ~(1 << core_id));
  509. spin_unlock_irqrestore(&__spm_lock, flags);
  510. #endif
  511. return ret;
  512. }
  513. void spm_set_mcdi_pcm_ver(void)
  514. {
  515. CHIP_SW_VER ver = mt_get_chip_sw_ver();
  516. /* Get Different FW */
  517. }
  518. void __init spm_mcdi_init(void)
  519. {
  520. #if SPM_AEE_RR_REC
  521. p_is_mcdi_wfi = aee_rr_rec_mcdi_wfi();
  522. *p_is_mcdi_wfi = 0;
  523. #endif
  524. spm_set_mcdi_pcm_ver();
  525. }
  526. static void __exit spm_mcdi_exit(void)
  527. {
  528. spm_idle_ver("Exit SPM-MCDI\n\r");
  529. }
  530. #ifndef CONFIG_CPU_ISOLATION
  531. void spm_mcdi_wakeup_all_cores(void)
  532. {
  533. unsigned long flags;
  534. spin_lock_irqsave(&__spm_mcdi_lock, flags);
  535. if (SPM_MCDI_isKICK == 0) {
  536. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  537. return;
  538. }
  539. /* trigger cpu wake up event */
  540. spm_mcdi_cpu_wake_up_event(1, 1);
  541. /* trigger cpu wake up event */
  542. spm_mcdi_cpu_wake_up_event(0, 0);
  543. spin_unlock_irqrestore(&__spm_mcdi_lock, flags);
  544. }
  545. #endif
  546. static void spm_mcdi_enable(enum spm_mcdi_lock_id id, int mcdi_en)
  547. {
  548. unsigned long flags;
  549. if (mcdi_en) {
  550. spin_lock_irqsave(&__spm_lock, flags);
  551. spm_mcdi_lock &= ~(1 << id);
  552. spin_unlock_irqrestore(&__spm_lock, flags);
  553. } else {
  554. spin_lock_irqsave(&__spm_lock, flags);
  555. spm_mcdi_lock |= (1 << id);
  556. spin_unlock_irqrestore(&__spm_lock, flags);
  557. }
  558. }
  559. static unsigned int spm_mcdi_is_disable(void)
  560. {
  561. return spm_mcdi_lock;
  562. }
  563. void spm_mcdi_switch_on_off(enum spm_mcdi_lock_id id, int mcdi_en)
  564. {
  565. spm_mcdi_enable(id, mcdi_en);
  566. if (mcdi_en) {
  567. if (spm_mcdi_is_disable())
  568. return;
  569. spm_go_to_mcdi(0, 0);
  570. } else
  571. spm_leave_MCDI();
  572. }
  573. MODULE_DESCRIPTION("SPM-MCDI Driver v0.1");