#include #include #include #include #include #include #include #include #include #include #include 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 };