forked from Mirrors/opensbi
lib: utils: serial: Add Cadence UART driver
Add Cadence UART driver Signed-off-by: Jun Liang Tan <junliang.tan@linux.starfivetech.com> Signed-off-by: Wei Liang Lim <weiliang.lim@linux.starfivetech.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Anup Patel <anup@brainfault.org>
This commit is contained in:

committed by
Anup Patel

parent
adf44b51ba
commit
cbaa9b0333
@@ -65,8 +65,8 @@ int fdt_parse_shakti_uart_node(void *fdt, int nodeoffset,
|
|||||||
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
int fdt_parse_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart);
|
struct platform_uart_data *uart);
|
||||||
|
|
||||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||||
const char *compatible);
|
const char *compatible);
|
||||||
|
16
include/sbi_utils/serial/cadence-uart.h
Normal file
16
include/sbi_utils/serial/cadence-uart.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SERIAL_CADENCE_UART_H__
|
||||||
|
#define __SERIAL_CADENCE_UART_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_types.h>
|
||||||
|
|
||||||
|
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate);
|
||||||
|
|
||||||
|
#endif
|
@@ -401,8 +401,8 @@ int fdt_parse_sifive_uart_node(void *fdt, int nodeoffset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_uart8250_node(void *fdt, int nodeoffset,
|
int fdt_parse_uart_node(void *fdt, int nodeoffset,
|
||||||
struct platform_uart_data *uart)
|
struct platform_uart_data *uart)
|
||||||
{
|
{
|
||||||
int len, rc;
|
int len, rc;
|
||||||
const fdt32_t *val;
|
const fdt32_t *val;
|
||||||
@@ -447,7 +447,7 @@ int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
|||||||
if (nodeoffset < 0)
|
if (nodeoffset < 0)
|
||||||
return nodeoffset;
|
return nodeoffset;
|
||||||
|
|
||||||
return fdt_parse_uart8250_node(fdt, nodeoffset, uart);
|
return fdt_parse_uart_node(fdt, nodeoffset, uart);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
|
int fdt_parse_xlnx_uartlite_node(void *fdt, int nodeoffset,
|
||||||
|
@@ -9,6 +9,11 @@ config FDT_SERIAL
|
|||||||
|
|
||||||
if FDT_SERIAL
|
if FDT_SERIAL
|
||||||
|
|
||||||
|
config FDT_SERIAL_CADENCE
|
||||||
|
bool "Cadence UART FDT driver"
|
||||||
|
select SERIAL_CADENCE
|
||||||
|
default n
|
||||||
|
|
||||||
config FDT_SERIAL_GAISLER
|
config FDT_SERIAL_GAISLER
|
||||||
bool "Gaisler UART FDT driver"
|
bool "Gaisler UART FDT driver"
|
||||||
select SERIAL_GAISLER
|
select SERIAL_GAISLER
|
||||||
@@ -46,6 +51,10 @@ config FDT_SERIAL_XILINX_UARTLITE
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
config SERIAL_CADENCE
|
||||||
|
bool "Cadence UART support"
|
||||||
|
default n
|
||||||
|
|
||||||
config SERIAL_GAISLER
|
config SERIAL_GAISLER
|
||||||
bool "Gaisler UART support"
|
bool "Gaisler UART support"
|
||||||
default n
|
default n
|
||||||
|
128
lib/utils/serial/cadence-uart.c
Normal file
128
lib/utils/serial/cadence-uart.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi/riscv_io.h>
|
||||||
|
#include <sbi/sbi_console.h>
|
||||||
|
#include <sbi_utils/serial/cadence-uart.h>
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
|
||||||
|
#define UART_REG_CTRL 0x00
|
||||||
|
#define UART_REG_MODE 0x04
|
||||||
|
#define UART_REG_IDR 0x0C
|
||||||
|
#define UART_REG_BRGR 0x18
|
||||||
|
#define UART_REG_CSR 0x2C
|
||||||
|
#define UART_REG_RFIFO_TFIFO 0x30
|
||||||
|
#define UART_REG_BDIVR 0x34
|
||||||
|
|
||||||
|
#define UART_CTRL_RXRES 0x00000001
|
||||||
|
#define UART_CTRL_TXRES 0x00000002
|
||||||
|
#define UART_CTRL_RXEN 0x00000004
|
||||||
|
#define UART_CTRL_RXDIS 0x00000008
|
||||||
|
#define UART_CTRL_TXEN 0x00000010
|
||||||
|
#define UART_CTRL_TXDIS 0x00000020
|
||||||
|
|
||||||
|
#define UART_MODE_PAR_NONE 0x00000020 /* No parity set */
|
||||||
|
|
||||||
|
#define UART_BRGR_CD_CLKDIVISOR 0x00000001 /* baud_sample = sel_clk */
|
||||||
|
|
||||||
|
#define UART_CSR_REMPTY 0x00000002
|
||||||
|
#define UART_CSR_TFUL 0x00000010
|
||||||
|
|
||||||
|
/* 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 SiFive UART driver (sifive-uart.c)
|
||||||
|
*/
|
||||||
|
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 offset)
|
||||||
|
{
|
||||||
|
return readl(uart_base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_reg(u32 offset, u32 val)
|
||||||
|
{
|
||||||
|
writel(val, uart_base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cadence_uart_putc(char ch)
|
||||||
|
{
|
||||||
|
while (get_reg(UART_REG_CSR) & UART_CSR_TFUL)
|
||||||
|
;
|
||||||
|
|
||||||
|
set_reg(UART_REG_RFIFO_TFIFO, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cadence_uart_getc(void)
|
||||||
|
{
|
||||||
|
u32 ret = get_reg(UART_REG_CSR);
|
||||||
|
|
||||||
|
if (!(ret & UART_CSR_REMPTY))
|
||||||
|
return get_reg(UART_REG_RFIFO_TFIFO);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sbi_console_device cadence_console = {
|
||||||
|
.name = "cadence_uart",
|
||||||
|
.console_putc = cadence_uart_putc,
|
||||||
|
.console_getc = cadence_uart_getc
|
||||||
|
};
|
||||||
|
|
||||||
|
int cadence_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
|
||||||
|
{
|
||||||
|
uart_base = (volatile void *)base;
|
||||||
|
uart_in_freq = in_freq;
|
||||||
|
uart_baudrate = baudrate;
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
set_reg(UART_REG_IDR, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
/* Disable TX RX */
|
||||||
|
set_reg(UART_REG_CTRL, UART_CTRL_TXDIS | UART_CTRL_RXDIS);
|
||||||
|
|
||||||
|
/* Configure baudrate */
|
||||||
|
if (in_freq && baudrate) {
|
||||||
|
set_reg(UART_REG_BRGR, UART_BRGR_CD_CLKDIVISOR);
|
||||||
|
set_reg(UART_REG_BDIVR,
|
||||||
|
uart_min_clk_divisor(in_freq, baudrate));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Software reset TX RX data path and enable TX RX */
|
||||||
|
set_reg(UART_REG_CTRL, UART_CTRL_TXRES | UART_CTRL_RXRES
|
||||||
|
| UART_CTRL_TXEN | UART_CTRL_RXEN);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set:
|
||||||
|
* 1 stop bit, bits[07:06] = 0x00,
|
||||||
|
* no parity set, bits[05:03] = 0x100,
|
||||||
|
* 8 bits character length, bits[02:01] = 0x00,
|
||||||
|
* sel_clk = uart_clk, bit[0] = 0x0
|
||||||
|
*/
|
||||||
|
set_reg(UART_REG_MODE, UART_MODE_PAR_NONE);
|
||||||
|
|
||||||
|
sbi_console_set_device(&cadence_console);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
35
lib/utils/serial/fdt_serial_cadence.c
Normal file
35
lib/utils/serial/fdt_serial_cadence.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||||
|
*
|
||||||
|
* Author: Jun Liang Tan <junliang.tan@linux.starfivetech.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sbi_utils/fdt/fdt_helper.h>
|
||||||
|
#include <sbi_utils/serial/fdt_serial.h>
|
||||||
|
#include <sbi_utils/serial/cadence-uart.h>
|
||||||
|
|
||||||
|
static int serial_cadence_init(void *fdt, int nodeoff,
|
||||||
|
const struct fdt_match *match)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct platform_uart_data uart = { 0 };
|
||||||
|
|
||||||
|
rc = fdt_parse_uart_node(fdt, nodeoff, &uart);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return cadence_uart_init(uart.addr, uart.freq, uart.baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fdt_match serial_cadence_match[] = {
|
||||||
|
{ .compatible = "cdns,uart-r1p12" },
|
||||||
|
{ .compatible = "starfive,jh8100-uart" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdt_serial fdt_serial_cadence = {
|
||||||
|
.match_table = serial_cadence_match,
|
||||||
|
.init = serial_cadence_init
|
||||||
|
};
|
@@ -17,7 +17,7 @@ static int serial_uart8250_init(void *fdt, int nodeoff,
|
|||||||
int rc;
|
int rc;
|
||||||
struct platform_uart_data uart = { 0 };
|
struct platform_uart_data uart = { 0 };
|
||||||
|
|
||||||
rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
|
rc = fdt_parse_uart_node(fdt, nodeoff, &uart);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@@ -10,6 +10,9 @@
|
|||||||
libsbiutils-objs-$(CONFIG_FDT_SERIAL) += serial/fdt_serial.o
|
libsbiutils-objs-$(CONFIG_FDT_SERIAL) += serial/fdt_serial.o
|
||||||
libsbiutils-objs-$(CONFIG_FDT_SERIAL) += serial/fdt_serial_drivers.o
|
libsbiutils-objs-$(CONFIG_FDT_SERIAL) += serial/fdt_serial_drivers.o
|
||||||
|
|
||||||
|
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_CADENCE) += fdt_serial_cadence
|
||||||
|
libsbiutils-objs-$(CONFIG_FDT_SERIAL_CADENCE) += serial/fdt_serial_cadence.o
|
||||||
|
|
||||||
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_GAISLER) += fdt_serial_gaisler
|
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_GAISLER) += fdt_serial_gaisler
|
||||||
libsbiutils-objs-$(CONFIG_FDT_SERIAL_GAISLER) += serial/fdt_serial_gaisler.o
|
libsbiutils-objs-$(CONFIG_FDT_SERIAL_GAISLER) += serial/fdt_serial_gaisler.o
|
||||||
|
|
||||||
@@ -31,6 +34,7 @@ libsbiutils-objs-$(CONFIG_FDT_SERIAL_UART8250) += serial/fdt_serial_uart8250.o
|
|||||||
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += fdt_serial_xlnx_uartlite
|
carray-fdt_serial_drivers-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += fdt_serial_xlnx_uartlite
|
||||||
libsbiutils-objs-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += serial/fdt_serial_xlnx_uartlite.o
|
libsbiutils-objs-$(CONFIG_FDT_SERIAL_XILINX_UARTLITE) += serial/fdt_serial_xlnx_uartlite.o
|
||||||
|
|
||||||
|
libsbiutils-objs-$(CONFIG_SERIAL_CADENCE) += serial/cadence-uart.o
|
||||||
libsbiutils-objs-$(CONFIG_SERIAL_GAISLER) += serial/gaisler-uart.o
|
libsbiutils-objs-$(CONFIG_SERIAL_GAISLER) += serial/gaisler-uart.o
|
||||||
libsbiutils-objs-$(CONFIG_SERIAL_SHAKTI) += serial/shakti-uart.o
|
libsbiutils-objs-$(CONFIG_SERIAL_SHAKTI) += serial/shakti-uart.o
|
||||||
libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o
|
libsbiutils-objs-$(CONFIG_SERIAL_SIFIVE) += serial/sifive-uart.o
|
||||||
|
@@ -18,6 +18,7 @@ CONFIG_FDT_RESET_SIFIVE_TEST=y
|
|||||||
CONFIG_FDT_RESET_SUNXI_WDT=y
|
CONFIG_FDT_RESET_SUNXI_WDT=y
|
||||||
CONFIG_FDT_RESET_THEAD=y
|
CONFIG_FDT_RESET_THEAD=y
|
||||||
CONFIG_FDT_SERIAL=y
|
CONFIG_FDT_SERIAL=y
|
||||||
|
CONFIG_FDT_SERIAL_CADENCE=y
|
||||||
CONFIG_FDT_SERIAL_GAISLER=y
|
CONFIG_FDT_SERIAL_GAISLER=y
|
||||||
CONFIG_FDT_SERIAL_HTIF=y
|
CONFIG_FDT_SERIAL_HTIF=y
|
||||||
CONFIG_FDT_SERIAL_SHAKTI=y
|
CONFIG_FDT_SERIAL_SHAKTI=y
|
||||||
|
Reference in New Issue
Block a user