forked from Mirrors/opensbi
platform: Move platform common to lib/utils.
Currently, platform/common contains platform/non-platform specific common minimal drivers and libraries. This is helpful is all platforms are built within opensbi framework. Move them to lib/utils so that any external platform code also can reuse the minimalistic drivers or other common libraries. This patch doesn't introduce any functional changes. Signed-off-by: Atish Patra <atish.patra@wdc.com> Acked-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
11
lib/utils/serial/objects.mk
Normal file
11
lib/utils/serial/objects.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
# Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
#
|
||||
# Authors:
|
||||
# Anup Patel <anup.patel@wdc.com>
|
||||
#
|
||||
|
||||
libsbiutils-objs-$(PLATFORM_SERIAL_UART8250) += serial/uart8250.o
|
||||
libsbiutils-objs-$(PLATFORM_SERIAL_SIFIVE_UART) += serial/sifive-uart.o
|
101
lib/utils/serial/sifive-uart.c
Normal file
101
lib/utils/serial/sifive-uart.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi_utils/serial/sifive-uart.h>
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define UART_REG_TXFIFO 0
|
||||
#define UART_REG_RXFIFO 1
|
||||
#define UART_REG_TXCTRL 2
|
||||
#define UART_REG_RXCTRL 3
|
||||
#define UART_REG_IE 4
|
||||
#define UART_REG_IP 5
|
||||
#define UART_REG_DIV 6
|
||||
|
||||
#define UART_TXFIFO_FULL 0x80000000
|
||||
#define UART_RXFIFO_EMPTY 0x80000000
|
||||
#define UART_RXFIFO_DATA 0x000000ff
|
||||
#define UART_TXCTRL_TXEN 0x1
|
||||
#define UART_RXCTRL_RXEN 0x1
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
static volatile void *uart_base;
|
||||
static u32 uart_in_freq;
|
||||
static u32 uart_baudrate;
|
||||
|
||||
/**
|
||||
* Find minimum divisor divides in_freq to max_target_hz;
|
||||
* Based on uart driver n SiFive FSBL.
|
||||
*
|
||||
* f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
|
||||
* The nearest integer solution requires rounding up as to not exceed max_target_hz.
|
||||
* div = ceil(f_in / f_baud) - 1
|
||||
* = floor((f_in - 1 + f_baud) / f_baud) - 1
|
||||
* This should not overflow as long as (f_in - 1 + f_baud) does not exceed
|
||||
* 2^32 - 1, which is unlikely since we represent frequencies in kHz.
|
||||
*/
|
||||
static inline unsigned int uart_min_clk_divisor(uint64_t in_freq,
|
||||
uint64_t max_target_hz)
|
||||
{
|
||||
uint64_t quotient = (in_freq + max_target_hz - 1) / (max_target_hz);
|
||||
// Avoid underflow
|
||||
if (quotient == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return quotient - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 get_reg(u32 num)
|
||||
{
|
||||
return readl(uart_base + (num * 0x4));
|
||||
}
|
||||
|
||||
static void set_reg(u32 num, u32 val)
|
||||
{
|
||||
writel(val, uart_base + (num * 0x4));
|
||||
}
|
||||
|
||||
void sifive_uart_putc(char ch)
|
||||
{
|
||||
while (get_reg(UART_REG_TXFIFO) & UART_TXFIFO_FULL)
|
||||
;
|
||||
|
||||
set_reg(UART_REG_TXFIFO, ch);
|
||||
}
|
||||
|
||||
int sifive_uart_getc(void)
|
||||
{
|
||||
u32 ret = get_reg(UART_REG_RXFIFO);
|
||||
if (!(ret & UART_RXFIFO_EMPTY))
|
||||
return ret & UART_RXFIFO_DATA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||
{
|
||||
uart_base = (volatile void *)base;
|
||||
uart_in_freq = in_freq;
|
||||
uart_baudrate = baudrate;
|
||||
|
||||
/* Configure baudrate */
|
||||
set_reg(UART_REG_DIV, uart_min_clk_divisor(in_freq, baudrate));
|
||||
/* Disable interrupts */
|
||||
set_reg(UART_REG_IE, 0);
|
||||
/* Enable TX */
|
||||
set_reg(UART_REG_TXCTRL, UART_TXCTRL_TXEN);
|
||||
/* Enable Rx */
|
||||
set_reg(UART_REG_RXCTRL, UART_RXCTRL_RXEN);
|
||||
|
||||
return 0;
|
||||
}
|
121
lib/utils/serial/uart8250.c
Normal file
121
lib/utils/serial/uart8250.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_io.h>
|
||||
#include <sbi_utils/serial/uart8250.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 void *uart8250_base;
|
||||
static u32 uart8250_in_freq;
|
||||
static u32 uart8250_baudrate;
|
||||
static u32 uart8250_reg_width;
|
||||
static u32 uart8250_reg_shift;
|
||||
|
||||
static u32 get_reg(u32 num)
|
||||
{
|
||||
u32 offset = num << uart8250_reg_shift;
|
||||
|
||||
if (uart8250_reg_width == 1)
|
||||
return readb(uart8250_base + offset);
|
||||
else if (uart8250_reg_width == 2)
|
||||
return readw(uart8250_base + offset);
|
||||
else
|
||||
return readl(uart8250_base + offset);
|
||||
}
|
||||
|
||||
static void set_reg(u32 num, u32 val)
|
||||
{
|
||||
u32 offset = num << uart8250_reg_shift;
|
||||
|
||||
if (uart8250_reg_width == 1)
|
||||
writeb(val, uart8250_base + offset);
|
||||
else if (uart8250_reg_width == 2)
|
||||
writew(val, uart8250_base + offset);
|
||||
else
|
||||
writel(val, uart8250_base + offset);
|
||||
}
|
||||
|
||||
void uart8250_putc(char ch)
|
||||
{
|
||||
while ((get_reg(UART_LSR_OFFSET) & UART_LSR_THRE) == 0)
|
||||
;
|
||||
|
||||
set_reg(UART_THR_OFFSET, ch);
|
||||
}
|
||||
|
||||
int uart8250_getc(void)
|
||||
{
|
||||
if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
|
||||
return get_reg(UART_RBR_OFFSET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
|
||||
u32 reg_width)
|
||||
{
|
||||
u16 bdiv;
|
||||
|
||||
uart8250_base = (volatile void *)base;
|
||||
uart8250_reg_shift = reg_shift;
|
||||
uart8250_reg_width = reg_width;
|
||||
uart8250_in_freq = in_freq;
|
||||
uart8250_baudrate = baudrate;
|
||||
|
||||
bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
|
||||
|
||||
/* Disable all interrupts */
|
||||
set_reg(UART_IER_OFFSET, 0x00);
|
||||
/* Enable DLAB */
|
||||
set_reg(UART_LCR_OFFSET, 0x80);
|
||||
/* 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);
|
||||
/* Enable FIFO */
|
||||
set_reg(UART_FCR_OFFSET, 0x01);
|
||||
/* No modem control DTR RTS */
|
||||
set_reg(UART_MCR_OFFSET, 0x00);
|
||||
/* Clear line status */
|
||||
get_reg(UART_LSR_OFFSET);
|
||||
/* Read receive buffer */
|
||||
get_reg(UART_RBR_OFFSET);
|
||||
/* Set scratchpad */
|
||||
set_reg(UART_SCR_OFFSET, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user