diff --git a/platform/riscv_vp/Kconfig b/platform/riscv_vp/Kconfig
new file mode 100644
index 00000000..66e792d8
--- /dev/null
+++ b/platform/riscv_vp/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+#
+# All mandatory drivers or libraries for this platform should
+# be directly selected by the PLATFORM_xyz kconfig symbol.
+#
+# All optional drivers or libraries for this platform should
+# be enabled via configs/defconfig of this platform.
+#
+config PLATFORM_TEMPLATE
+ bool
+ select IPI_MSWI
+ select IRQCHIP_PLIC
+ select SERIAL_UART8250
+ select TIMER_MTIMER
+ default n
diff --git a/platform/riscv_vp/configs/defconfig b/platform/riscv_vp/configs/defconfig
new file mode 100644
index 00000000..e69de29b
diff --git a/platform/riscv_vp/objects.mk b/platform/riscv_vp/objects.mk
new file mode 100644
index 00000000..ca1f50a9
--- /dev/null
+++ b/platform/riscv_vp/objects.mk
@@ -0,0 +1,99 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2019 Western Digital Corporation or its affiliates.
+#
+
+# Compiler pre-processor flags
+platform-cppflags-y =
+
+# C Compiler and assembler flags.
+platform-cflags-y =
+platform-asflags-y =
+
+# Linker flags: additional libraries and object files that the platform
+# code needs can be added here
+platform-ldflags-y =
+
+#
+# Command for platform specific "make run"
+# Useful for development and debugging on plaftform simulator (such as QEMU)
+#
+# platform-runcmd = your_platform_run.sh
+
+#
+# Platform RISC-V XLEN, ABI, ISA and Code Model configuration.
+# These are optional parameters but platforms can optionaly provide it.
+# Some of these are guessed based on GCC compiler capabilities
+#
+PLATFORM_RISCV_XLEN = 64
+PLATFORM_RISCV_ABI = lp64d
+PLATFORM_RISCV_ISA = rv64imafdc_zicsr_zifencei
+PLATFORM_RISCV_CODE_MODEL = medany
+
+# Space separated list of object file names to be compiled for the platform
+platform-objs-y += platform.o
+
+#
+# If the platform support requires a builtin device tree file, the name of
+# the device tree compiled file should be specified here. The device tree
+# source file be in the form
.dts
+#
+# platform-objs-y += .o
+
+# Optional parameter for path to external FDT
+# FW_FDT_PATH="path to platform flattened device tree file"
+
+#
+# Dynamic firmware configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_DYNAMIC=n
+
+#
+# Jump firmware configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_JUMP=n
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+# ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# FW_JUMP_OFFSET=0x400000
+# else
+# FW_JUMP_OFFSET=0x200000
+# endif
+# FW_JUMP_FDT_OFFSET=0x2200000
+#
+# You can use fixed address for jump firmware as an alternative option.
+# SBI will prefer "_ADDR" if both "_ADDR" and "_OFFSET" are
+# defined
+# ifeq ($(PLATFORM_RISCV_XLEN), 32)
+# FW_JUMP_ADDR=0x80400000
+# else
+# FW_JUMP_ADDR=0x80200000
+# endif
+# FW_JUMP_FDT_ADDR=0x82200000
+
+#
+# Firmware with payload configuration.
+# Optional parameters are commented out. Uncomment and define these parameters
+# as needed.
+#
+FW_PAYLOAD=y
+# This needs to be 4MB aligned for 32-bit support
+# This needs to be 2MB aligned for 64-bit support
+ifeq ($(PLATFORM_RISCV_XLEN), 32)
+FW_PAYLOAD_OFFSET=0x400000
+else
+FW_PAYLOAD_OFFSET=0x200000
+endif
+# FW_PAYLOAD_ALIGN=0x1000
+# FW_PAYLOAD_PATH="path to next boot stage binary image file"
+# FW_PAYLOAD_FDT_OFFSET=0x2200000
+#
+# You can use fixed address for payload firmware as an alternative option.
+# SBI will prefer "FW_PAYLOAD_FDT_ADDR" if both "FW_PAYLOAD_FDT_OFFSET"
+# and "FW_PAYLOAD_FDT_ADDR" are defined.
+# FW_PAYLOAD_FDT_ADDR=0x82200000
diff --git a/platform/riscv_vp/platform.c b/platform/riscv_vp/platform.c
new file mode 100644
index 00000000..f61f3523
--- /dev/null
+++ b/platform/riscv_vp/platform.c
@@ -0,0 +1,178 @@
+#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
+};