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 <[email protected]> Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
committed by
Alex von Gluck IV
parent
bc3b6065c6
commit
9d010ea47d
@@ -40,43 +40,18 @@ extern "C" {
|
|||||||
|
|
||||||
// If we dprintf before the UART is initalized there will be no output
|
// If we dprintf before the UART is initalized there will be no output
|
||||||
|
|
||||||
|
static DebugUART*
|
||||||
DebugUART*
|
debug_uart_from_node(const void *fdt, int node)
|
||||||
debug_uart_from_fdt(const void *fdt)
|
|
||||||
{
|
{
|
||||||
const char *name;
|
|
||||||
int node;
|
|
||||||
int len;
|
int len;
|
||||||
|
const void *prop;
|
||||||
phys_addr_t regs;
|
phys_addr_t regs;
|
||||||
int32 clock = 0;
|
int32 clock = 0;
|
||||||
int32 speed = 0;
|
int32 speed = 0;
|
||||||
const void *prop;
|
|
||||||
DebugUART *uart = NULL;
|
DebugUART *uart = NULL;
|
||||||
|
|
||||||
if (fdt == NULL) {
|
if (node < 0 || fdt == NULL)
|
||||||
TRACE("%s: No FDT found!\n", __func__);
|
|
||||||
return 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
|
// determine the MMIO address
|
||||||
regs = fdt_get_device_reg(fdt, node, false);
|
regs = fdt_get_device_reg(fdt, node, false);
|
||||||
@@ -86,7 +61,7 @@ debug_uart_from_fdt(const void *fdt)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("serial: using '%s', node %d @ %" B_PRIxPHYSADDR "\n",
|
TRACE("serial: checking '%s', node %d @ %" B_PRIxPHYSADDR "\n",
|
||||||
name, node, regs);
|
name, node, regs);
|
||||||
|
|
||||||
// get the UART clock rate
|
// get the UART clock rate
|
||||||
@@ -104,9 +79,9 @@ debug_uart_from_fdt(const void *fdt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fdt_node_check_compatible returns 0 on match.
|
// fdt_node_check_compatible returns 0 on match.
|
||||||
|
|
||||||
if (fdt_node_check_compatible(fdt, node, "ns16550a") == 0
|
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");
|
TRACE("serial: Found 8250 serial UART!\n");
|
||||||
uart = arch_get_uart_8250(regs, clock);
|
uart = arch_get_uart_8250(regs, clock);
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
@@ -124,10 +99,96 @@ debug_uart_from_fdt(const void *fdt)
|
|||||||
TRACE("serial: Found pl011 serial UART!\n");
|
TRACE("serial: Found pl011 serial UART!\n");
|
||||||
uart = arch_get_uart_pl011(regs, clock);
|
uart = arch_get_uart_pl011(regs, clock);
|
||||||
#endif
|
#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;
|
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;
|
return uart;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user