| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- /*
- * Copyright (c) 2019 Nuclei Limited. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #ifndef __CORE_FEATURE_CIDU_H__
- #define __CORE_FEATURE_CIDU_H__
- /*!
- * @file core_feature_cidu.h
- * @brief Cluster Interrupt Distribution Unit feature API header file for Nuclei N/NX Core
- */
- /*
- * CIDU Feature Configuration Macro:
- * 1. __CIDU_PRESENT: Define whether Cluster Interrupt Distribution Unit is present or not.
- * * 0: Not present
- * * 1: Present
- * 2. __CIDU_BASEADDR: Define the base address of the CIDU.
- */
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "core_feature_base.h"
- #if defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1)
- /* ########################## CIDU functions #################################### */
- /**
- * \defgroup NMSIS_Core_CIDU CIDU Functions
- * \ingroup NMSIS_Core
- * \brief Functions that manage external interrupts, inter core interrupts and semaphores.
- * \details
- *
- * Nuclei provide Cluster Interrupt Distribution Unit (CIDU) for scenarios that a SMP system is designed for real
- * time application or both Linux and real time application, and Nuclei processor core can optionally support CIDU.
- * The CIDU is used to distribute external interrupts to the core’s ECLIC, also it provides Inter Core Interrupt (ICI)
- * and Semaphores Mechanism. Its features are as follows:
- *
- * * Support up to 16 Cores in one cluster
- * * Support up to 4096 external interrupts sources
- * * Support up to 16 Inter Core Interrupts
- * * Support 32 Semaphores
- *
- * @{
- */
- #ifndef __CIDU_BASEADDR
- /* Base address of CIDU(__CIDU_BASEADDR) should be defined in <Device.h> */
- #error "__CIDU_BASEADDR is not defined, please check!"
- #endif
- #define CIDU_BASE __CIDU_BASEADDR
- #define CIDU_RECEIVE_INTERRUPT_EN(core_id) (0x1UL << core_id) /*!< Indicates the core can receive corresponding interrupt */
- #define CIDU_CORE_INT_STATUS_OFS 0x0 /*!< Core n Inter Core Interrupt status register base offset */
- #define CIDU_SEMAPHORE_OFS 0x80 /*!< Semaphore n register base offset */
- #define CIDU_ICI_SHADOW_OFS 0x3FFC /*!< ICI Interrupt source core ID and target core ID register offset */
- #define CIDU_INT_INDICATOR_OFS 0x4000 /*!< External interrupt n indicator register base offset */
- #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 */
- #define CIDU_CORE_NUM_OFS 0xC084 /*!< Static configuration core num register offset */
- #define CIDU_INT_NUM_OFS 0xC090 /*!< Static configuration external interrupt number register offset */
- #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 */
- #define CIDU_SEMAPHORE_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_SEMAPHORE_OFS) + ((n) << 2)) /*!< Semaphore n register address */
- #define CIDU_ICI_SHADOW_ADDR (unsigned long)((CIDU_BASE) + (CIDU_ICI_SHADOW_OFS)) /*!< ICI Interrupt source core ID and target core ID register address */
- #define CIDU_INT_INDICATOR_ADDR(n) (unsigned long)((CIDU_BASE) + (CIDU_INT_INDICATOR_OFS) + ((n) << 2)) /*!< External interrupt n indicator register address */
- #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 */
- #define CIDU_CORE_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_CORE_NUM_OFS)) /*!< Static configuration core num register address */
- #define CIDU_INT_NUM_ADDR (unsigned long)((CIDU_BASE) + (CIDU_INT_NUM_OFS)) /*!< Static configuration external interrupt number register address */
- /* SEND_CORE_ID position in ICI_SHADOW_REG register */
- #define CIDU_ICI_SEND_CORE_ID_POS 16
- /**
- * \brief Get core number in the cluster
- * \details
- * Indicate the static configuration core num in the cluster.
- * \return core number configured
- * \remarks
- * - In a Nulcei multi-core system, each core has an identifiable serial number, the serial number starts from 0 and is
- * continuous, also the number is static.
- * - CORE_NUM register is read only.
- */
- __STATIC_FORCEINLINE uint32_t CIDU_GetCoreNum(void)
- {
- uint32_t val;
- uint32_t* addr = (uint32_t*)CIDU_CORE_NUM_ADDR;
- val = __LW(addr);
- return val;
- }
- /**
- * \brief Get external interrupt number
- * \details
- * Indicate the static configuration external interrupt number
- * \return interrupt number configured
- * \remarks
- * - INT_NUM register is read only.
- */
- __STATIC_FORCEINLINE uint32_t CIDU_GetIntNum(void)
- {
- uint32_t val;
- uint32_t* addr = (uint32_t*)CIDU_INT_NUM_ADDR;
- val = __LW(addr);
- return val;
- }
- /** @} */ /* End of Doxygen Group NMSIS_Core_CIDU */
- /**
- * \defgroup NMSIS_Core_Distribute_Interrupt External Interrupt Distribution Functions
- * \ingroup NMSIS_Core_CIDU
- * \brief Functions that distribute external interrupts to cores.
- * @{
- */
- /**
- * \brief Broadcast external interrupt to cores
- * \details
- * This function broadcasts external interrupt which id is int_id to some/all target cores
- * \param [in] int_id external interrupt id
- * \param [in] to_cores target cores which can receive interrupt, use bitwise inclusive or
- * of \ref CIDU_RECEIVE_INTERRUPT_EN(core_id)
- * \remarks
- * - External IRQn ID(int_id) is from the hard-wired persperctive,
- * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
- * - By default on reset, only core 0 can receive interrupt which id is int_id
- */
- __STATIC_FORCEINLINE void CIDU_BroadcastExtInterrupt(uint32_t int_id, uint32_t to_cores)
- {
- uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
- __SW(addr, (uint32_t)to_cores);
- }
- /**
- * \brief get broadcast mode status
- * \details
- * Just query the INTn_INDICATOR register value
- * \param [in] int_id external interrupt id
- * \return INTn_INDICATOR register value
- * \remarks
- * - External IRQn ID(int_id) is from the hard-wired persperctive,
- * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
- * - By default on reset, only core 0 can receive interrupt which id is int_id
- */
- __STATIC_FORCEINLINE uint32_t CIDU_GetBroadcastModeStatus(uint32_t int_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_INT_INDICATOR_ADDR(int_id);
- val = __LW(addr);
- return val;
- }
- /**
- * \brief Let the first coming core to first claim the interrupt
- * \details
- * In external interrupt broadcast mode, make the first coming core to claim this interrupt and then can handle it.
- * \param [in] int_id external interrupt id
- * \param [in] core_id core id that receive the interrupt
- * \return -1 if it fails to claim the interrupt, else it can continue to handle the interrupt
- * \remarks
- * - External IRQn ID(int_id) is from the hard-wired persperctive,
- * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>.
- * - If it fails to claim the interrupt, it should quit the interrupt n's handler of all cores
- * - When a core claims the interrupt successfully and has handled it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim.
- * \sa
- * - \ref CIDU_BroadcastExtInterrupt
- * - \ref CIDU_ResetFirstClaimMode
- */
- __STATIC_INLINE long CIDU_SetFirstClaimMode(uint32_t int_id, uint32_t core_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
- uint32_t mask = 1UL << core_id;
- __SW(addr, mask);
- val = __LW(addr);
- if (mask == val) {
- return 0;
- }
- return -1;
- }
- /**
- * \brief Reset the claim mode mask
- * \details
- * Reset the claim mode mask by Writing the reset value (all 1) to it
- * \param [in] int_id external interrupt id
- * \remarks
- * - External IRQn ID(int_id) is from the hard-wired persperctive,
- * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
- * - When a core claims the interrupt successfully and handle it, it must call \ref CIDU_ResetFirstClaimMode to reset the claim
- * \sa
- * - \ref CIDU_SetFirstClaimMode
- */
- __STATIC_FORCEINLINE void CIDU_ResetFirstClaimMode(uint32_t int_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
- /* clear by writing all 1 */
- __SW(addr, 0xFFFFFFFF);
- }
- /**
- * \brief Get the claim mask status
- * \details
- * Get the claim mode staus, each bit[n] indicates whether core n has claimed interrupt successfully,
- * 1 means yes, 0 means no.
- * \param [in] int_id external interrupt id
- * \return claim mode register INTn_MASK value
- * \remarks
- * - External IRQn ID(int_id) is from the hard-wired persperctive,
- * which has an offset mapped to the ECLIC IRQn, see Interrupt Number Definition in <Device.h>
- * \sa
- * - \ref CIDU_ResetFirstClaimMode
- * - \ref CIDU_SetFirstClaimMode
- */
- __STATIC_FORCEINLINE uint32_t CIDU_GetClaimStatus(uint32_t int_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_INT_MASK_ADDR(int_id);
- val = __LW(addr);
- return val;
- }
- /** @} */ /* End of Doxygen Group NMSIS_Core_Distribute_Interrupt */
- /**
- * \defgroup NMSIS_Core_ICI Inter Core Interrupt Functions
- * \ingroup NMSIS_Core_CIDU
- * \brief Functions that implement Inter Core Interrupt mechanism.
- * @{
- * Inter Core Interrupt (ICI) means that one core can send interrupt to another core in a multi-core cluster. CIDU ICI belongs
- * to Internal Interrupt.
- *
- * * CIDU ICI Interrupt ID is fixed to 16.
- */
- /**
- * \brief Trigger interrupt to another core in a multi-core cluster
- * \details
- * When called by core send_core_id, CIDU will trigger ICI to core recv_core_id automatically.
- * and core recv_core_id could query \ref CIDU_GetCoreIntSenderId to know the sender.
- * \param [in] send_core_id the core id which want to send the inter core interrupt
- * \param [in] recv_core_id the core id which will receive the inter core interrupt
- * \remarks
- * - The core recv_core_id need to call CIDU_ClearInterCoreIntReq to clear the corresponding bit/bits
- * of its own COREn_INT_STATUS.
- * - It supports that multiple cores call \ref CIDU_TriggerInterCoreInt simultaneously.
- * \sa
- * - \ref CIDU_GetCoreIntSenderId
- * - \ref CIDU_ClearInterCoreIntReq
- */
- __STATIC_FORCEINLINE void CIDU_TriggerInterCoreInt(uint32_t send_core_id, uint32_t recv_core_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_ICI_SHADOW_ADDR;
- val = (uint32_t)(send_core_id << CIDU_ICI_SEND_CORE_ID_POS) | (uint32_t)(recv_core_id);
- __SW(addr, (uint32_t)val);
- }
- /**
- * \brief Core recv_core_id queries out who sends inter core interrupt to itself
- * \details
- * In the ISR of ICI, receive core can query if bit[n] of this return value is 1, core n sends the current ICI,
- * if bit[m] is 1, then core m also sends, etc.
- * \param [in] recv_core_id the core id which receives the inter core interrupt
- * \return Value that shows sender core's ID n whose bit[n](bit[m] if core m send too, etc.) is 1
- * \remarks
- * - If the ICI ISR has finished the job, should call \ref CIDU_ClearInterCoreIntReq to clear the IRQ
- */
- __STATIC_FORCEINLINE uint32_t CIDU_QueryCoreIntSenderMask(uint32_t recv_core_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
- val = __LW(addr);
- return val;
- }
- /**
- * \brief Clear the corresponding bit/bits of ICI request triggered by sender core
- * \details
- * Core recv_core_id write 1 to clear the bit send_core_id of the core recv_core_id's COREn_INT_STATUS.
- * \param [in] send_core_id the core id which wants to send the inter core interrupt
- * \param [in] recv_core_id the core id which will receive the inter core interrupt
- * \remarks
- * - If the ICI ISR has finished the job of send_core_id_n's ICI, then clear bit send_core_id_n;
- * if it has finished send_core_id_n and send_core_id_m's, then should clear both the bits, etc.
- */
- __STATIC_FORCEINLINE void CIDU_ClearInterCoreIntReq(uint32_t send_core_id, uint32_t recv_core_id)
- {
- uint32_t val = 0;
- uint32_t* addr = (uint32_t*)CIDU_CORE_INT_STATUS_ADDR(recv_core_id);
- val = (uint32_t)(1UL << send_core_id);
- __SW(addr, val);
- }
- /** @} */ /* End of Doxygen Group NMSIS_Core_ICI */
- /**
- * \defgroup NMSIS_Core_Semaphore Semaphore Functions
- * \ingroup NMSIS_Core_CIDU
- * \brief Functions that configure and use semaphores
- * @{
- * Semaphore is very useful for multi-core cluster without SMP enable.
- *
- * * All Cores in the cluster agree on using SEMAPHORE_n register to protect a critical resource (an UART device for example).
- * * 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.
- * * When the Core n owns the register SEMPAPHORE_n and finishes the job related the critical resource, then it should
- * release the register by writing all 1 to it.
- */
- /**
- * \brief Get SEMAPHOREn's value
- * \details
- * Just query the semaphore n's value
- * \param [in] semph_n the semaphore id used to protect a critical resource
- * \return register SEMAPHOREn_STATUS value
- */
- __STATIC_FORCEINLINE uint32_t CIDU_GetSemaphoreStatus(uint32_t semph_n)
- {
- uint32_t val;
- uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
- val = __LW(addr);
- return val;
- }
- /**
- * \brief check SEMAPHOREn's acquired status
- * \details
- * Query that whether SEMAPHOREn has been acquired by one core successfully.
- * \param [in] semph_n the semaphore id used to protect a critical resource
- * \param [in] core_id the core id that wants to access the critical resource
- * \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
- * \remarks
- * - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
- * it should call \ref CIDU_ReleaseSemaphore to release it.
- * \sa
- * - \ref CIDU_GetSemaphoreStatus
- * - \ref CIDU_ReleaseSemaphore
- */
- __STATIC_INLINE long CIDU_CheckSemaphoreAcquired(uint32_t semph_n, uint32_t core_id)
- {
- uint32_t val;
- val = CIDU_GetSemaphoreStatus(semph_n);
- if (core_id != val) {
- return -1;
- }
- return 0;
- }
- /**
- * \brief Acquire the SEMAPHOREn
- * \details
- * Acuqire the SEMAPHOREn, and check the acquired status
- * \param [in] semph_n the semaphore id used to protect a critical resource
- * \param [in] core_id the core id that wants to access the critical resource
- * \return 0 if core_id has acquired this semaphore successfully, or else -1 if failed
- * \remarks
- * - When the core n owns the register SEMPAPHORE_n and finishes the job related the critical resource,
- * it should call \ref CIDU_ReleaseSemaphore to release it.
- * \sa
- * - \ref CIDU_CheckSemaphoreAcquired
- * - \ref CIDU_ReleaseSemaphore
- */
- __STATIC_INLINE long CIDU_AcquireSemaphore(uint32_t semph_n, uint32_t core_id)
- {
- long semaphore_status = -1;
- uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
- __SW(addr, core_id);
- semaphore_status = CIDU_CheckSemaphoreAcquired(semph_n, core_id);
- return semaphore_status;
- }
- /**
- * \brief Keep acquiring the SEMAPHOREn until it has acquired this semaphore successfully
- * \details
- * Query that whether SEMAPHOREn has been owned by one core successfully, if not, keep trying.
- * \param [in] semph_n the semaphore id used to protect a critical resource
- * \param [in] core_id the core id that wants to access the critical resource
- * \remarks
- * - Core n will block here acquiring, so take care that core should release the semaphore when related job done.
- * \sa
- * - \ref CIDU_AcquireSemaphore
- * - \ref CIDU_ReleaseSemaphore
- */
- __STATIC_INLINE void CIDU_AcquireSemaphore_Block(uint32_t semph_n, uint32_t core_id)
- {
- int32_t semaphore_status = -1;
- while(0 != semaphore_status) {
- semaphore_status = CIDU_AcquireSemaphore(semph_n, core_id);
- }
- }
- /**
- * \brief Release the SEMAPHOREn
- * \details
- * Release the SEMAPHOREn by writing all 1 to SEMAPHOREn register.
- * \param [in] semph_n the semaphore id used to protect a critical resource
- * \remarks
- * - When the core finishes the job related to the critical resource, it should release the corresponding semaphore.
- * \sa
- * - \ref CIDU_AcquireSemaphore_Block
- */
- __STATIC_FORCEINLINE void CIDU_ReleaseSemaphore(uint32_t semph_n)
- {
- uint32_t* addr = (uint32_t*)CIDU_SEMAPHORE_ADDR(semph_n);
- /* Release by writing all 1 */
- __SW(addr, 0xFFFFFFFF);
- }
- /** @} */ /* End of Doxygen Group NMSIS_Core_Semaphore */
- /** @} */ /* End of Doxygen Group NMSIS_Core_CIDU_Functions */
- #endif /* defined(__CIDU_PRESENT) && (__CIDU_PRESENT == 1) */
- #ifdef __cplusplus
- }
- #endif
- #endif /* __CORE_FEATURE_CIDU_H__ */
|