clint.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* Copyright 2018 Canaan Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #include <stddef.h>
  16. #include <stdint.h>
  17. #include "clint.h"
  18. #include "encoding.h"
  19. #include "sysctl.h"
  20. volatile clint_t *const clint = (volatile clint_t *)CLINT_BASE_ADDR;
  21. static clint_timer_instance_t clint_timer_instance[CLINT_NUM_CORES];
  22. static clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_CORES];
  23. uint64_t clint_get_time(void)
  24. {
  25. /* No difference on cores */
  26. return clint->mtime;
  27. }
  28. int clint_timer_init(void)
  29. {
  30. /* Read core id */
  31. unsigned long core_id = current_coreid();
  32. /* Clear the Machine-Timer bit in MIE */
  33. clear_csr(mie, MIP_MTIP);
  34. /* Fill core's instance with original data */
  35. /* clang-format off */
  36. clint_timer_instance[core_id] = (const clint_timer_instance_t)
  37. {
  38. .interval = 0,
  39. .cycles = 0,
  40. .single_shot = 0,
  41. .callback = NULL,
  42. .ctx = NULL,
  43. };
  44. /* clang-format on */
  45. return 0;
  46. }
  47. int clint_timer_stop(void)
  48. {
  49. /* Clear the Machine-Timer bit in MIE */
  50. clear_csr(mie, MIP_MTIP);
  51. return 0;
  52. }
  53. uint64_t clint_timer_get_freq(void)
  54. {
  55. /* The clock is divided by CLINT_CLOCK_DIV */
  56. return sysctl_clock_get_freq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV;
  57. }
  58. int clint_timer_start(uint64_t interval, int single_shot)
  59. {
  60. /* Read core id */
  61. unsigned long core_id = current_coreid();
  62. /* Set timer interval */
  63. if(clint_timer_set_interval(interval) != 0)
  64. return -1;
  65. /* Set timer single shot */
  66. if(clint_timer_set_single_shot(single_shot) != 0)
  67. return -1;
  68. /* Check settings to prevent interval is 0 */
  69. if(clint_timer_instance[core_id].interval == 0)
  70. return -1;
  71. /* Check settings to prevent cycles is 0 */
  72. if(clint_timer_instance[core_id].cycles == 0)
  73. return -1;
  74. /* Add cycle interval to mtimecmp */
  75. uint64_t now = clint->mtime;
  76. uint64_t then = now + clint_timer_instance[core_id].cycles;
  77. /* Set mtimecmp by core id */
  78. clint->mtimecmp[core_id] = then;
  79. /* Enable interrupts in general */
  80. set_csr(mstatus, MSTATUS_MIE);
  81. /* Enable the Machine-Timer bit in MIE */
  82. set_csr(mie, MIP_MTIP);
  83. return 0;
  84. }
  85. uint64_t clint_timer_get_interval(void)
  86. {
  87. /* Read core id */
  88. unsigned long core_id = current_coreid();
  89. return clint_timer_instance[core_id].interval;
  90. }
  91. int clint_timer_set_interval(uint64_t interval)
  92. {
  93. /* Read core id */
  94. unsigned long core_id = current_coreid();
  95. /* Check parameter */
  96. if(interval == 0)
  97. return -1;
  98. /* Assign user interval with Millisecond(ms) */
  99. clint_timer_instance[core_id].interval = interval;
  100. /* Convert interval to cycles */
  101. clint_timer_instance[core_id].cycles = interval * clint_timer_get_freq() / 1000ULL;
  102. return 0;
  103. }
  104. int clint_timer_get_single_shot(void)
  105. {
  106. /* Read core id */
  107. unsigned long core_id = current_coreid();
  108. /* Get single shot mode by core id */
  109. return clint_timer_instance[core_id].single_shot;
  110. }
  111. int clint_timer_set_single_shot(int single_shot)
  112. {
  113. /* Read core id */
  114. unsigned long core_id = current_coreid();
  115. /* Set single shot mode by core id */
  116. clint_timer_instance[core_id].single_shot = single_shot;
  117. return 0;
  118. }
  119. int clint_timer_register(clint_timer_callback_t callback, void *ctx)
  120. {
  121. /* Read core id */
  122. unsigned long core_id = current_coreid();
  123. /* Set user callback function */
  124. clint_timer_instance[core_id].callback = callback;
  125. /* Assign user context */
  126. clint_timer_instance[core_id].ctx = ctx;
  127. return 0;
  128. }
  129. int clint_timer_unregister(void)
  130. {
  131. /* Just assign NULL to user callback function and context */
  132. return clint_timer_register(NULL, NULL);
  133. }
  134. int clint_ipi_init(void)
  135. {
  136. /* Read core id */
  137. unsigned long core_id = current_coreid();
  138. /* Clear the Machine-Software bit in MIE */
  139. clear_csr(mie, MIP_MSIP);
  140. /* Fill core's instance with original data */
  141. /* clang-format off */
  142. clint_ipi_instance[core_id] = (const clint_ipi_instance_t){
  143. .callback = NULL,
  144. .ctx = NULL,
  145. };
  146. /* clang-format on */
  147. return 0;
  148. }
  149. int clint_ipi_enable(void)
  150. {
  151. /* Enable interrupts in general */
  152. set_csr(mstatus, MSTATUS_MIE);
  153. /* Set the Machine-Software bit in MIE */
  154. set_csr(mie, MIP_MSIP);
  155. return 0;
  156. }
  157. int clint_ipi_disable(void)
  158. {
  159. /* Clear the Machine-Software bit in MIE */
  160. clear_csr(mie, MIP_MSIP);
  161. return 0;
  162. }
  163. int clint_ipi_send(size_t core_id)
  164. {
  165. if(core_id >= CLINT_NUM_CORES)
  166. return -1;
  167. clint->msip[core_id].msip = 1;
  168. return 0;
  169. }
  170. int clint_ipi_clear(size_t core_id)
  171. {
  172. if(core_id >= CLINT_NUM_CORES)
  173. return -1;
  174. if(clint->msip[core_id].msip)
  175. {
  176. clint->msip[core_id].msip = 0;
  177. return 1;
  178. }
  179. return 0;
  180. }
  181. int clint_ipi_register(clint_ipi_callback_t callback, void *ctx)
  182. {
  183. /* Read core id */
  184. unsigned long core_id = current_coreid();
  185. /* Set user callback function */
  186. clint_ipi_instance[core_id].callback = callback;
  187. /* Assign user context */
  188. clint_ipi_instance[core_id].ctx = ctx;
  189. return 0;
  190. }
  191. int clint_ipi_unregister(void)
  192. {
  193. /* Just assign NULL to user callback function and context */
  194. return clint_ipi_register(NULL, NULL);
  195. }
  196. uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc)
  197. {
  198. /* Read core id */
  199. uint64_t core_id = current_coreid();
  200. uint64_t ie_flag = read_csr(mie);
  201. clear_csr(mie, MIP_MTIP | MIP_MSIP);
  202. set_csr(mstatus, MSTATUS_MIE);
  203. if(clint_timer_instance[core_id].callback != NULL)
  204. clint_timer_instance[core_id].callback(
  205. clint_timer_instance[core_id].ctx);
  206. clear_csr(mstatus, MSTATUS_MIE);
  207. set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
  208. write_csr(mie, ie_flag);
  209. /* If not single shot and cycle interval is not 0, repeat this timer */
  210. if(!clint_timer_instance[core_id].single_shot && clint_timer_instance[core_id].cycles != 0)
  211. {
  212. /* Set mtimecmp by core id */
  213. clint->mtimecmp[core_id] += clint_timer_instance[core_id].cycles;
  214. } else
  215. clear_csr(mie, MIP_MTIP);
  216. return epc;
  217. }
  218. uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc)
  219. {
  220. /* Read core id */
  221. uint64_t core_id = current_coreid();
  222. /* Clear the Machine-Software bit in MIE to prevent call again */
  223. clear_csr(mie, MIP_MSIP);
  224. set_csr(mstatus, MSTATUS_MIE);
  225. /* Clear ipi flag */
  226. clint_ipi_clear(core_id);
  227. if(clint_ipi_instance[core_id].callback != NULL)
  228. clint_ipi_instance[core_id].callback(clint_ipi_instance[core_id].ctx);
  229. clear_csr(mstatus, MSTATUS_MIE);
  230. set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
  231. set_csr(mie, MIP_MSIP);
  232. return epc;
  233. }