summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart/uart_cpu_fdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/uart/uart_cpu_fdt.c')
-rw-r--r--sys/dev/uart/uart_cpu_fdt.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/sys/dev/uart/uart_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c
index 356049b..8dfdb3c 100644
--- a/sys/dev/uart/uart_cpu_fdt.c
+++ b/sys/dev/uart/uart_cpu_fdt.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_cpu_fdt.h>
/*
* UART console routines.
@@ -115,13 +116,46 @@ phandle_chosen_propdev(phandle_t chosen, const char *name, phandle_t *node)
return (0);
}
+static const struct ofw_compat_data *
+uart_fdt_find_compatible(phandle_t node, const struct ofw_compat_data *cd)
+{
+ const struct ofw_compat_data *ocd;
+
+ for (ocd = cd; ocd->ocd_str != NULL; ocd++) {
+ if (fdt_is_compatible(node, ocd->ocd_str))
+ return (ocd);
+ }
+ return (NULL);
+}
+
+static uintptr_t
+uart_fdt_find_by_node(phandle_t node, int class_list)
+{
+ struct ofw_compat_data **cd;
+ const struct ofw_compat_data *ocd;
+
+ if (class_list) {
+ SET_FOREACH(cd, uart_fdt_class_set) {
+ ocd = uart_fdt_find_compatible(node, *cd);
+ if ((ocd != NULL) && (ocd->ocd_data != 0))
+ return (ocd->ocd_data);
+ }
+ } else {
+ SET_FOREACH(cd, uart_fdt_class_and_device_set) {
+ ocd = uart_fdt_find_compatible(node, *cd);
+ if ((ocd != NULL) && (ocd->ocd_data != 0))
+ return (ocd->ocd_data);
+ }
+ }
+ return (0);
+}
+
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
const char *propnames[] = {"stdout-path", "linux,stdout-path", "stdout",
"stdin-path", "stdin", NULL};
const char **name;
- const struct ofw_compat_data *cd;
struct uart_class *class;
phandle_t node, chosen;
pcell_t shift, br, rclk;
@@ -160,24 +194,32 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
* Retrieve serial attributes.
*/
uart_fdt_get_shift(node, &shift);
-
if (OF_getprop(node, "current-speed", &br, sizeof(br)) <= 0)
br = 0;
- br = fdt32_to_cpu(br);
+ else
+ br = fdt32_to_cpu(br);
- if ((err = uart_fdt_get_clock(node, &rclk)) != 0)
- return (err);
/*
- * Finalize configuration.
+ * Check old style of UART definition first. Unfortunately, the common
+ * FDT processing is not possible if we have clock, power domains and
+ * pinmux stuff.
*/
- for (cd = uart_fdt_compat_data; cd->ocd_str != NULL; ++cd) {
- if (fdt_is_compatible(node, cd->ocd_str))
- break;
+ class = (struct uart_class *)uart_fdt_find_by_node(node, 0);
+ if (class != NULL) {
+ if ((err = uart_fdt_get_clock(node, &rclk)) != 0)
+ return (err);
+ } else {
+ /* Check class only linker set */
+ class =
+ (struct uart_class *)uart_fdt_find_by_node(node, 1);
+ if (class == NULL)
+ return (ENXIO);
+ rclk = 0;
}
- if (cd->ocd_str == NULL)
- return (ENXIO);
- class = (struct uart_class *)cd->ocd_data;
+ /*
+ * Finalize configuration.
+ */
di->bas.chan = 0;
di->bas.regshft = (u_int)shift;
di->baudrate = br;
OpenPOWER on IntegriCloud