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:
parent
75322a634b
commit
76a89403c8
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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
|
||||
};
|
|
@ -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
|
||||
};
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue