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:
parent
bc3b6065c6
commit
9d010ea47d
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user