Files
opensbi/lib/utils/serial/gaisler-uart.c
Andrew Jones f27203525a lib: utils/serial: Ensure baudrate is non-zero before using
RISC-V doesn't generate exceptions on divide-by-zero, but the result,
all bits set, is not likely what people expect either. In all cases
where we divide by baudrate there's a chance it's zero (when the DT
it came from is "bad"). To avoid difficult to debug situations, leave
baudrate dependent registers alone when baudrate is zero, as, also in
all cases, it appears we can skip initialization of those registers
and still [hopefully] have a functioning UART.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
2022-07-30 11:39:42 +05:30

87 lines
1.8 KiB
C

/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Cobham Gaisler AB.
*
* Authors:
* Daniel Cederman <cederman@gaisler.com>
*/
#include <sbi/riscv_io.h>
#include <sbi/sbi_console.h>
#include <sbi_utils/serial/gaisler-uart.h>
/* clang-format off */
#define UART_REG_DATA 0
#define UART_REG_STATUS 1
#define UART_REG_CTRL 2
#define UART_REG_SCALER 3
#define UART_DATA_DATA 0x000000ff
#define UART_STATUS_FIFOFULL 0x00000200
#define UART_STATUS_DATAREADY 0x00000001
#define UART_CTRL_DB (1<<11)
#define UART_CTRL_FL (1<<6)
#define UART_CTRL_TE (1<<1)
#define UART_CTRL_RE (1<<0)
/* clang-format on */
static volatile char *uart_base;
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));
}
static void gaisler_uart_putc(char ch)
{
while (get_reg(UART_REG_STATUS) & UART_STATUS_FIFOFULL)
;
set_reg(UART_REG_DATA, ch);
}
static int gaisler_uart_getc(void)
{
u32 ret = get_reg(UART_REG_STATUS);
if (!(ret & UART_STATUS_DATAREADY))
return -1;
return get_reg(UART_REG_DATA) & UART_DATA_DATA;
}
static struct sbi_console_device gaisler_console = {
.name = "gaisler_uart",
.console_putc = gaisler_uart_putc,
.console_getc = gaisler_uart_getc
};
int gaisler_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
{
u32 ctrl;
uart_base = (volatile char *)base;
/* Configure baudrate */
if (in_freq && baudrate)
set_reg(UART_REG_SCALER, in_freq / (baudrate * 8 + 7));
ctrl = get_reg(UART_REG_CTRL);
/* Preserve debug mode and flow control */
ctrl &= (UART_CTRL_DB | UART_CTRL_FL);
/* Enable TX and RX */
ctrl |= UART_CTRL_TE | UART_CTRL_RE;
set_reg(UART_REG_CTRL, ctrl);
sbi_console_set_device(&gaisler_console);
return 0;
}