mt_cpu_pm_cpc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * Copyright (c) 2021, MediaTek Inc. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <string.h>
  7. #include <drivers/delay_timer.h>
  8. #include <mt_cpu_pm_cpc.h>
  9. #include <mt_timer.h>
  10. struct mtk_cpc_dev {
  11. int auto_off;
  12. unsigned int auto_thres_tick;
  13. };
  14. static struct mtk_cpc_dev cpc;
  15. static int mtk_cpc_last_core_prot(uint32_t prot_req,
  16. uint32_t resp_reg, uint32_t resp_ofs)
  17. {
  18. uint32_t sta, retry;
  19. retry = 0U;
  20. while (retry++ < RETRY_CNT_MAX) {
  21. mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
  22. udelay(1U);
  23. sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
  24. if (sta == PROT_SUCCESS) {
  25. return CPC_SUCCESS;
  26. } else if (sta == PROT_GIVEUP) {
  27. return CPC_ERR_FAIL;
  28. }
  29. }
  30. return CPC_ERR_TIMEOUT;
  31. }
  32. int mtk_cpu_pm_mcusys_prot_aquire(void)
  33. {
  34. return mtk_cpc_last_core_prot(
  35. MCUSYS_PROT_SET,
  36. CPC_MCUSYS_LAST_CORE_RESP,
  37. MCUSYS_RESP_OFS);
  38. }
  39. void mtk_cpu_pm_mcusys_prot_release(void)
  40. {
  41. mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
  42. }
  43. int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
  44. {
  45. return mtk_cpc_last_core_prot(
  46. CPUSYS_PROT_SET,
  47. CPC_MCUSYS_MP_LAST_CORE_RESP,
  48. CPUSYS_RESP_OFS);
  49. }
  50. void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
  51. {
  52. mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
  53. }
  54. static void mtk_cpc_cluster_cnt_backup(void)
  55. {
  56. uint32_t backup_cnt;
  57. uint32_t curr_cnt;
  58. uint32_t cnt_mask = GENMASK(14, 0);
  59. uint32_t clr_mask = GENMASK(1, 0);
  60. /* Single Cluster */
  61. backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
  62. curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
  63. /* Get off count if dormant count is 0 */
  64. if ((curr_cnt & cnt_mask) == 0U) {
  65. curr_cnt = (curr_cnt >> 16) & cnt_mask;
  66. } else {
  67. curr_cnt = curr_cnt & cnt_mask;
  68. }
  69. mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
  70. mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
  71. }
  72. static inline void mtk_cpc_mcusys_off_en(void)
  73. {
  74. mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
  75. }
  76. static inline void mtk_cpc_mcusys_off_dis(void)
  77. {
  78. mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
  79. }
  80. void mtk_cpc_mcusys_off_reflect(void)
  81. {
  82. mtk_cpc_mcusys_off_dis();
  83. mtk_cpu_pm_mcusys_prot_release();
  84. }
  85. int mtk_cpc_mcusys_off_prepare(void)
  86. {
  87. if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
  88. return CPC_ERR_FAIL;
  89. }
  90. mtk_cpc_cluster_cnt_backup();
  91. mtk_cpc_mcusys_off_en();
  92. return CPC_SUCCESS;
  93. }
  94. void mtk_cpc_core_on_hint_set(unsigned int cpu)
  95. {
  96. mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
  97. }
  98. void mtk_cpc_core_on_hint_clr(unsigned int cpu)
  99. {
  100. mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
  101. }
  102. static void mtk_cpc_dump_timestamp(void)
  103. {
  104. uint32_t id;
  105. for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
  106. mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
  107. memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
  108. (const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
  109. CPC_TRACE_SIZE);
  110. }
  111. }
  112. void mtk_cpc_time_sync(void)
  113. {
  114. uint64_t kt;
  115. uint32_t systime_l, systime_h;
  116. kt = sched_clock();
  117. systime_l = mmio_read_32(CNTSYS_L_REG);
  118. systime_h = mmio_read_32(CNTSYS_H_REG);
  119. /* sync kernel timer to cpc */
  120. mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
  121. mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
  122. /* sync system timer to cpc */
  123. mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
  124. mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
  125. }
  126. static void mtk_cpc_config(uint32_t cfg, uint32_t data)
  127. {
  128. uint32_t val;
  129. uint32_t reg = 0U;
  130. switch (cfg) {
  131. case CPC_SMC_CONFIG_PROF:
  132. reg = CPC_MCUSYS_CPC_DBG_SETTING;
  133. val = mmio_read_32(reg);
  134. val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
  135. break;
  136. case CPC_SMC_CONFIG_AUTO_OFF:
  137. reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
  138. val = mmio_read_32(reg);
  139. if (data != 0U) {
  140. val |= CPC_AUTO_OFF_EN;
  141. cpc.auto_off = 1;
  142. } else {
  143. val &= ~CPC_AUTO_OFF_EN;
  144. cpc.auto_off = 0;
  145. }
  146. break;
  147. case CPC_SMC_CONFIG_AUTO_OFF_THRES:
  148. reg = CPC_MCUSYS_CPC_OFF_THRES;
  149. cpc.auto_thres_tick = us_to_ticks(data);
  150. val = cpc.auto_thres_tick;
  151. break;
  152. case CPC_SMC_CONFIG_CNT_CLR:
  153. reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
  154. val = GENMASK(1, 0); /* clr_mask */
  155. break;
  156. case CPC_SMC_CONFIG_TIME_SYNC:
  157. mtk_cpc_time_sync();
  158. break;
  159. default:
  160. break;
  161. }
  162. if (reg != 0U) {
  163. mmio_write_32(reg, val);
  164. }
  165. }
  166. static uint32_t mtk_cpc_read_config(uint32_t cfg)
  167. {
  168. uint32_t res = 0U;
  169. switch (cfg) {
  170. case CPC_SMC_CONFIG_PROF:
  171. res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
  172. 1U : 0U;
  173. break;
  174. case CPC_SMC_CONFIG_AUTO_OFF:
  175. res = cpc.auto_off;
  176. break;
  177. case CPC_SMC_CONFIG_AUTO_OFF_THRES:
  178. res = ticks_to_us(cpc.auto_thres_tick);
  179. break;
  180. case CPC_SMC_CONFIG_CNT_CLR:
  181. break;
  182. default:
  183. break;
  184. }
  185. return res;
  186. }
  187. uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
  188. {
  189. uint64_t res = 0ULL;
  190. switch (act) {
  191. case CPC_SMC_EVENT_DUMP_TRACE_DATA:
  192. mtk_cpc_dump_timestamp();
  193. break;
  194. case CPC_SMC_EVENT_GIC_DPG_SET:
  195. /* isolated_status = x2; */
  196. break;
  197. case CPC_SMC_EVENT_CPC_CONFIG:
  198. mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
  199. break;
  200. case CPC_SMC_EVENT_READ_CONFIG:
  201. res = mtk_cpc_read_config((uint32_t)arg1);
  202. break;
  203. default:
  204. break;
  205. }
  206. return res;
  207. }
  208. void mtk_cpc_init(void)
  209. {
  210. mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
  211. mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
  212. | CPC_DBG_EN
  213. | CPC_CALC_EN);
  214. cpc.auto_off = 1;
  215. cpc.auto_thres_tick = us_to_ticks(8000);
  216. mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
  217. mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
  218. | CPC_OFF_PRE_EN
  219. | (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
  220. mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
  221. }