fdt/serial: Make uart search more agressive. Examine /chosen for serial devices

Change-Id: Icc1673b331d9afb3a7b34c91e7b1f20c3dee964a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1871
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com>
This commit is contained in:
Alexander von Gluck IV 2019-09-20 09:32:59 -05:00 committed by Alex von Gluck IV
parent bc3b6065c6
commit 9d010ea47d

View File

@ -40,43 +40,18 @@ extern "C" {
// If we dprintf before the UART is initalized there will be no output
DebugUART*
debug_uart_from_fdt(const void *fdt)
static DebugUART*
debug_uart_from_node(const void *fdt, int node)
{
const char *name;
int node;
int len;
const void *prop;
phys_addr_t regs;
int32 clock = 0;
int32 speed = 0;
const void *prop;
DebugUART *uart = NULL;
if (fdt == NULL) {
TRACE("%s: No FDT found!\n", __func__);
if (node < 0 || fdt == NULL)
return NULL;
}
name = fdt_get_alias(fdt, "serial");
if (name == NULL)
name = fdt_get_alias(fdt, "serial0");
if (name == NULL)
name = fdt_get_alias(fdt, "serial1");
if (name == NULL)
name = fdt_get_alias(fdt, "uart0");
// TODO: else use /chosen linux,stdout-path
if (name == NULL) {
TRACE("%s: No known FDT UART alias found!\n", __func__);
return NULL;
}
node = fdt_path_offset(fdt, name);
if (node < 0) {
TRACE("%s: FDT node not found!\n", __func__);
return NULL;
}
// determine the MMIO address
regs = fdt_get_device_reg(fdt, node, false);
@ -86,7 +61,7 @@ debug_uart_from_fdt(const void *fdt)
return NULL;
}
TRACE("serial: using '%s', node %d @ %" B_PRIxPHYSADDR "\n",
TRACE("serial: checking '%s', node %d @ %" B_PRIxPHYSADDR "\n",
name, node, regs);
// get the UART clock rate
@ -104,9 +79,9 @@ debug_uart_from_fdt(const void *fdt)
}
// fdt_node_check_compatible returns 0 on match.
if (fdt_node_check_compatible(fdt, node, "ns16550a") == 0
|| fdt_node_check_compatible(fdt, node, "ns16550") == 0) {
|| fdt_node_check_compatible(fdt, node, "ns16550") == 0
|| fdt_node_check_compatible(fdt, node, "snps,dw-apb-uart") == 0) {
TRACE("serial: Found 8250 serial UART!\n");
uart = arch_get_uart_8250(regs, clock);
#if defined(__arm__)
@ -124,10 +99,96 @@ debug_uart_from_fdt(const void *fdt)
TRACE("serial: Found pl011 serial UART!\n");
uart = arch_get_uart_pl011(regs, clock);
#endif
} else {
// TODO: handle more UART types
}
return uart;
}
DebugUART*
debug_uart_from_fdt(const void *fdt)
{
int chosen_node;
int node;
int len;
const char *name;
const void *prop;
DebugUART *uart = NULL;
if (fdt == NULL) {
TRACE("%s: No FDT found!\n", __func__);
return NULL;
}
chosen_node = fdt_path_offset(fdt, "/chosen");
if (chosen_node >= 0) {
prop = fdt_getprop(fdt, chosen_node, "stdout-path", &len);
if (prop && len > 0) {
node = fdt_path_offset(fdt, (const char*)prop);
uart = debug_uart_from_node(fdt, node);
}
if (uart == NULL) {
prop = fdt_getprop(fdt, chosen_node, "linux,stdout-path", &len);
if (prop && len > 0) {
node = fdt_path_offset(fdt, (const char*)prop);
uart = debug_uart_from_node(fdt, node);
}
}
if (uart == NULL) {
// From what i've seen, stdout is generally an alias.
// we could check for "/..." in the prop, but not sure
// it's needed. If we *did* check for a prop starting
// with / we could make all three of these "the same"
prop = fdt_getprop(fdt, chosen_node, "stdout", &len);
if (prop && len > 0) {
name = fdt_get_alias(fdt, (const char*)prop);
if (name != NULL) {
node = fdt_path_offset(fdt, name);
uart = debug_uart_from_node(fdt, node);
}
}
}
// Whoo-hoo! Bail.
if (uart != NULL)
return uart;
}
// If we didn't find a /chosen serial device, lets search for some common aliases
char aliases[][8] = {
"serial",
"serial0",
"uart",
"uart0",
"serial1",
"serial2",
"serial3",
"uart1",
"uart2",
"uart3"
};
// For each known common serial alias, check it out and see if we have the
// needed driver for it. uart0 seems most common.
for (int index = 0; index < sizeof(aliases[0]) / sizeof(aliases); index++) {
name = fdt_get_alias(fdt, aliases[index]);
if (name == NULL)
continue;
node = fdt_path_offset(fdt, name);
if (node < 0) {
TRACE("%s: FDT node not found!\n", __func__);
continue;
}
uart = debug_uart_from_node(fdt, node);
// We found a valid serial device. bail.
if (uart != NULL)
break;
}
// It would be nice if we had *some* communication mechanism here if uart is still
// NULL to warn the user that we couldn't find a serial port.
return uart;
}