339 lines
9.1 KiB
C
339 lines
9.1 KiB
C
/* 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 |
|
||
*/
|
||
|
||
#ifndef _DRIVER_CLINT_H
|
||
#define _DRIVER_CLINT_H
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include "platform.h"
|
||
|
||
#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 /* _DRIVER_CLINT_H */
|
||
|