core_feature_cidu.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * Copyright (c) 2019 Nuclei Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #ifndef __CORE_FEATURE_CIDU_H__
  19. #define __CORE_FEATURE_CIDU_H__
  20. /*!
  21. * @file core_feature_cidu.h
  22. * @brief Cluster Interrupt Distribution Unit feature API header file for Nuclei N/NX Core
  23. */
  24. /*
  25. * CIDU Feature Configuration Macro:
  26. * 1. __CIDU_PRESENT: Define whether Cluster Interrupt Distribution Unit is present or not.
  27. * * 0: Not present
  28. * * 1: Present
  29. * 2. __CIDU_BASEADDR: Define the base address of the CIDU.
  30. */
  31. #ifdef __cplusplus
  32. extern "C" {
  33. #endif
  34. #include "core_feature_base.h"
  35. #if defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1)
  36. /* ########################## CIDU functions #################################### */
  37. /**
  38. * \defgroup NMSIS_Core_CIDU CIDU Functions
  39. * \ingroup NMSIS_Core
  40. * \brief Functions that manage external interrupts, inter core interrupts and semaphores.
  41. * \details
  42. *
  43. * Nuclei provide Cluster Interrupt Distribution Unit (CIDU) for scenarios that a SMP system is designed for real
  44. * time application or both Linux and real time application, and Nuclei processor core can optionally support CIDU.
  45. * The CIDU is used to distribute external interrupts to the core’s ECLIC, also it provides Inter Core Interrupt (ICI)
  46. * and Semaphores Mechanism. Its features are as follows:
  47. *
  48. * * Support up to 16 Cores in one cluster
  49. * * Support up to 4096 external interrupts sources
  50. * * Support up to 16 Inter Core Interrupts
  51. * * Support 32 Semaphores
  52. *
  53. * @{
  54. */
  55. #ifndef __CIDU_BASEADDR
  56. /* Base address of CIDU(__CIDU_BASEADDR) should be defined in <Device.h> */
  57. #error "__CIDU_BASEADDR is not defined, please check!"
  58. #endif
  59. #define CIDU_BASE __CIDU_BASEADDR
  60. #define CIDU_RECEIVE_INTERRUPT_EN(core_id) (0x1UL << core_id) /*!< Indicates the core can receive corresponding interrupt */
  61. #define CIDU_CORE_INT_STATUS_OFS 0x0 /*!< Core n Inter Core Interrupt status register base offset */
  62. #define CIDU_SEMAPHORE_OFS 0x80 /*!< Semaphore n register base offset */
  63. #define CIDU_ICI_SHADOW_OFS 0x3FFC /*!< ICI Interrupt source core ID and target core ID register offset */
  64. #define CIDU_INT_INDICATOR_OFS 0x4000 /*!< External interrupt n indicator register base offset */
  65. #define CIDU_INT_MASK_OFS 0x8000 /*!< External interrupt n mask (mask interrupt n to cores or not when interrupt n indicator on)register base offset */
  66. #define CIDU_CORE_NUM_OFS 0xC084 /*!< Static configuration core num register offset */
  67. #define CIDU_INT_NUM_OFS 0xC090 /*!< Static configuration external interrupt number register offset */
  68. #define CIDU_CORE_INT_STATUS_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_CORE_INT_STATUS_OFS) + ((n) << 2)) /*!< Core n Inter Core Interrupt status register address */
  69. #define CIDU_SEMAPHORE_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_SEMAPHORE_OFS) + ((n) << 2)) /*!< Semaphore n register address */
  70. #define CIDU_ICI_SHADOW_ADDR (unsigned long)((CIDU_BASE) + (CIDU_ICI_SHADOW_OFS)) /*!< ICI Interrupt source core ID and target core ID register address */
  71. #define CIDU_INT_INDICATOR_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_INT_INDICATOR_OFS) + ((n) << 2)) /*!< External interrupt n indicator register address */
  72. #define CIDU_INT_MASK_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_INT_MASK_OFS) + ((n) << 2)) /*!< External interrupt n mask (mask interrupt n to cores or not when interrupt n indicator on)register address */
  73. #define CIDU_CORE_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_CORE_NUM_OFS)) /*!< Static configuration core num register address */
  74. #define CIDU_INT_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_INT_NUM_OFS)) /*!< Static configuration external interrupt number register address */
  75. /* SEND_CORE_ID position in ICI_SHADOW_REG register */
  76. #define CIDU_ICI_SEND_CORE_ID_POS 16
  77. /**
  78. * \brief Get core number in the cluster
  79. * \details
  80. * Indicate the static configuration core num in the cluster.
  81. * \return core number configured
  82. * \remarks
  83. * - In a Nulcei multi-core system, each core has an identifiable serial number, the serial number starts from 0 and is
  84. * continuous, also the number is static.
  85. * - CORE_NUM register is read only.
  86. */
  87. __STATIC_FORCEINLINE uint32_t CIDU_GetCoreNum(void)
  88. {
  89. uint32_t val;
  90. uint32_t* addr = (uint32_t*)CIDU_CORE_NUM_ADDR;
  91. val = __LW(addr);
  92. return val;
  93. }
  94. /**
  95. * \brief Get external interrupt number
  96. * \details
  97. * Indicate the static configuration external interrupt number
  98. * \return interrupt number configured
  99. * \remarks
  100. * - INT_NUM register is read only.
  101. */
  102. __STATIC_FORCEINLINE uint32_t CIDU_GetIntNum(void)
  103. {
  104. uint32_t val;
  105. uint32_t* addr = (uint32_t*)CIDU_INT_NUM_ADDR;
  106. val = __LW(addr);
  107. return val;
  108. }
  109. /** @} */ /* End of Doxygen Group NMSIS_Core_CIDU */
  110. /**
  111. * \defgroup NMSIS_Core_Distribute_Interrupt External Interrupt Distribution Functions
  112. * \ingroup NMSIS_Core_CIDU
  113. * \brief Functions that distribute external interrupts to cores.
  114. * @{
  115. */
  116. /**
  117. * \brief Broadcast external interrupt to cores
  118. * \details
  119. * This function broadcasts external interrupt which id is int_id to some/all target cores
  120. * \param [in] int_id external interrupt id
  121. * \param [in] to_cores target cores which can receive interrupt, use bitwise inclusive or
  122. * of \ref CIDU_RECEIVE_INTERRUPT_EN(core_id)
  123. * \remarks
  124. * - External IRQn ID(int_id) is from the hard-wired persperctive,
  125. * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
  126. * - By default on reset, only core 0 can receive interrupt which id is int_id
  127. */
  128. __STATIC_FORCEINLINE void CIDU_BroadcastExtInterrupt(uint32_t int_id, uint32_t to_cores)
  129. {
  130. uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
  131. __SW(addr, (uint32_t)to_cores);
  132. }
  133. /**
  134. * \brief get broadcast mode status
  135. * \details
  136. * Just query the INTn_INDICATOR register value
  137. * \param [in] int_id external interrupt id
  138. * \return INTn_INDICATOR register value
  139. * \remarks
  140. * - External IRQn ID(int_id) is from the hard-wired persperctive,
  141. * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
  142. * - By default on reset, only core 0 can receive interrupt which id is int_id
  143. */
  144. __STATIC_FORCEINLINE uint32_t CIDU_GetBroadcastModeStatus(uint32_t int_id)
  145. {
  146. uint32_t val = 0;
  147. uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
  148. val = __LW(addr);
  149. return val;
  150. }
  151. /**
  152. * \brief Let the first coming core to first claim the interrupt
  153. * \details
  154. * In external interrupt broadcast mode, make the first coming core to claim this interrupt and then can handle it.
  155. * \param [in] int_id external interrupt id
  156. * \param [in] core_id core id that receive the interrupt
  157. * \return -1 if it fails to claim the interrupt, else it can continue to handle the interrupt
  158. * \remarks
  159. * - External IRQn ID(int_id) is from the hard-wired persperctive,
  160. * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>.
  161. * - If it fails to claim the interrupt, it should quit the interrupt n's handler of all cores
  162. * - When a core claims the interrupt successfully and has handled it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim.
  163. * \sa
  164. * - \ref CIDU_BroadcastExtInterrupt
  165. * - \ref CIDU_ResetFirstClaimMode
  166. */
  167. __STATIC_INLINE long CIDU_SetFirstClaimMode(uint32_t int_id, uint32_t core_id)
  168. {
  169. uint32_t val = 0;
  170. uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
  171. uint32_t mask = 1UL << core_id;
  172. __SW(addr, mask);
  173. val = __LW(addr);
  174. if (mask == val) {
  175. return 0;
  176. }
  177. return -1;
  178. }
  179. /**
  180. * \brief Reset the claim mode mask
  181. * \details
  182. * Reset the claim mode mask by Writing the reset value (all 1) to it
  183. * \param [in] int_id external interrupt id
  184. * \remarks
  185. * - External IRQn ID(int_id) is from the hard-wired persperctive,
  186. * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
  187. * - When a core claims the interrupt successfully and handle it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim
  188. * \sa
  189. * - \ref CIDU_SetFirstClaimMode
  190. */
  191. __STATIC_FORCEINLINE void CIDU_ResetFirstClaimMode(uint32_t int_id)
  192. {
  193. uint32_t val = 0;
  194. uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
  195. /* clear by writing all 1 */
  196. __SW(addr, 0xFFFFFFFF);
  197. }
  198. /**
  199. * \brief Get the claim mask status
  200. * \details
  201. * Get the claim mode staus, each bit[n] indicates whether core n has claimed interrupt successfully,
  202. * 1 means yes, 0 means no.
  203. * \param [in] int_id external interrupt id
  204. * \return claim mode register INTn_MASK value
  205. * \remarks
  206. * - External IRQn ID(int_id) is from the hard-wired persperctive,
  207. * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
  208. * \sa
  209. * - \ref CIDU_ResetFirstClaimMode
  210. * - \ref CIDU_SetFirstClaimMode
  211. */
  212. __STATIC_FORCEINLINE uint32_t CIDU_GetClaimStatus(uint32_t int_id)
  213. {
  214. uint32_t val = 0;
  215. uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
  216. val = __LW(addr);
  217. return val;
  218. }
  219. /** @} */ /* End of Doxygen Group NMSIS_Core_Distribute_Interrupt */
  220. /**
  221. * \defgroup NMSIS_Core_ICI Inter Core Interrupt Functions
  222. * \ingroup NMSIS_Core_CIDU
  223. * \brief Functions that implement Inter Core Interrupt mechanism.
  224. * @{
  225. * Inter Core Interrupt (ICI) means that one core can send interrupt to another core in a multi-core cluster. CIDU ICI belongs
  226. * to Internal Interrupt.
  227. *
  228. * * CIDU ICI Interrupt ID is fixed to 16.
  229. */
  230. /**
  231. * \brief Trigger interrupt to another core in a multi-core cluster
  232. * \details
  233. * When called by core send_core_id, CIDU will trigger ICI to core recv_core_id automatically.
  234. * and core recv_core_id could query \ref CIDU_GetCoreIntSenderId to know the sender.
  235. * \param [in] send_core_id the core id which want to send the inter core interrupt
  236. * \param [in] recv_core_id the core id which will receive the inter core interrupt
  237. * \remarks
  238. * - The core recv_core_id need to call CIDU_ClearInterCoreIntReq to clear the corresponding bit/bits
  239. * of its own COREn_INT_STATUS.
  240. * - It supports that multiple cores call \ref CIDU_TriggerInterCoreInt simultaneously.
  241. * \sa
  242. * - \ref CIDU_GetCoreIntSenderId
  243. * - \ref CIDU_ClearInterCoreIntReq
  244. */
  245. __STATIC_FORCEINLINE void CIDU_TriggerInterCoreInt(uint32_t send_core_id, uint32_t recv_core_id)
  246. {
  247. uint32_t val = 0;
  248. uint32_t* addr = (uint32_t*)CIDU_ICI_SHADOW_ADDR;
  249. val = (uint32_t)(send_core_id << CIDU_ICI_SEND_CORE_ID_POS) | (uint32_t)(recv_core_id);
  250. __SW(addr, (uint32_t)val);
  251. }
  252. /**
  253. * \brief Core recv_core_id queries out who sends inter core interrupt to itself
  254. * \details
  255. * In the ISR of ICI, receive core can query if bit[n] of this return value is 1, core n sends the current ICI,
  256. * if bit[m] is 1, then core m also sends, etc.
  257. * \param [in] recv_core_id the core id which receives the inter core interrupt
  258. * \return Value that shows sender core's ID n whose bit[n](bit[m] if core m send too, etc.) is 1
  259. * \remarks
  260. * - If the ICI ISR has finished the job, should call \ref CIDU_ClearInterCoreIntReq to clear the IRQ
  261. */
  262. __STATIC_FORCEINLINE uint32_t CIDU_QueryCoreIntSenderMask(uint32_t recv_core_id)
  263. {
  264. uint32_t val = 0;
  265. uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
  266. val = __LW(addr);
  267. return val;
  268. }
  269. /**
  270. * \brief Clear the corresponding bit/bits of ICI request triggered by sender core
  271. * \details
  272. * Core recv_core_id write 1 to clear the bit send_core_id of the core recv_core_id's COREn_INT_STATUS.
  273. * \param [in] send_core_id the core id which wants to send the inter core interrupt
  274. * \param [in] recv_core_id the core id which will receive the inter core interrupt
  275. * \remarks
  276. * - If the ICI ISR has finished the job of send_core_id_n's ICI, then clear bit send_core_id_n;
  277. * if it has finished send_core_id_n and send_core_id_m's, then should clear both the bits, etc.
  278. */
  279. __STATIC_FORCEINLINE void CIDU_ClearInterCoreIntReq(uint32_t send_core_id, uint32_t recv_core_id)
  280. {
  281. uint32_t val = 0;
  282. uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
  283. val = (uint32_t)(1UL << send_core_id);
  284. __SW(addr, val);
  285. }
  286. /** @} */ /* End of Doxygen Group NMSIS_Core_ICI */
  287. /**
  288. * \defgroup NMSIS_Core_Semaphore Semaphore Functions
  289. * \ingroup NMSIS_Core_CIDU
  290. * \brief Functions that configure and use semaphores
  291. * @{
  292. * Semaphore is very useful for multi-core cluster without SMP enable.
  293. *
  294. * * All Cores in the cluster agree on using SEMAPHORE_n register to protect a critical resource (an UART device for example).
  295. * * If Core n wants to access the critical resource, it should try to own the SEMPAPHORE_n register, or else it can’t access the critical resource.
  296. * * When the Core n owns the register SEMPAPHORE_n and finishes the job related the critical resource, then it should
  297. * release the register by writing all 1 to it.
  298. */
  299. /**
  300. * \brief Get SEMAPHOREn's value
  301. * \details
  302. * Just query the semaphore n's value
  303. * \param [in] semph_n the semaphore id used to protect a critical resource
  304. * \return register SEMAPHOREn_STATUS value
  305. */
  306. __STATIC_FORCEINLINE uint32_t CIDU_GetSemaphoreStatus(uint32_t semph_n)
  307. {
  308. uint32_t val;
  309. uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
  310. val = __LW(addr);
  311. return val;
  312. }
  313. /**
  314. * \brief check SEMAPHOREn's acquired status
  315. * \details
  316. * Query that whether SEMAPHOREn has been acquired by one core successfully.
  317. * \param [in] semph_n the semaphore id used to protect a critical resource
  318. * \param [in] core_id the core id that wants to access the critical resource
  319. * \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
  320. * \remarks
  321. * - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
  322. * it should call \ref CIDU_ReleaseSemaphore to release it.
  323. * \sa
  324. * - \ref CIDU_GetSemaphoreStatus
  325. * - \ref CIDU_ReleaseSemaphore
  326. */
  327. __STATIC_INLINE long CIDU_CheckSemaphoreAcquired(uint32_t semph_n, uint32_t core_id)
  328. {
  329. uint32_t val;
  330. val = CIDU_GetSemaphoreStatus(semph_n);
  331. if (core_id != val) {
  332. return -1;
  333. }
  334. return 0;
  335. }
  336. /**
  337. * \brief Acquire the SEMAPHOREn
  338. * \details
  339. * Acuqire the SEMAPHOREn, and check the acquired status
  340. * \param [in] semph_n the semaphore id used to protect a critical resource
  341. * \param [in] core_id the core id that wants to access the critical resource
  342. * \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
  343. * \remarks
  344. * - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
  345. * it should call \ref CIDU_ReleaseSemaphore to release it.
  346. * \sa
  347. * - \ref CIDU_CheckSemaphoreAcquired
  348. * - \ref CIDU_ReleaseSemaphore
  349. */
  350. __STATIC_INLINE long CIDU_AcquireSemaphore(uint32_t semph_n, uint32_t core_id)
  351. {
  352. long semaphore_status = -1;
  353. uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
  354. __SW(addr, core_id);
  355. semaphore_status = CIDU_CheckSemaphoreAcquired(semph_n, core_id);
  356. return semaphore_status;
  357. }
  358. /**
  359. * \brief Keep acquiring the SEMAPHOREn until it has acquired this semaphore successfully
  360. * \details
  361. * Query that whether SEMAPHOREn has been owned by one core successfully, if not, keep trying.
  362. * \param [in] semph_n the semaphore id used to protect a critical resource
  363. * \param [in] core_id the core id that wants to access the critical resource
  364. * \remarks
  365. * - Core n will block here acquiring, so take care that core should release the semaphore when related job done.
  366. * \sa
  367. * - \ref CIDU_AcquireSemaphore
  368. * - \ref CIDU_ReleaseSemaphore
  369. */
  370. __STATIC_INLINE void CIDU_AcquireSemaphore_Block(uint32_t semph_n, uint32_t core_id)
  371. {
  372. int32_t semaphore_status = -1;
  373. while(0 != semaphore_status) {
  374. semaphore_status = CIDU_AcquireSemaphore(semph_n, core_id);
  375. }
  376. }
  377. /**
  378. * \brief Release the SEMAPHOREn
  379. * \details
  380. * Release the SEMAPHOREn by writing all 1 to SEMAPHOREn register.
  381. * \param [in] semph_n the semaphore id used to protect a critical resource
  382. * \remarks
  383. * - When the core finishes the job related to the critical resource, it should release the corresponding semaphore.
  384. * \sa
  385. * - \ref CIDU_AcquireSemaphore_Block
  386. */
  387. __STATIC_FORCEINLINE void CIDU_ReleaseSemaphore(uint32_t semph_n)
  388. {
  389. uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
  390. /* Release by writing all 1 */
  391. __SW(addr, 0xFFFFFFFF);
  392. }
  393. /** @} */ /* End of Doxygen Group NMSIS_Core_Semaphore */
  394. /** @} */ /* End of Doxygen Group NMSIS_Core_CIDU_Functions */
  395. #endif /* defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1) */
  396. #ifdef __cplusplus
  397. }
  398. #endif
  399. #endif /* __CORE_FEATURE_CIDU_H__ */