drv_hwsem.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2022-10-5 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_HWSEM)
  14. #include <rthw.h>
  15. #include "drv_hwsem.h"
  16. #include "drv_sys.h"
  17. #include "drv_common.h"
  18. #include "nu_bitutil.h"
  19. /* Private define ---------------------------------------------------------------*/
  20. enum
  21. {
  22. HWSEM_START = -1,
  23. #if defined(BSP_USING_HWSEM0)
  24. HWSEM0_IDX,
  25. #endif
  26. HWSEM_END
  27. };
  28. /* Private typedef --------------------------------------------------------------*/
  29. struct nu_mutex_priv
  30. {
  31. struct nu_mutex parent;
  32. rt_thread_t owner;
  33. uint8_t key;
  34. uint8_t hold;
  35. struct rt_completion completion;
  36. void *user_data;
  37. };
  38. typedef struct nu_mutex_priv *nu_mutex_priv_t;
  39. struct nu_hwsem
  40. {
  41. struct rt_device dev;
  42. char *name;
  43. HWSEM_T *base;
  44. IRQn_Type irqn;
  45. uint32_t rstidx;
  46. struct nu_mutex_priv mutex[evHWSEM_CNT];
  47. };
  48. typedef struct nu_hwsem *nu_hwsem_t;
  49. static struct nu_hwsem nu_hwsem_arr [] =
  50. {
  51. #if defined(BSP_USING_HWSEM0)
  52. {
  53. .name = "hwsem0",
  54. .base = HWSEM0,
  55. .irqn = HWSEM0_IRQn,
  56. .rstidx = HWSEM0_RST,
  57. },
  58. #endif
  59. }; /* nu_hwsem */
  60. /**
  61. * All HWSEM interrupt service routine
  62. */
  63. static void nu_hwsem_isr(int vector, void *param)
  64. {
  65. nu_hwsem_t psNuHwSem = (nu_hwsem_t)param;
  66. rt_int32_t irqidx;
  67. volatile uint32_t vu32Intsts = psNuHwSem->base->INTSTS_CORE;
  68. while ((irqidx = nu_ctz(vu32Intsts)) < evHWSEM_CNT)
  69. {
  70. nu_mutex_priv_t priv = (nu_mutex_priv_t)&psNuHwSem->mutex[irqidx];
  71. uint32_t u32IsrBitMask = 1 << irqidx ;
  72. HWSEM_CLR_INT_FLAG(psNuHwSem->base, irqidx);
  73. /* Unlocked, Signal waiter. */
  74. rt_completion_done(&priv->completion);
  75. /* Clear sent bit */
  76. vu32Intsts &= ~(u32IsrBitMask);
  77. }
  78. }
  79. nu_mutex_t nu_mutex_init(struct rt_device *device, E_HWSEM_ID id)
  80. {
  81. if (id < evHWSEM_CNT)
  82. {
  83. nu_hwsem_t psNuHwSem = (nu_hwsem_t)device->user_data;
  84. nu_mutex_t mutex = (nu_mutex_t)&psNuHwSem->mutex[id];
  85. nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
  86. if (!priv->owner)
  87. {
  88. priv->owner = rt_thread_self();
  89. }
  90. else
  91. {
  92. goto exit_nu_mutex_init;
  93. }
  94. return mutex;
  95. }
  96. exit_nu_mutex_init:
  97. return RT_NULL;
  98. }
  99. void nu_mutex_deinit(struct rt_device *device, E_HWSEM_ID id)
  100. {
  101. if (id < evHWSEM_CNT)
  102. {
  103. nu_hwsem_t psNuHwSem = (nu_hwsem_t)device->user_data;
  104. nu_mutex_t mutex = (nu_mutex_t)&psNuHwSem->mutex[id];
  105. nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
  106. if (priv->owner == rt_thread_self())
  107. {
  108. priv->owner = RT_NULL;
  109. }
  110. }
  111. }
  112. rt_err_t nu_mutex_take(nu_mutex_t mutex, rt_int32_t timeout)
  113. {
  114. rt_err_t ret = RT_EOK;
  115. nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
  116. nu_hwsem_t dev = (nu_hwsem_t)priv->user_data;
  117. uint8_t u8PrivKey = priv->key;
  118. #ifdef RT_USING_SMP
  119. u8PrivKey |= (rt_hw_cpu_id() << 6);
  120. #endif /* RT_USING_SMP */
  121. if (priv->owner != rt_thread_self())
  122. {
  123. return -RT_ERROR;
  124. }
  125. rt_completion_init(&priv->completion);
  126. while (1)
  127. {
  128. if (HWSEM_IS_LOCKED(dev->base, mutex->id) != HWSEM_NOLOCK)
  129. {
  130. /* LOCKED */
  131. if (HWSEM_GET_KEY(dev->base, mutex->id) != u8PrivKey)
  132. {
  133. /* Enable interrupt */
  134. HWSEM_ENABLE_INT(dev->base, mutex->id);
  135. /* owner is NOT me. */
  136. if (rt_completion_wait(&priv->completion, timeout) != RT_EOK)
  137. {
  138. ret = -RT_EBUSY;
  139. break;
  140. }
  141. else
  142. {
  143. /* Got notification, do lock. */
  144. }
  145. }
  146. else
  147. {
  148. /* owner is me. */
  149. priv->hold++;
  150. break;
  151. }
  152. }
  153. else
  154. {
  155. /* NOLOCK, To lock */
  156. HWSEM_LOCK(dev->base, mutex->id, u8PrivKey);
  157. if (HWSEM_GET_KEY(dev->base, mutex->id) == u8PrivKey)
  158. {
  159. /* owner is me. */
  160. priv->hold = 1;
  161. /* Disable interrupt */
  162. HWSEM_DISABLE_INT(dev->base, mutex->id);
  163. break;
  164. }
  165. else
  166. {
  167. /* Failed to lock, owner is not me. wait notification. */
  168. }
  169. }
  170. } //while(1)
  171. return ret;
  172. }
  173. RTM_EXPORT(nu_mutex_take);
  174. rt_err_t nu_mutex_release(nu_mutex_t mutex)
  175. {
  176. rt_err_t ret = RT_EOK;
  177. nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
  178. nu_hwsem_t dev = (nu_hwsem_t)priv->user_data;
  179. uint8_t u8PrivKey = priv->key;
  180. if (priv->owner != rt_thread_self())
  181. {
  182. return -RT_ERROR;
  183. }
  184. #ifdef RT_USING_SMP
  185. u8PrivKey |= (rt_hw_cpu_id() << 6);
  186. #endif /* RT_USING_SMP */
  187. if (HWSEM_IS_LOCKED(dev->base, mutex->id) != 0 &&
  188. HWSEM_GET_KEY(dev->base, mutex->id) == u8PrivKey)
  189. {
  190. priv->hold--;
  191. if (priv->hold == 0)
  192. {
  193. /* Unlocked */
  194. HWSEM_UNLOCK(dev->base, mutex->id, u8PrivKey);
  195. }
  196. }
  197. else
  198. {
  199. ret = -RT_ERROR;
  200. }
  201. return ret;
  202. }
  203. RTM_EXPORT(nu_mutex_release);
  204. static rt_err_t hwsem_register(struct rt_device *device, const char *name, void *user_data)
  205. {
  206. RT_ASSERT(device);
  207. device->type = RT_Device_Class_Miscellaneous;
  208. device->rx_indicate = RT_NULL;
  209. device->tx_complete = RT_NULL;
  210. #ifdef RT_USING_DEVICE_OPS
  211. device->ops = RT_NULL;
  212. #else
  213. device->init = RT_NULL;
  214. device->open = RT_NULL;
  215. device->close = RT_NULL;
  216. device->read = RT_NULL;
  217. device->write = RT_NULL;
  218. device->control = RT_NULL;
  219. #endif
  220. device->user_data = user_data;
  221. return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
  222. }
  223. /**
  224. * Hardware Sem Initialization
  225. */
  226. int rt_hw_hwsem_init(void)
  227. {
  228. int i, j;
  229. rt_err_t ret = RT_EOK;
  230. for (i = (HWSEM_START + 1); i < HWSEM_END; i++)
  231. {
  232. #if !defined(USE_MA35D1_SUBM)
  233. /* Reset this module */
  234. nu_sys_ip_reset(nu_hwsem_arr[i].rstidx);
  235. #endif
  236. for (j = 0; j < evHWSEM_CNT; j++)
  237. {
  238. nu_hwsem_arr[i].mutex[j].parent.id = (E_HWSEM_ID)j;
  239. nu_hwsem_arr[i].mutex[j].user_data = (void *)&nu_hwsem_arr[i];
  240. nu_hwsem_arr[i].mutex[j].key = (HWSEM_LOCK_BY_OWNER << 4) | j; // CoreID + SemID
  241. nu_hwsem_arr[i].mutex[j].hold = 0;
  242. nu_hwsem_arr[i].mutex[j].owner = RT_NULL;
  243. if (HWSEM_IS_LOCKED(nu_hwsem_arr[i].base, j) == HWSEM_LOCK_BY_OWNER)
  244. HWSEM_UNLOCK(nu_hwsem_arr[i].base, j, nu_hwsem_arr[i].mutex[j].key);
  245. /* Disable interrupt */
  246. HWSEM_DISABLE_INT(nu_hwsem_arr[i].base, j);
  247. }
  248. rt_hw_interrupt_install(nu_hwsem_arr[i].irqn, nu_hwsem_isr, &nu_hwsem_arr[i], nu_hwsem_arr[i].name);
  249. rt_hw_interrupt_umask(nu_hwsem_arr[i].irqn);
  250. ret = hwsem_register(&nu_hwsem_arr[i].dev, (const char *)nu_hwsem_arr[i].name, (void *)&nu_hwsem_arr[i]);
  251. RT_ASSERT(ret == RT_EOK);
  252. }
  253. return 0;
  254. }
  255. INIT_BOARD_EXPORT(rt_hw_hwsem_init);
  256. #endif //#if defined(BSP_USING_UART)