/* Copyright 2018 Canaan Inc. * * 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 * * http://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. */ /** * @file * @brief The CLINT block holds memory-mapped control and status registers * associated with local interrupts for a Coreplex. * * @note CLINT RAM Layout * * | Address -| Description | * |------------|---------------------------------| * | 0x02000000 | msip for core 0 | * | 0x02000004 | msip for core 1 | * | ... | ... | * | 0x02003FF8 | msip for core 4094 | * | | | * | 0x02004000 | mtimecmp for core 0 | * | 0x02004008 | mtimecmp for core 1 | * | ... | ... | * | 0x0200BFF0 | mtimecmp For core 4094 | * | 0x0200BFF8 | mtime | * | | | * | 0x0200C000 | Reserved | * | ... | ... | * | 0x0200EFFC | Reserved | */ /** * @file clint.h * @brief add from Canaan k210 SDK * https://canaan-creative.com/developer * @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-25 */ #ifndef __CLINT_H__ #define __CLINT_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif /* clang-format off */ /* Register address offsets */ #define CLINT_MSIP (0x0000) #define CLINT_MSIP_SIZE (0x4) #define CLINT_MTIMECMP (0x4000) #define CLINT_MTIMECMP_SIZE (0x8) #define CLINT_MTIME (0xBFF8) #define CLINT_MTIME_SIZE (0x8) /* Max number of cores */ #define CLINT_MAX_CORES (4095) /* Real number of cores */ #define CLINT_NUM_CORES (2) /* Clock frequency division factor */ #define CLINT_CLOCK_DIV (50) /* clang-format on */ /** * @brief MSIP Registers * * Machine-mode software interrupts are generated by writing to a * per-core memory-mapped control register. The msip registers are * 32-bit wide WARL registers, where the LSB is reflected in the * msip bit of the associated core’s mip register. Other bits in * the msip registers are hardwired to zero. The mapping supports * up to 4095 machine-mode cores. */ typedef struct _clint_msip { uint32_t msip : 1; /*!< Bit 0 is msip */ uint32_t zero : 31; /*!< Bits [32:1] is 0 */ } __attribute__((packed, aligned(4))) clint_msip_t; /** * @brief Timer compare Registers Machine-mode timer interrupts are * generated by a real-time counter and a per-core comparator. The * mtime register is a 64-bit read-only register that contains the * current value of the real-time counter. Each mtimecmp register * holds its core’s time comparator. A timer interrupt is pending * whenever mtime is greater than or equal to the value in a * core’s mtimecmp register. The timer interrupt is reflected in * the mtip bit of the associated core’s mip register. */ typedef uint64_t clint_mtimecmp_t; /** * @brief Timer Registers * * The mtime register has a 64-bit precision on all RV32, RV64, * and RV128 systems. Platforms provide a 64-bit memory-mapped * machine-mode timer compare register (mtimecmp), which causes a * timer interrupt to be posted when the mtime register contains a * value greater than or equal to the value in the mtimecmp * register. The interrupt remains posted until it is cleared by * writing the mtimecmp register. The interrupt will only be taken * if interrupts are enabled and the MTIE bit is set in the mie * register. */ typedef uint64_t clint_mtime_t; /** * @brief CLINT object * * Coreplex-Local INTerrupts, which includes software interrupts, * local timer interrupts, and other interrupts routed directly to * a core. */ typedef struct _clint { /* 0x0000 to 0x3FF8, MSIP Registers */ clint_msip_t msip[CLINT_MAX_CORES]; /* Resverd space, do not use */ uint32_t resv0; /* 0x4000 to 0xBFF0, Timer Compare Registers */ clint_mtimecmp_t mtimecmp[CLINT_MAX_CORES]; /* 0xBFF8, Time Register */ clint_mtime_t mtime; } __attribute__((packed, aligned(4))) clint_t; /** * @brief Clint object instanse */ extern volatile clint_t* const clint; /** * @brief Definitions for the timer callbacks */ typedef int (*clint_timer_callback_t)(void *ctx); /** * @brief Definitions for local interprocessor interrupt callbacks */ typedef int (*clint_ipi_callback_t)(void *ctx); typedef struct _clint_timer_instance { uint64_t interval; uint64_t cycles; uint64_t single_shot; clint_timer_callback_t callback; void *ctx; } clint_timer_instance_t; typedef struct _clint_ipi_instance { clint_ipi_callback_t callback; void *ctx; } clint_ipi_instance_t; /** * @brief Get the time form CLINT timer register * * @note The CLINT must init to get right time * * @return 64bit Time */ uint64_t clint_get_time(void); /** * @brief Init the CLINT timer * * @note MIP_MTIP will be clear after init. The MSTATUS_MIE must set by * user. * * @return result * - 0 Success * - Other Fail */ int clint_timer_init(void); /** * @brief Stop the CLINT timer * * @note MIP_MTIP will be clear after stop * * @return result * - 0 Success * - Other Fail */ int clint_timer_stop(void); /** * @brief Start the CLINT timer * * @param[in] interval The interval with Millisecond(ms) * @param[in] single_shot Single shot or repeat * * @return result * - 0 Success * - Other Fail */ int clint_timer_start(uint64_t interval, int single_shot); /** * @brief Get the interval of timer * * @return The interval with Millisecond(ms) */ uint64_t clint_timer_get_interval(void); /** * @brief Set the interval with Millisecond(ms) * * @param[in] interval The interval with Millisecond(ms) * * @return result * - 0 Success * - Other Fail */ int clint_timer_set_interval(uint64_t interval); /** * @brief Get whether the timer is a single shot timer * * @return result * - 0 It is a repeat timer * - 1 It is a single shot timer */ int clint_timer_get_single_shot(void); /** * @brief Set the timer working as a single shot timer or repeat timer * * @param[in] single_shot Single shot or repeat * * @return result * - 0 Success * - Other Fail */ int clint_timer_set_single_shot(int single_shot); /** * @brief Set user callback function when timer is timeout * * @param[in] callback The callback function * @param[in] ctx The context * * @return result * - 0 Success * - Other Fail */ int clint_timer_register(clint_timer_callback_t callback, void *ctx); /** * @brief Deregister user callback function * * @return result * - 0 Success * - Other Fail */ int clint_timer_unregister(void); /** * @brief Initialize local interprocessor interrupt * * @return result * - 0 Success * - Other Fail */ int clint_ipi_init(void); /** * @brief Enable local interprocessor interrupt * * @return result * - 0 Success * - Other Fail */ int clint_ipi_enable(void); /** * @brief Disable local interprocessor interrupt * * @return result * - 0 Success * - Other Fail */ int clint_ipi_disable(void); /** * @brief Send local interprocessor interrupt to core by core id * * @param[in] core_id The core identifier * * @return result * - 0 Success * - Other Fail */ int clint_ipi_send(size_t core_id); /** * @brief Clear local interprocessor interrupt * * @param[in] core_id The core identifier * * @return result * - 1 An IPI was pending * - 0 Non IPI was pending * - -1 Fail */ int clint_ipi_clear(size_t core_id); /** * @brief Set user callback function when interprocessor interrupt * * @param[in] callback The callback function * @param[in] ctx The context * * @return result * - 0 Success * - Other Fail */ int clint_ipi_register(clint_ipi_callback_t callback, void *ctx); /** * @brief Deregister user callback function * * @return result * - 0 Success * - Other Fail */ int clint_ipi_unregister(void); #ifdef __cplusplus } #endif #endif /* __CLINT_H__ */