diff mbox series

[5/7] rpi: Properly detect which serial device is active

Message ID 20180116134741.4103-6-agraf@suse.de
State Superseded
Headers show
Series RPi: Properly handle dynamic serial configuration | expand

Commit Message

Alexander Graf Jan. 16, 2018, 1:47 p.m. UTC
Now that we have all infrastructure in place to dynamically determine whether
a serial device is actually usable (read: routed to user accessible pins), we
can wire it up to the board.

This patch adds support to determine whether the pl011 or mini-uart or no serial
is routed to the UART RX/TX pins on the Raspberry Pi family of boards.

Signed-off-by: Alexander Graf <agraf@suse.de>
---
 board/raspberrypi/rpi/rpi.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)
diff mbox series

Patch

diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index a96d5d8952..b0cdad70f7 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -24,9 +24,16 @@ 
 #include <asm/armv8/mmu.h>
 #endif
 #include <watchdog.h>
+#include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/*
+ * This is the GPIO pin that the user facing UART RX line is attached to.
+ * We use this pin to determine which serial device is available.
+ */
+#define BCM2835_GPIO_RX		15
+
 /* From lowlevel_init.S */
 extern unsigned long fw_dtb_pointer;
 
@@ -419,6 +426,68 @@  static void get_board_rev(void)
 	printf("RPI %s (0x%x)\n", model->name, revision);
 }
 
+/*
+ * We may get called before the device model is initialized, so we can not
+ * rely on the GPIO driver.
+ */
+int get_func_id(unsigned gpio)
+{
+	u32 val;
+	u32 node;
+	u32 *gpfsel;
+	fdt_addr_t addr;
+	fdt_size_t size;
+
+	node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2835-gpio");
+	if (node < 0)
+		return -EINVAL;
+
+	addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, node, "reg",
+						  0, &size, true);
+	gpfsel = (void*)addr;
+
+	val = readl(&gpfsel[BCM2835_GPIO_FSEL_BANK(gpio)]);
+
+	return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK);
+}
+
+
+/*
+ * The RPi has 2 serial ports: A PL011 based one and the mini-uart.
+ * Depending on firmware configuration, either can be configured to either
+ * nothing, the wifi adapter or serial output.
+ *
+ * We only want to use the serial port that is user facing to not
+ * end up with a potentially unresponsive serial port. Due to this
+ * we need to check whether the serial device is actually connected
+ * to the UART RX/TX pins on the RPi GPIO pin bar.
+ *
+ * We only allow U-Boot to instantiate the serial driver for the serial
+ * device that is muxed correctly.
+ */
+int board_check_serial(struct udevice *dev)
+{
+	int func;
+
+	printf("Checking serial %s\n", dev->name);
+
+	if (device_is_compatible(dev, "arm,pl011")) {
+		func = BCM2835_GPIO_ALT0;
+	} else if (device_is_compatible(dev, "brcm,bcm2835-aux-uart")) {
+		func = BCM2835_GPIO_ALT5;
+	} else {
+		return 0;
+	}
+
+	if (get_func_id(BCM2835_GPIO_RX) != func) {
+		printf("Disabling serial %s\n", dev->name);
+		return -ENODEV;
+	}
+
+	printf("Enabling serial %s\n", dev->name);
+	return 0;
+}
+
 int board_init(void)
 {
 #ifdef CONFIG_HW_WATCHDOG