lib: utils: Add simple FDT serial framework

We add simple serial framework which will select and use serial driver
based on details in FDT passed by previous booting stage.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
Anup Patel 2020-04-24 17:00:37 +05:30 committed by Anup Patel
parent 75322a634b
commit 76a89403c8
6 changed files with 242 additions and 0 deletions

View File

@ -0,0 +1,28 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#ifndef __FDT_SERIAL_H__
#define __FDT_SERIAL_H__
#include <sbi/sbi_types.h>
struct fdt_serial {
const struct fdt_match *match_table;
int (*init)(void *fdt, int nodeoff, const struct fdt_match *match);
void (*putc)(char ch);
int (*getc)(void);
};
void fdt_serial_putc(char ch);
int fdt_serial_getc(void);
int fdt_serial_init(void);
#endif

View File

@ -0,0 +1,109 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <libfdt.h>
#include <sbi/sbi_scratch.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
extern struct fdt_serial fdt_serial_uart8250;
extern struct fdt_serial fdt_serial_sifive;
extern struct fdt_serial fdt_serial_htif;
static struct fdt_serial *serial_drivers[] = {
&fdt_serial_uart8250,
&fdt_serial_sifive,
&fdt_serial_htif,
};
static void dummy_putc(char ch)
{
}
static int dummy_getc(void)
{
return -1;
}
static struct fdt_serial dummy = {
.match_table = NULL,
.init = NULL,
.putc = dummy_putc,
.getc = dummy_getc,
};
static struct fdt_serial *current_driver = &dummy;
void fdt_serial_putc(char ch)
{
current_driver->putc(ch);
}
int fdt_serial_getc(void)
{
return current_driver->getc();
}
int fdt_serial_init(void)
{
const void *prop;
struct fdt_serial *drv;
const struct fdt_match *match;
int pos, noff = -1, len, coff, rc;
void *fdt = sbi_scratch_thishart_arg1_ptr();
/* Find offset of node pointed by stdout-path */
coff = fdt_path_offset(fdt, "/chosen");
if (-1 < coff) {
prop = fdt_getprop(fdt, coff, "stdout-path", &len);
if (prop && len)
noff = fdt_path_offset(fdt, prop);
}
/* First check DT node pointed by stdout-path */
for (pos = 0; pos < array_size(serial_drivers) && -1 < noff; pos++) {
drv = serial_drivers[pos];
match = fdt_match_node(fdt, noff, drv->match_table);
if (!match)
continue;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
break;
}
/* Check if we found desired driver */
if (current_driver != &dummy)
goto done;
/* Lastly check all DT nodes */
for (pos = 0; pos < array_size(serial_drivers); pos++) {
drv = serial_drivers[pos];
noff = fdt_find_match(fdt, drv->match_table, &match);
if (noff < 0)
continue;
if (drv->init) {
rc = drv->init(fdt, noff, match);
if (rc)
return rc;
}
current_driver = drv;
break;
}
done:
return 0;
}

View File

@ -0,0 +1,24 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/sys/htif.h>
static const struct fdt_match serial_htif_match[] = {
{ .compatible = "ucb,htif0" },
{ },
};
struct fdt_serial fdt_serial_htif = {
.match_table = serial_htif_match,
.init = NULL,
.getc = htif_getc,
.putc = htif_putc
};

View File

@ -0,0 +1,38 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/sifive-uart.h>
static int serial_sifive_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_sifive_uart_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return sifive_uart_init(uart.addr, uart.freq, uart.baud);
}
static const struct fdt_match serial_sifive_match[] = {
{ .compatible = "sifive,fu540-c000-uart" },
{ .compatible = "sifive,uart0" },
{ },
};
struct fdt_serial fdt_serial_sifive = {
.match_table = serial_sifive_match,
.init = serial_sifive_init,
.getc = sifive_uart_getc,
.putc = sifive_uart_putc
};

View File

@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <anup.patel@wdc.com>
*/
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/serial/fdt_serial.h>
#include <sbi_utils/serial/uart8250.h>
static int serial_uart8250_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
int rc;
struct platform_uart_data uart;
rc = fdt_parse_uart8250_node(fdt, nodeoff, &uart);
if (rc)
return rc;
return uart8250_init(uart.addr, uart.freq, uart.baud,
uart.reg_shift, uart.reg_io_width);
}
static const struct fdt_match serial_uart8250_match[] = {
{ .compatible = "ns16550" },
{ .compatible = "ns16550a" },
{ },
};
struct fdt_serial fdt_serial_uart8250 = {
.match_table = serial_uart8250_match,
.init = serial_uart8250_init,
.getc = uart8250_getc,
.putc = uart8250_putc
};

View File

@ -7,5 +7,9 @@
# Anup Patel <anup.patel@wdc.com>
#
libsbiutils-objs-y += serial/fdt_serial.o
libsbiutils-objs-y += serial/fdt_serial_htif.o
libsbiutils-objs-y += serial/fdt_serial_sifive.o
libsbiutils-objs-y += serial/fdt_serial_uart8250.o
libsbiutils-objs-y += serial/sifive-uart.o
libsbiutils-objs-y += serial/uart8250.o