Files
opensbi/platform/riscv_vp/platform.c

179 lines
5.5 KiB
C

#include <sbi/riscv_asm.h>
#include <sbi/riscv_encoding.h>
#include <sbi/sbi_const.h>
#include <sbi/sbi_platform.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_types.h>
#include <sbi/sbi_ecall_interface.h>
#include <sbi/sbi_ecall.h>
#include <sbi/sbi_system.h>
#include <sbi/riscv_asm.h>
#include <sbi/sbi_timer.h>
typedef struct {
volatile uint32_t RX_TX_REG;
volatile uint32_t INT_CTRL_REG;
volatile uint32_t CLK_DIVIDER_REG;
volatile uint32_t FRAME_CONFIG_REG;
volatile uint32_t STATUS_REG;
} uart_t;
typedef struct {
volatile uint32_t MSIP0;
uint8_t fill0[16380];
volatile uint32_t MTIMECMP0LO;
volatile uint32_t MTIMECMP0HI;
uint8_t fill1[32752];
volatile uint32_t MTIME_LO;
volatile uint32_t MTIME_HI;
} aclint_t;
#define PERIPH(TYPE, ADDR) ((volatile TYPE *)(ADDR))
#define uart PERIPH(uart_t, 0x10000000 + 0x01000)
#define aclint PERIPH(aclint_t, 0x10000000 + 0x30000)
static inline void set_aclint_mtimecmp0lo(volatile aclint_t* reg, uint32_t value) {
reg->MTIMECMP0LO = (reg->MTIMECMP0LO & ~(0xffffffffU << 0)) | (value << 0);
}
static inline void set_aclint_mtimecmp0hi(volatile aclint_t* reg, uint32_t value) {
reg->MTIMECMP0HI = (reg->MTIMECMP0HI & ~(0xffffffffU << 0)) | (value << 0);
}
static inline uint32_t get_aclint_mtime_lo(volatile aclint_t* reg) { return (reg->MTIME_LO >> 0) & 0xffffffff; }
static inline uint32_t get_aclint_mtime_hi(volatile aclint_t* reg) { return (reg->MTIME_HI >> 0) & 0xffffffff; }
static inline uint32_t get_uart_rx_tx_reg_tx_free(volatile uart_t* reg) { return (reg->RX_TX_REG >> 15) & 0x1; }
static inline void set_uart_rx_tx_reg_data(volatile uart_t* reg, uint8_t value) {
reg->RX_TX_REG = (reg->RX_TX_REG & ~(0xffU << 0)) | (value << 0);
}
static inline uint32_t get_uart_rx_tx_reg_rx_avail(volatile uart_t* reg) { return (reg->RX_TX_REG >> 14) & 0x1; }
static inline uint32_t get_uart_rx_tx_reg_data(volatile uart_t* reg) { return (reg->RX_TX_REG >> 0) & 0xff; }
static void riscv_vp_putc(char c){
while(get_uart_rx_tx_reg_tx_free(uart) == 0)
;
set_uart_rx_tx_reg_data(uart, c);
}
static int riscv_vp_getc(){
if (get_uart_rx_tx_reg_rx_avail(uart))
return get_uart_rx_tx_reg_data(uart);
else
return -1;
}
const struct sbi_console_device minres_console = {
.name = "riscv_vp-uart",
.console_putc = riscv_vp_putc,
.console_getc = riscv_vp_getc,
};
void riscv_vp_reset(u32 reset_type, u32 reset_reason){
switch (reset_type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
sbi_printf("Shutting down system...\n");
break;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
sbi_printf("Performing cold reboot...\n");
break;
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
sbi_printf("Performing warm reboot...\n");
break;
default:
sbi_printf("Unknown system reset type: %u\n", reset_type);
}
while (1)
wfi();
};
int riscv_vp_reset_check(u32 reset_type, u32 reset_reason){
switch (reset_type) {
case SBI_SRST_RESET_TYPE_SHUTDOWN:
return 1;
case SBI_SRST_RESET_TYPE_COLD_REBOOT:
case SBI_SRST_RESET_TYPE_WARM_REBOOT:
default:
return 0;
}};
static struct sbi_system_reset_device reset_device = {
.name = "riscv_vp-reset",
.system_reset_check = riscv_vp_reset_check,
.system_reset = riscv_vp_reset
};
static u64 riscv_vp_timer_value(void){
uint32_t hi, lo;
do {
hi = get_aclint_mtime_hi(aclint);
lo = get_aclint_mtime_lo(aclint);
} while (hi != get_aclint_mtime_hi(aclint));
return ((u64)hi << 32) | lo;
}
static void riscv_vp_timer_event_start(u64 next_event){
// sbi_printf("OpenSBI: setting timer at %#lx\n", next_event);
set_aclint_mtimecmp0lo(aclint, (uint32_t)0xFFFFFFFF);
set_aclint_mtimecmp0hi(aclint, (uint32_t)(next_event >> 32));
set_aclint_mtimecmp0lo(aclint, (uint32_t)(next_event & 0xFFFFFFFF));
}
static void riscv_vp_timer_event_stop(void){
// sbi_printf("OpenSBI: Cancelling pending event\n");
set_aclint_mtimecmp0lo(aclint, (uint32_t)0xFFFFFFFF);
set_aclint_mtimecmp0hi(aclint, (uint32_t)0xFFFFFFFF);
}
static int riscv_vp_timer_warm_init(void){
riscv_vp_timer_event_stop();
return 0;
}
static struct sbi_timer_device timer_device = {
.name = "riscv_vp_timer",
.timer_freq = 32768,
.timer_value = riscv_vp_timer_value,
.timer_event_start = riscv_vp_timer_event_start,
.timer_event_stop = riscv_vp_timer_event_stop,
.warm_init = riscv_vp_timer_warm_init
};
static int platform_early_init(bool cold_boot){
if (cold_boot){
sbi_console_set_device(&minres_console);
}
return 0;
}
static int platform_final_init(bool cold_boot){
if (cold_boot){
sbi_system_reset_add_device(&reset_device);
sbi_timer_set_device(&timer_device);
}
return 0;
}
static int platform_irqchip_init(void){
return 0;
}
static int platform_ipi_init(void){
return 0;
}
static int platform_timer_init(void){
return 0;
}
const struct sbi_platform_operations platform_ops = {
.early_init = platform_early_init,
.final_init = platform_final_init,
.irqchip_init = platform_irqchip_init,
.ipi_init = platform_ipi_init,
.timer_init = platform_timer_init
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x1, 0x07),
.name = "riscv_vp",
.features = SBI_PLATFORM_DEFAULT_FEATURES,
.hart_count = 1,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.heap_size = SBI_PLATFORM_DEFAULT_HEAP_SIZE(1),
.platform_ops_addr = (unsigned long)&platform_ops
};