rockchip: Allow console device to be set by DTB.

Currently the compile-time constant PLAT_RK_UART_BASE defines
which UART is used as console device. E.g. on RK3399 it is set
to UART2. That means, that a single bl31 image can not be used
for two boards, which just differ on the UART console.

This patch addresses this limitation by parsing the "stdout-path"
property from the "chosen" node in the DTB. The expected property
string is expected to have the form "serialN:XXX", with
N being either 0, 1, 2, 3 or 4. When the property is found, it will
be used to override PLAT_RK_UART_BASE.

Tested on RK3399-Q7, with a stdout-path of "serial0:115200n8".

Signed-off-by: Christoph Müllner <christophm30@gmail.com>
Change-Id: Iafe1320e77ab006c121f8d52745d54cef68a48c7
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
index 2c970eb..30782d1 100644
--- a/plat/rockchip/common/bl31_plat_setup.c
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -78,7 +78,7 @@
 				       coreboot_serial.baud,
 				       &console);
 #else
-	console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK,
+	console_16550_register(rockchip_get_uart_base(), PLAT_RK_UART_CLOCK,
 			       PLAT_RK_UART_BAUDRATE, &console);
 #endif
 
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index f9470e5..c0ebefc 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -146,6 +146,8 @@
 
 extern const mmap_region_t plat_rk_mmap[];
 
+uint32_t rockchip_get_uart_base(void);
+
 #endif /* __ASSEMBLY__ */
 
 /******************************************************************************
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index baf2563..8a743bf 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -28,6 +28,12 @@
 static struct gpio_info suspend_gpio[10];
 uint32_t suspend_gpio_cnt;
 static struct apio_info *suspend_apio;
+static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
+
+uint32_t rockchip_get_uart_base(void)
+{
+	return rk_uart_base;
+}
 
 #if COREBOOT
 static int dt_process_fdt(void *blob)
@@ -42,6 +48,63 @@
 	return &fdt_buffer[0];
 }
 
+static void plat_rockchip_dt_process_fdt_uart(void *fdt)
+{
+	const char *path_name = "/chosen";
+	const char *prop_name = "stdout-path";
+	int node_offset;
+	int stdout_path_len;
+	const char *stdout_path;
+	char serial_char;
+	int serial_no;
+	uint32_t uart_base;
+
+	node_offset = fdt_path_offset(fdt, path_name);
+	if (node_offset < 0)
+		return;
+
+	stdout_path = fdt_getprop(fdt, node_offset, prop_name,
+				  &stdout_path_len);
+	if (stdout_path == NULL)
+		return;
+
+	/*
+	 * We expect something like:
+	 *   "serial0:...""
+	 */
+	if (strncmp("serial", stdout_path, 6) != 0)
+		return;
+
+	serial_char = stdout_path[6];
+	serial_no = serial_char - '0';
+
+	switch (serial_no) {
+	case 0:
+		uart_base = UART0_BASE;
+		break;
+	case 1:
+		uart_base = UART1_BASE;
+		break;
+	case 2:
+		uart_base = UART2_BASE;
+		break;
+#ifdef UART3_BASE
+	case 3:
+		uart_base = UART3_BASE;
+		break;
+#endif
+#ifdef UART4_BASE
+	case 4:
+		uart_base = UART4_BASE;
+		break;
+#endif
+	default:
+		return;
+	}
+
+	rk_uart_base = uart_base;
+}
+
 static int dt_process_fdt(void *blob)
 {
 	void *fdt = plat_get_fdt();
@@ -51,6 +114,8 @@
 	if (ret < 0)
 		return ret;
 
+	plat_rockchip_dt_process_fdt_uart(fdt);
+
 	return 0;
 }
 #endif
diff --git a/plat/rockchip/common/sp_min_plat_setup.c b/plat/rockchip/common/sp_min_plat_setup.c
index 7250919..7cdbaba 100644
--- a/plat/rockchip/common/sp_min_plat_setup.c
+++ b/plat/rockchip/common/sp_min_plat_setup.c
@@ -65,7 +65,7 @@
 				       coreboot_serial.baud,
 				       &console);
 #else
-	console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK,
+	console_16550_register(rockchip_get_uart_base(), PLAT_RK_UART_CLOCK,
 			       PLAT_RK_UART_BAUDRATE, &console);
 #endif
 	VERBOSE("sp_min_setup\n");