From 1bfc32e91a48065b47edc39c0dd3dd38bbfd7495 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Thu, 27 Jun 2024 11:29:15 +0200 Subject: [PATCH] Working OpenSBI 1.2 --- alveo-uart-sbi-hack.patch | 438 +++++++++++++++++++++++++++++++++++ lagarto-ox.nix | 64 ++++- ox-alveo-platform-plic.patch | 166 +++++++++++++ ox-alveo-platform.patch | 148 ++++++++++++ ox-plic.dts | 143 ++++++++++++ ox.dts | 58 +++++ 6 files changed, 1013 insertions(+), 4 deletions(-) create mode 100644 alveo-uart-sbi-hack.patch create mode 100644 ox-alveo-platform-plic.patch create mode 100644 ox-alveo-platform.patch create mode 100644 ox-plic.dts create mode 100644 ox.dts diff --git a/alveo-uart-sbi-hack.patch b/alveo-uart-sbi-hack.patch new file mode 100644 index 0000000..7de4768 --- /dev/null +++ b/alveo-uart-sbi-hack.patch @@ -0,0 +1,438 @@ +diff --git a/include/sbi_utils/serial/alveo_uart.h b/include/sbi_utils/serial/alveo_uart.h +new file mode 100644 +index 0000000..0b6408c +--- /dev/null ++++ b/include/sbi_utils/serial/alveo_uart.h +@@ -0,0 +1,13 @@ ++/* ++ * SPDX-License-Identifier: BSD-2-Clause ++ */ ++ ++#ifndef __SERIAL_ALVEO_UART_H__ ++#define __SERIAL_ALVEO_UART_H__ ++ ++#include ++ ++int alveo_uart_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift, ++ u32 reg_width, u32 reg_offset); ++ ++#endif +diff --git a/lib/utils/serial/Kconfig b/lib/utils/serial/Kconfig +index e3589ca..b754c7c 100644 +--- a/lib/utils/serial/Kconfig ++++ b/lib/utils/serial/Kconfig +@@ -84,6 +84,10 @@ config SERIAL_UART8250 + bool "8250 UART support" + default n + ++config SERIAL_ALVEO_UART ++ bool "ALveo UART support" ++ default n ++ + config SERIAL_XILINX_UARTLITE + bool "Xilinx UART Lite support" + default n +diff --git a/lib/utils/serial/alveo_uart.c b/lib/utils/serial/alveo_uart.c +new file mode 100644 +index 0000000..a351741 +--- /dev/null ++++ b/lib/utils/serial/alveo_uart.c +@@ -0,0 +1,123 @@ ++/* ++ * SPDX-License-Identifier: BSD-2-Clause ++ */ ++ ++#include ++#include ++#include ++ ++/* clang-format off */ ++ ++#define UART_RBR_OFFSET 0 /* In: Recieve Buffer Register */ ++#define UART_THR_OFFSET 0 /* Out: Transmitter Holding Register */ ++#define UART_DLL_OFFSET 0 /* Out: Divisor Latch Low */ ++#define UART_IER_OFFSET 1 /* I/O: Interrupt Enable Register */ ++#define UART_DLM_OFFSET 1 /* Out: Divisor Latch High */ ++#define UART_FCR_OFFSET 2 /* Out: FIFO Control Register */ ++#define UART_IIR_OFFSET 2 /* I/O: Interrupt Identification Register */ ++#define UART_LCR_OFFSET 3 /* Out: Line Control Register */ ++#define UART_MCR_OFFSET 4 /* Out: Modem Control Register */ ++#define UART_LSR_OFFSET 5 /* In: Line Status Register */ ++#define UART_MSR_OFFSET 6 /* In: Modem Status Register */ ++#define UART_SCR_OFFSET 7 /* I/O: Scratch Register */ ++#define UART_MDR1_OFFSET 8 /* I/O: Mode Register */ ++ ++#define UART_LSR_FIFOE 0x80 /* Fifo error */ ++#define UART_LSR_TEMT 0x40 /* Transmitter empty */ ++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ ++#define UART_LSR_BI 0x10 /* Break interrupt indicator */ ++#define UART_LSR_FE 0x08 /* Frame error indicator */ ++#define UART_LSR_PE 0x04 /* Parity error indicator */ ++#define UART_LSR_OE 0x02 /* Overrun error indicator */ ++#define UART_LSR_DR 0x01 /* Receiver data ready */ ++#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */ ++ ++/* clang-format on */ ++ ++static volatile char *alveo_uart_base; ++static u32 alveo_uart_in_freq; ++static u32 alveo_uart_baudrate; ++static u32 alveo_uart_reg_width; ++static u32 alveo_uart_reg_shift; ++ ++static u32 get_reg(u32 num) ++{ ++ u32 offset = num << alveo_uart_reg_shift; ++ ++ if (alveo_uart_reg_width == 1) ++ return readb(alveo_uart_base + offset); ++ else if (alveo_uart_reg_width == 2) ++ return readw(alveo_uart_base + offset); ++ else ++ return readl(alveo_uart_base + offset); ++} ++ ++static void set_reg(u32 num, u32 val) ++{ ++ u32 offset = num << alveo_uart_reg_shift; ++ ++ if (alveo_uart_reg_width == 1) ++ writeb(val, alveo_uart_base + offset); ++ else if (alveo_uart_reg_width == 2) ++ writew(val, alveo_uart_base + offset); ++ else ++ writel(val, alveo_uart_base + offset); ++} ++ ++static void alveo_uart_putc(char ch) ++{ ++ while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_TEMT)) ++ ; ++ ++ set_reg(UART_THR_OFFSET, ch); ++} ++ ++static int alveo_uart_getc(void) ++{ ++ if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR) ++ return get_reg(UART_RBR_OFFSET); ++ return -1; ++} ++ ++static struct sbi_console_device alveo_uart_console = { ++ .name = "alveo_uart", ++ .console_putc = alveo_uart_putc, ++ .console_getc = alveo_uart_getc ++}; ++ ++int alveo_uart_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift, ++ u32 reg_width, u32 reg_offset) ++{ ++ u16 bdiv = 0; ++ ++ alveo_uart_base = (volatile char *)base + reg_offset; ++ alveo_uart_reg_shift = reg_shift; ++ alveo_uart_reg_width = reg_width; ++ alveo_uart_in_freq = in_freq; ++ alveo_uart_baudrate = baudrate; ++ ++ if (alveo_uart_baudrate) { ++ bdiv = alveo_uart_in_freq / (16 * alveo_uart_baudrate); ++ } ++ ++ /* Disable all interrupts */ ++ set_reg(UART_IER_OFFSET, 0x00); ++ /* Enable DLAB */ ++ set_reg(UART_LCR_OFFSET, 0x80); ++ ++ if (bdiv) { ++ /* Set divisor low byte */ ++ set_reg(UART_DLL_OFFSET, bdiv & 0xff); ++ /* Set divisor high byte */ ++ set_reg(UART_DLM_OFFSET, (bdiv >> 8) & 0xff); ++ } ++ ++ /* 8 bits, no parity, one stop bit */ ++ set_reg(UART_LCR_OFFSET, 0x03); // previous was 0x0B ++ /* Disable all interrupts*/ ++ set_reg(UART_IER_OFFSET, 0x00); ++ ++ sbi_console_set_device(&alveo_uart_console); ++ ++ return 0; ++} +diff --git a/lib/utils/serial/objects.mk b/lib/utils/serial/objects.mk +index 1e6bd2e..0268bdf 100644 +--- a/lib/utils/serial/objects.mk ++++ b/lib/utils/serial/objects.mk +@@ -44,5 +44,6 @@ libsbiutils-objs-$(CONFIG_SERIAL_SHAKTI) += serial/shakti-uart.o + libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o + libsbiutils-objs-$(CONFIG_SERIAL_LITEX) += serial/litex-uart.o + libsbiutils-objs-$(CONFIG_SERIAL_UART8250) += serial/uart8250.o ++libsbiutils-objs-$(CONFIG_SERIAL_ALVEO_UART) += serial/alveo_uart.o + libsbiutils-objs-$(CONFIG_SERIAL_XILINX_UARTLITE) += serial/xlnx-uartlite.o + libsbiutils-objs-$(CONFIG_SERIAL_SEMIHOSTING) += serial/semihosting.o +diff --git a/platform/fpga/sargantana_alveo/Kconfig b/platform/fpga/sargantana_alveo/Kconfig +new file mode 100644 +index 0000000..bf3e7e6 +--- /dev/null ++++ b/platform/fpga/sargantana_alveo/Kconfig +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: BSD-2-Clause ++ ++config PLATFORM_SARGANTANA_ALVEO_FPGA ++ bool ++ select FDT ++ select IPI_MSWI ++ select IRQCHIP_PLIC ++ select SERIAL_ALVEO_UART ++ select TIMER_MTIMER ++ default y +diff --git a/platform/fpga/sargantana_alveo/configs/defconfig b/platform/fpga/sargantana_alveo/configs/defconfig +new file mode 100644 +index 0000000..e69de29 +diff --git a/platform/fpga/sargantana_alveo/objects.mk b/platform/fpga/sargantana_alveo/objects.mk +new file mode 100644 +index 0000000..d444abe +--- /dev/null ++++ b/platform/fpga/sargantana_alveo/objects.mk +@@ -0,0 +1,87 @@ ++# ++# 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 = rv64imafd ++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 ++ ++# Firmware load address configuration. This is mandatory. ++FW_TEXT_START=0x80000000 ++ ++# 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_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_ADDR=0x82200000 +diff --git a/platform/fpga/sargantana_alveo/platform.c b/platform/fpga/sargantana_alveo/platform.c +new file mode 100644 +index 0000000..a359b34 +--- /dev/null ++++ b/platform/fpga/sargantana_alveo/platform.c +@@ -0,0 +1,146 @@ ++/* ++ * SPDX-License-Identifier: BSD-2-Clause ++ * ++ * Copyright (c) 2019 Western Digital Corporation or its affiliates. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * Include these files as needed. ++ * See objects.mk SARGANTANA_ALVEO_xxx configuration parameters. ++ */ ++ ++#include ++#include ++ ++#define SARGANTANA_ALVEO_HART_COUNT 1 ++ ++#define SARGANTANA_ALVEO_UART_BASE_ADDR 0x40000000 ++#define SARGANTANA_ALVEO_UART_OFFSET 0x1000 ++//#define SARGANTANA_ALVEO_UART_ADDR SARGANTANA_ALVEO_UART_BASE_ADDR + SARGANTANA_ALVEO_UART_XLNX_OFFSET ++#define SARGANTANA_ALVEO_UART_INPUT_FREQ 50000000 ++#define SARGANTANA_ALVEO_UART_BAUDRATE 115200 ++ ++#define SARGANTANA_ALVEO_TIMER_BASE 0x40170000 ++#define ADDR_TIME_L 0x0u // 32 lower bits of the time register ++#define ADDR_TIME_H 0x1u // 32 higher bits of the time register ++#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator ++#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator ++ ++volatile uint32_t *timer_base_ptr = (uint32_t *)(SARGANTANA_ALVEO_TIMER_BASE); ++ ++/* ++ * Platform early initialization. ++ */ ++static int sargantana_alveo_early_init(bool cold_boot) ++{ ++ return 0; ++} ++ ++/* ++ * Platform final initialization. ++ */ ++static int sargantana_alveo_final_init(bool cold_boot) ++{ ++ return 0; ++} ++ ++/* ++ * Initialize the platform console. ++ */ ++static int sargantana_alveo_console_init(void) ++{ ++ return alveo_uart_init(SARGANTANA_ALVEO_UART_BASE_ADDR, ++ SARGANTANA_ALVEO_UART_INPUT_FREQ, ++ SARGANTANA_ALVEO_UART_BAUDRATE, ++ 2, 4, ++ SARGANTANA_ALVEO_UART_OFFSET); ++} ++ ++/* ++ * Initialize the platform interrupt controller for current HART. ++ */ ++static int sargantana_alveo_irqchip_init(bool cold_boot) ++{ ++ u32 hartid = current_hartid(); ++ return hartid; ++} ++ ++/* ++ * Initialize IPI for current HART. ++ */ ++static int sargantana_alveo_ipi_init(bool cold_boot) ++{ ++ return 0; ++} ++ ++/* ++ * Get platform timer value. ++ */ ++static u64 sargantana_alveo_timer_value(void) ++{ ++ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L); ++} ++ ++/* ++ * Start platform timer event for current HART. ++ */ ++static void sargantana_alveo_timer_event_start(u64 next_event) ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event; ++} ++ ++/* ++ * Stop platform timer event for current HART. ++ */ ++static void sargantana_alveo_timer_event_stop(void) ++{ ++ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++} ++ ++static struct sbi_timer_device mtimer = { ++ .name = "generic_timer", // TODO Where the timer comes from? I would prefer a better name :p ++ .timer_freq = SARGANTANA_ALVEO_UART_INPUT_FREQ, ++ .timer_value = sargantana_alveo_timer_value, ++ .timer_event_start = sargantana_alveo_timer_event_start, ++ .timer_event_stop = sargantana_alveo_timer_event_stop ++}; ++ ++/* ++ * Initialize platform timer for current HART. ++ */ ++static int sargantana_alveo_timer_init(bool cold_boot) ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++ sbi_timer_set_device(&mtimer); ++ return 0; ++} ++ ++/* ++ * Platform descriptor. ++ */ ++const struct sbi_platform_operations sargantana_alveo_ops = { ++ .early_init = sargantana_alveo_early_init, ++ .final_init = sargantana_alveo_final_init, ++ .console_init = sargantana_alveo_console_init, ++ .irqchip_init = sargantana_alveo_irqchip_init, ++ .ipi_init = sargantana_alveo_ipi_init, ++ .timer_init = sargantana_alveo_timer_init ++}; ++const struct sbi_platform platform = { ++ .opensbi_version = OPENSBI_VERSION, ++ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01), ++ .name = "Sargantana (for Xilinx Alveo FPGA)", ++ .features = SBI_PLATFORM_DEFAULT_FEATURES, ++ .hart_count = SARGANTANA_ALVEO_HART_COUNT, ++ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, ++ .platform_ops_addr = (unsigned long)&sargantana_alveo_ops ++}; diff --git a/lagarto-ox.nix b/lagarto-ox.nix index 51359ba..5f4442b 100644 --- a/lagarto-ox.nix +++ b/lagarto-ox.nix @@ -5,6 +5,13 @@ "${modulesPath}/installer/sd-card/sd-image.nix" ]; + # No need, Lagarto OX has support for rv64gc. + #nixpkgs.crossSystem = { + # system = "riscv64-linux"; + # gcc.arch = "rv64imafd"; + # gcc.tune = "rv64imafd"; + #}; + #boot.kernelPackages = pkgs.linuxPackages_latest; boot = { kernelPatches = [ @@ -121,12 +128,61 @@ echo 'booti ''${kernel_addr_r} ''${ramdisk_addr_r}:''${ramdisk_size} ''${fdtcontroladdr}' >> $out ''; - opensbi = prev.opensbi.overrideAttrs (old: { - makeFlags = old.makeFlags ++ [ - "PLATFORM=fpga/openpiton" + # Lagarto OX doesn't work with newer versions of OpenSBI (1.3, 1.4), not + # sure why. + opensbi = prev.opensbi.overrideAttrs (old: rec { + version = "1.2"; # ok + #version = "1.3"; # bad + #version = "1.4"; # bad + src = prev.fetchFromGitHub { + owner = "riscv-software-src"; + repo = "opensbi"; + rev = "v${version}"; + hash = "sha256-Zcl+SE2nySMycV/ozsl4AvGipRsMblA5mt3oVZ81Z44="; #1.2 + #hash = "sha256-Dr16fVUGLYGnGYHkjAyqpJxt8p95F0CJIU9ESGWKGWo="; #1.3 + #hash = "sha256-T8ZeAzjM9aeTXitjE7s+m+jjGGtDo2jK1qO5EuKiVLU="; #1.4 + }; + #NIX_DEBUG=5; + # Compile dts to dtb form + nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ prev.buildPackages.dtc ]; + dtsFile = ./ox-plic.dts; + preBuild = '' + dtc -O dtb -o ox.dtb $dtsFile + ''; + makeFlags = [ + "PLATFORM=fpga/ox_alveo" + #"CONFIG_SBI_ECALL_RFENCE=n" + #"PLATFORM_RISCV_ISA=rv64imafd" # No compressed instructions + #"PLATFORM_RISCV_ISA=rv64g" # No compressed instructions + #"PLATFORM_RISCV_ABI=lp64d" "FW_PAYLOAD_PATH=${final.uboot}/u-boot-nodtb.bin" + "FW_FDT_PATH=ox.dtb" ]; - patches = [ ./opensbi-lagarto-hun.patch ]; + patches = [ ./ox-alveo-platform-plic.patch ]; }); +# opensbi = prev.opensbi.overrideAttrs (old: { +# #NIX_DEBUG=5; +# # Compile dts to dtb form +# #nativeBuildInputs = (old.nativeBuildInputs or []) ++ [ prev.buildPackages.dtc ]; +# #preBuild = '' +# # dtc -O dtb -o ox.dtb ${./ox.dts} +# #''; +# makeFlags = old.makeFlags ++ [ +# "PLATFORM=fpga/sargantana_alveo" +# #"PLATFORM_RISCV_ISA=rv64imafd" # No compressed instructions +# "PLATFORM_RISCV_ISA=rv64g" # No compressed instructions +# #"PLATFORM_RISCV_ABI=lp64d" +# "FW_PAYLOAD_PATH=${final.uboot}/u-boot-nodtb.bin" +# #"FW_FDT_PATH=ox.dtb" +# ]; +# patches = [ ./alveo-uart-sbi-hack.patch ]; +# }); +# opensbi = prev.opensbi.overrideAttrs (old: { +# makeFlags = old.makeFlags ++ [ +# "PLATFORM=fpga/openpiton" +# "FW_PAYLOAD_PATH=${final.uboot}/u-boot-nodtb.bin" +# ]; +# patches = [ ./opensbi-lagarto-hun.patch ]; +# }); }) ]; } diff --git a/ox-alveo-platform-plic.patch b/ox-alveo-platform-plic.patch new file mode 100644 index 0000000..d906a6f --- /dev/null +++ b/ox-alveo-platform-plic.patch @@ -0,0 +1,166 @@ +diff --git a/platform/fpga/ox_alveo/Kconfig b/platform/fpga/ox_alveo/Kconfig +new file mode 100644 +index 0000000..bf3e7e6 +--- /dev/null ++++ b/platform/fpga/ox_alveo/Kconfig +@@ -0,0 +1,5 @@ ++config PLATFORM_OX_ALVEO_FPGA ++ bool ++ select SERIAL_UART8250 ++ select IRQCHIP_PLIC ++ default y +diff --git a/platform/fpga/ox_alveo/configs/defconfig b/platform/fpga/ox_alveo/configs/defconfig +new file mode 100644 +index 0000000..e69de29 +diff --git a/platform/fpga/ox_alveo/objects.mk b/platform/fpga/ox_alveo/objects.mk +new file mode 100644 +index 0000000..d444abe +--- /dev/null ++++ b/platform/fpga/ox_alveo/objects.mk +@@ -0,0 +1,19 @@ ++platform-cppflags-y = ++platform-cflags-y = ++platform-asflags-y = ++platform-ldflags-y = ++PLATFORM_RISCV_XLEN = 64 ++PLATFORM_RISCV_ABI = lp64d ++PLATFORM_RISCV_ISA = rv64g ++PLATFORM_RISCV_CODE_MODEL = medany ++ ++platform-objs-y += platform.o ++ ++FW_TEXT_START=0x80000000 ++ ++FW_DYNAMIC=n ++FW_JUMP=n ++FW_PAYLOAD=y ++ ++FW_PAYLOAD_OFFSET=0x200000 ++FW_PAYLOAD_ALIGN=0x1000 +diff --git a/platform/fpga/ox_alveo/platform.c b/platform/fpga/ox_alveo/platform.c +new file mode 100644 +index 0000000..a359b34 +--- /dev/null ++++ b/platform/fpga/ox_alveo/platform.c +@@ -0,0 +1,121 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OX_ALVEO_HART_COUNT 1 ++ ++#define OX_ALVEO_UART_BASE_ADDR 0x40000000 ++#define OX_ALVEO_UART_OFFSET 0x1000 ++#define OX_ALVEO_UART_INPUT_FREQ 50000000 ++#define OX_ALVEO_UART_BAUDRATE 115200 ++#define OX_ALVEO_PLIC_ADDR 0x40800000 ++#define OX_ALVEO_PLIC_NUM_SOURCES 3 ++ ++#define OX_ALVEO_TIMER_BASE 0x40170000 ++#define ADDR_TIME_L 0x0u // 32 lower bits of the time register ++#define ADDR_TIME_H 0x1u // 32 higher bits of the time register ++#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator ++#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator ++ ++volatile uint32_t *timer_base_ptr = (uint32_t *)(OX_ALVEO_TIMER_BASE); ++ ++static struct plic_data plic = { ++ .addr = OX_ALVEO_PLIC_ADDR, ++ .num_src = OX_ALVEO_PLIC_NUM_SOURCES, ++}; ++ ++static int ox_alveo_early_init(bool cold_boot) // Platform early initialization. ++{ ++ return 0; ++} ++ ++static int ox_alveo_final_init(bool cold_boot) // Platform final initialization. ++{ ++ return 0; ++} ++ ++static int ox_alveo_console_init(void) // Initialize the platform console. ++{ ++ return uart8250_init(OX_ALVEO_UART_BASE_ADDR, ++ OX_ALVEO_UART_INPUT_FREQ, ++ OX_ALVEO_UART_BAUDRATE, ++ 2, 4, ++ OX_ALVEO_UART_OFFSET); ++} ++ ++static int ox_alveo_irqchip_init(bool cold_boot) // Initialize the platform interrupt controller for current HART. ++{ ++ u32 hartid = current_hartid(); ++ int ret; ++ ++ /* Example if the generic PLIC driver is used */ ++ if (cold_boot) { ++ ret = plic_cold_irqchip_init(&plic); ++ if (ret) ++ return ret; ++ } ++ ++ return plic_warm_irqchip_init(&plic, 2 * hartid, -1); ++} ++ ++static int ox_alveo_ipi_init(bool cold_boot) // Initialize IPI for current HART. ++{ ++ return 0; ++} ++ ++static u64 ox_alveo_timer_value(void) // Get platform timer value. ++{ ++ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L); ++} ++ ++static void ox_alveo_timer_event_start(u64 next_event) // Start platform timer event for current HART. ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event; ++} ++ ++static void ox_alveo_timer_event_stop(void) // Stop platform timer event for current HART. ++{ ++ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++} ++ ++static struct sbi_timer_device mtimer = { ++ .name = "axi_timer", ++ .timer_freq = OX_ALVEO_UART_INPUT_FREQ, ++ .timer_value = ox_alveo_timer_value, ++ .timer_event_start = ox_alveo_timer_event_start, ++ .timer_event_stop = ox_alveo_timer_event_stop ++}; ++ ++static int ox_alveo_timer_init(bool cold_boot) // Initialize platform timer for current HART. ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++ sbi_timer_set_device(&mtimer); ++ return 0; ++} ++ ++const struct sbi_platform_operations ox_alveo_ops = { // Platform descriptor. ++ .early_init = ox_alveo_early_init, ++ .final_init = ox_alveo_final_init, ++ .console_init = ox_alveo_console_init, ++ .irqchip_init = ox_alveo_irqchip_init, ++ .ipi_init = ox_alveo_ipi_init, ++ .timer_init = ox_alveo_timer_init ++}; ++ ++const struct sbi_platform platform = { ++ .opensbi_version = OPENSBI_VERSION, ++ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01), ++ .name = "ox (Rodrigo NixOS version)", ++ .features = SBI_PLATFORM_DEFAULT_FEATURES, ++ .hart_count = OX_ALVEO_HART_COUNT, ++ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, ++ .platform_ops_addr = (unsigned long)&ox_alveo_ops ++}; diff --git a/ox-alveo-platform.patch b/ox-alveo-platform.patch new file mode 100644 index 0000000..347d0d4 --- /dev/null +++ b/ox-alveo-platform.patch @@ -0,0 +1,148 @@ +diff --git a/platform/fpga/ox_alveo/Kconfig b/platform/fpga/ox_alveo/Kconfig +new file mode 100644 +index 0000000..bf3e7e6 +--- /dev/null ++++ b/platform/fpga/ox_alveo/Kconfig +@@ -0,0 +1,4 @@ ++config PLATFORM_OX_ALVEO_FPGA ++ bool ++ select SERIAL_UART8250 ++ default y +diff --git a/platform/fpga/ox_alveo/configs/defconfig b/platform/fpga/ox_alveo/configs/defconfig +new file mode 100644 +index 0000000..e69de29 +diff --git a/platform/fpga/ox_alveo/objects.mk b/platform/fpga/ox_alveo/objects.mk +new file mode 100644 +index 0000000..d444abe +--- /dev/null ++++ b/platform/fpga/ox_alveo/objects.mk +@@ -0,0 +1,19 @@ ++platform-cppflags-y = ++platform-cflags-y = ++platform-asflags-y = ++platform-ldflags-y = ++PLATFORM_RISCV_XLEN = 64 ++PLATFORM_RISCV_ABI = lp64d ++PLATFORM_RISCV_ISA = rv64imafd ++PLATFORM_RISCV_CODE_MODEL = medany ++ ++platform-objs-y += platform.o ++ ++FW_TEXT_START=0x80000000 ++ ++FW_DYNAMIC=n ++FW_JUMP=n ++FW_PAYLOAD=y ++ ++FW_PAYLOAD_OFFSET=0x200000 ++FW_PAYLOAD_ALIGN=0x1000 +diff --git a/platform/fpga/ox_alveo/platform.c b/platform/fpga/ox_alveo/platform.c +new file mode 100644 +index 0000000..a359b34 +--- /dev/null ++++ b/platform/fpga/ox_alveo/platform.c +@@ -0,0 +1,104 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define OX_ALVEO_HART_COUNT 1 ++ ++#define OX_ALVEO_UART_BASE_ADDR 0x40000000 ++#define OX_ALVEO_UART_OFFSET 0x1000 ++#define OX_ALVEO_UART_INPUT_FREQ 50000000 ++#define OX_ALVEO_UART_BAUDRATE 115200 ++ ++#define OX_ALVEO_TIMER_BASE 0x40170000 ++#define ADDR_TIME_L 0x0u // 32 lower bits of the time register ++#define ADDR_TIME_H 0x1u // 32 higher bits of the time register ++#define ADDR_TIMECMP_L 0x2u // 32 lower bits of the time comparator ++#define ADDR_TIMECMP_H 0x3u // 32 higher bits of the time comparator ++ ++volatile uint32_t *timer_base_ptr = (uint32_t *)(OX_ALVEO_TIMER_BASE); ++ ++static int ox_alveo_early_init(bool cold_boot) // Platform early initialization. ++{ ++ return 0; ++} ++ ++static int ox_alveo_final_init(bool cold_boot) // Platform final initialization. ++{ ++ return 0; ++} ++ ++static int ox_alveo_console_init(void) // Initialize the platform console. ++{ ++ return uart8250_init(OX_ALVEO_UART_BASE_ADDR, ++ OX_ALVEO_UART_INPUT_FREQ, ++ OX_ALVEO_UART_BAUDRATE, ++ 2, 4, ++ OX_ALVEO_UART_OFFSET); ++} ++ ++static int ox_alveo_irqchip_init(bool cold_boot) // Initialize the platform interrupt controller for current HART. ++{ ++ u32 hartid = current_hartid(); ++ return hartid; ++} ++ ++static int ox_alveo_ipi_init(bool cold_boot) // Initialize IPI for current HART. ++{ ++ return 0; ++} ++ ++static u64 ox_alveo_timer_value(void) // Get platform timer value. ++{ ++ return ((u64)*(timer_base_ptr + ADDR_TIME_H) << 32) + *(timer_base_ptr + ADDR_TIME_L); ++} ++ ++static void ox_alveo_timer_event_start(u64 next_event) // Start platform timer event for current HART. ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = next_event >> 32; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = next_event; ++} ++ ++static void ox_alveo_timer_event_stop(void) // Stop platform timer event for current HART. ++{ ++ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++} ++ ++static struct sbi_timer_device mtimer = { ++ .name = "axi_timer", ++ .timer_freq = OX_ALVEO_UART_INPUT_FREQ, ++ .timer_value = ox_alveo_timer_value, ++ .timer_event_start = ox_alveo_timer_event_start, ++ .timer_event_stop = ox_alveo_timer_event_stop ++}; ++ ++static int ox_alveo_timer_init(bool cold_boot) // Initialize platform timer for current HART. ++{ ++ *(timer_base_ptr + ADDR_TIMECMP_H) = 0; ++ *(timer_base_ptr + ADDR_TIMECMP_L) = 0; ++ sbi_timer_set_device(&mtimer); ++ return 0; ++} ++ ++const struct sbi_platform_operations ox_alveo_ops = { // Platform descriptor. ++ .early_init = ox_alveo_early_init, ++ .final_init = ox_alveo_final_init, ++ .console_init = ox_alveo_console_init, ++ .irqchip_init = ox_alveo_irqchip_init, ++ .ipi_init = ox_alveo_ipi_init, ++ .timer_init = ox_alveo_timer_init ++}; ++ ++const struct sbi_platform platform = { ++ .opensbi_version = OPENSBI_VERSION, ++ .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01), ++ .name = "ox (for Xilinx Alveo FPGA)", ++ .features = SBI_PLATFORM_DEFAULT_FEATURES, ++ .hart_count = OX_ALVEO_HART_COUNT, ++ .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE, ++ .platform_ops_addr = (unsigned long)&ox_alveo_ops ++}; diff --git a/ox-plic.dts b/ox-plic.dts new file mode 100644 index 0000000..c91c375 --- /dev/null +++ b/ox-plic.dts @@ -0,0 +1,143 @@ +/dts-v1/; +/ { + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + compatible = "riscv,rv64i"; + model = "Barcelona Supercomputing Center - Lagarto Ox"; + chosen { + bootargs = "earlyprintk ignore_loglevel earlycon=sbi console=hvc0 root=/dev/pmem0p1 ro init=/bin/bash"; + }; + cpus { + #address-cells = <0x00000001>; + #size-cells = <0x00000000>; + timebase-frequency = <0x0000c350>; + cpu@0 { + clock-frequency = <0x02FAF080>; + device_type = "cpu"; + reg = <0x00000000>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafd"; + mmu-type = "riscv,sv39"; + tlb-split; + L3: interrupt-controller { + #interrupt-cells = <0x00000001>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + }; + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0x00000000 0x77e00000>; + }; + reserved-memory { + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + ranges; + eth_pool: dma_pool@60000000 { + reg = <0x00000000 0x60000000 0x00000000 0x10000000>; + compatible = "shared-dma-pool"; + }; + onic_pool: dma_pool@70000000 { + reg = <0x00000000 0x70000000 0x00000000 0x10000000>; + compatible = "shared-dma-pool"; + }; + }; + eth0_clk: eth0_clk { + compatible = "fixed-clock"; + #clock-cells = <0x00000000>; + clock-frequency = <0x09502f90>; + }; + pmem@1bff00000 { + volatile; + compatible = "pmem-region"; + reg = <0x00000001 0xbff00000 0x00000000 0xc0100000>; + }; + pmem2@1b7f00000 { + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + volatile; + compatible = "pmem-region"; + reg = <0x00000001 0xb7f00000 0x00000000 0x08000000>; + }; + pmem3@f7e00000 { + volatile; + compatible = "pmem-region"; + reg = <0x00000000 0xf7e00000 0x00000000 0xc0100000>; + }; + soc { + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + compatible = "BSC,Lagarto-bare-soc", "simple-bus"; + ranges; + serial@40001000 { + compatible = "ns16750"; + reg = <0x00000000 0x40001000 0x00000000 0x00001000>; + interrupts = <0x00000000>; + port-number = <0x00000000>; + reg-shift = <0x00000002>; + clock-frequency = <0x02FAF080>; + current-speed = <0x0001c200>; + status = "okay"; + }; + ethernet0 { + xlnx,rxmem = <0x000005f2>; + carv,mtu = <0x000005dc>; + carv,no-mac; + device_type = "network"; + local-mac-address = [02 05 00 01 00 05]; + axistream-connected = <0x000000fe>; + compatible = "xlnx,xxv-ethernet-1.0-carv"; + memory-region = <ð_pool>; + }; + dma@40400000 { + xlnx,include-dre; + phandle = <0x000000fe>; + #dma-cells = <0x00000001>; + compatible = "xlnx,axi-dma-1.00.a"; + clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk", "m_axi_sg_aclk"; + clocks = <ð0_clk>, <ð0_clk>, <ð0_clk>, <ð0_clk>; + reg = <0x00000000 0x40400000 0x00000000 0x00400000>; + interrupt-names = "mm2s_introut", "s2mm_introut"; + interrupt-parent = <&PLIC0>; + interrupts = <0x00000002 0x00000003>; + xlnx,addrwidth = <0x00000028>; + xlnx,include-sg; + xlnx,sg-length-width = <0x00000017>; + dma-channel@40400000 { + compatible = "xlnx,axi-dma-mm2s-channel"; + dma-channels = <0x00000000>; + interrupts = <0x00000002>; + xlnx,datawidth = <0x00000040>; + xlnx,device-id = <0x00000000>; + xlnx,include-dre; + }; + dma-channel@40400030 { + compatible = "xlnx,axi-dma-s2mm-channel"; + dma-channels = <0x00000001>; + interrupts = <0x00000003>; + xlnx,datawidth = <0x00000040>; + xlnx,device-id = <0x00000000>; + xlnx,include-dre; + }; + }; + clint@40002000 { + reg-names = "control"; + interrupts-extended = <0x00000004 0x00000003 0x00000004 0x00000007 0x00000005 0x00000003 0x00000005 0x00000007 0x00000006 0x00000003 0x00000006 0x00000007 0x00000007 0x00000003 0x00000007 0x00000007>; + compatible = "riscv,clint0"; + #interrupt-cells = <0x00000001>; + reg = <0x00000000 0x40002000 0x00000000 0x000c0000>; + }; + PLIC0: plic@40800000 { + #interrupt-cells = <1>; + compatible = "riscv,plic0"; + interrupt-controller; + interrupts-extended = <&L3 3 &L3 7>; + reg = < 0x00000000 0x40800000 0x00000000 0x00400000>; + riscv,ndev = <0x00000003>; + riscv,max-priority = <0x00000007>; + }; + }; + +}; diff --git a/ox.dts b/ox.dts new file mode 100644 index 0000000..8fd11b8 --- /dev/null +++ b/ox.dts @@ -0,0 +1,58 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "riscv,rv64i"; + model = "Barcelona Supercomputing Center - OX"; + chosen { + bootargs = "earlycon=sbi console=ttyS0,115200n8"; + }; + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <50000>; // 32.768 kHz + CPU0: cpu@0 { + //clock-frequency = <25000000>; // 25 MHz + clock-frequency = <50000000>; // 50 MHz + device_type = "cpu"; + reg = <0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafd"; + mmu-type = "riscv,sv39"; + tlb-split; + // HLIC - hart local interrupt controller + CPU0_intc: interrupt-controller { + #address-cells = <1>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + }; + + uart0: serial@40001000 { + compatible = "ns16750"; + //reg = <0x40001000 0x1000>; + reg = <0x00000000 0x40001000 0x00000000 0x00000100>; + interrupts = <0>; + port-number = <0>; + reg-shift = <2>; + reg-io-width = <4>; + clock-frequency = <25000000>; + current-speed = <115200>; + status = "okay"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x40000000>; + }; + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + }; +};