439 lines
13 KiB
Diff
439 lines
13 KiB
Diff
|
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 <sbi/sbi_types.h>
|
||
|
+
|
||
|
+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 <sbi/riscv_io.h>
|
||
|
+#include <sbi/sbi_console.h>
|
||
|
+#include <sbi_utils/serial/alveo_uart.h>
|
||
|
+
|
||
|
+/* 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 <dt file name>.dts
|
||
|
+#
|
||
|
+# platform-objs-y += <dt file name>.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 <sbi/riscv_asm.h>
|
||
|
+#include <sbi/riscv_encoding.h>
|
||
|
+#include <sbi/sbi_const.h>
|
||
|
+#include <sbi/sbi_platform.h>
|
||
|
+
|
||
|
+/*
|
||
|
+ * Include these files as needed.
|
||
|
+ * See objects.mk SARGANTANA_ALVEO_xxx configuration parameters.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sbi_utils/serial/alveo_uart.h>
|
||
|
+#include <sbi/sbi_timer.h>
|
||
|
+
|
||
|
+#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
|
||
|
+};
|