blob: eec75cca0c98ee0849ea4c9364a5c18b90a8c268 [file] [log] [blame]
/*
* 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;
}