fdt/wrappers: Introduce code to find UART DT node

The stdout-path property in the /chosen node of a DTB points to a device
node, which is used for boot console output.
On most (if not all) ARM based platforms this is the debug UART.
The ST platform code contains a function to parse this property and
chase down eventual aliases to learn the node offset of this UART node.

Introduce a slightly more generalised version of this ST platform function
in the generic fdt_wrappers code. This will be useful for other platforms
as well.

Change-Id: Ie6da47ace7833861b5e35fe8cba49835db3659a5
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
index 2c4b9c3..1901a20 100644
--- a/common/fdt_wrappers.c
+++ b/common/fdt_wrappers.c
@@ -294,3 +294,50 @@
 
 	return fdt_get_reg_props_by_index(dtb, node, index, base, size);
 }
+
+/*******************************************************************************
+ * This function gets the stdout path node.
+ * It reads the value indicated inside the device tree.
+ * Returns node offset on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int fdt_get_stdout_node_offset(const void *dtb)
+{
+	int node;
+	const char *prop, *path;
+	int len;
+
+	/* The /secure-chosen node takes precedence over the standard one. */
+	node = fdt_path_offset(dtb, "/secure-chosen");
+	if (node < 0) {
+		node = fdt_path_offset(dtb, "/chosen");
+		if (node < 0) {
+			return -FDT_ERR_NOTFOUND;
+		}
+	}
+
+	prop = fdt_getprop(dtb, node, "stdout-path", NULL);
+	if (prop == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/* Determine the actual path length, as a colon terminates the path. */
+	path = strchr(prop, ':');
+	if (path == NULL) {
+		len = strlen(prop);
+	} else {
+		len = path - prop;
+	}
+
+	/* Aliases cannot start with a '/', so it must be the actual path. */
+	if (prop[0] == '/') {
+		return fdt_path_offset_namelen(dtb, prop, len);
+	}
+
+	/* Lookup the alias, as this contains the actual path. */
+	path = fdt_get_alias_namelen(dtb, prop, len);
+	if (path == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return fdt_path_offset(dtb, path);
+}
diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h
index 06625e4..382651e 100644
--- a/include/common/fdt_wrappers.h
+++ b/include/common/fdt_wrappers.h
@@ -32,5 +32,6 @@
 			       uintptr_t *base, size_t *size);
 int fdt_get_reg_props_by_name(const void *dtb, int node, const char *name,
 			      uintptr_t *base, size_t *size);
+int fdt_get_stdout_node_offset(const void *dtb);
 
 #endif /* FDT_WRAPPERS_H */
diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i
index c656c79..213a974 100644
--- a/plat/arm/board/fvp/jmptbl.i
+++ b/plat/arm/board/fvp/jmptbl.i
@@ -24,11 +24,13 @@
 fdt     fdt_first_subnode
 fdt     fdt_next_subnode
 fdt     fdt_path_offset
+fdt     fdt_path_offset_namelen
 fdt     fdt_subnode_offset
 fdt     fdt_address_cells
 fdt     fdt_size_cells
 fdt     fdt_parent_offset
 fdt     fdt_stringlist_search
+fdt     fdt_get_alias_namelen
 mbedtls mbedtls_asn1_get_alg
 mbedtls mbedtls_asn1_get_alg_null
 mbedtls mbedtls_asn1_get_bitstring_null
diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i
index 213afd0..09017ac 100644
--- a/plat/arm/board/juno/jmptbl.i
+++ b/plat/arm/board/juno/jmptbl.i
@@ -25,6 +25,9 @@
 fdt     fdt_next_subnode
 fdt     fdt_parent_offset
 fdt     fdt_stringlist_search
+fdt     fdt_get_alias_namelen
+fdt     fdt_path_offset
+fdt     fdt_path_offset_namelen
 mbedtls mbedtls_asn1_get_alg
 mbedtls mbedtls_asn1_get_alg_null
 mbedtls mbedtls_asn1_get_bitstring_null