[U-Boot] [PATCH] rpi: Support both UART interfaces.

Alex Deymo deymo at google.com
Sun Apr 2 08:26:33 UTC 2017


The Raspberry Pi 3 has two UART interfaces that can be pinmuxed to the
header pins. The PL011 is by default muxed to the Bluetooth chip and
the mini-UART can be muxed to the pin headers passing "enabled_uart=1"
in the config.txt file.

Passing "enable_uart=1" has other implications, since the baudrate of
the miniuart depends on the clock frequency of the main core, which
is normally dynamic unless enable_uart=1 is set. If Bluetooth is not
used or not required, it is possible to set the PL011 UART to the
header pins passing either "dtoverlay=pi3-disable-bt" or
"dtoverlay=pi3-miniuart-bt" to disable Bluetooth or use it via the
miniuart respectively.

This patch disables (for U-Boot) the UARTs modules not muxed to the
header pins so the serial port is used only if available in the
header pins, avoiding writing to the Bluetooth chip if needed. This
allows to enable the PL01X driver for the Raspberry Pi 3, previously
disabled for that board, which can be used for the U-Boot console if
properly configured in the device tree.

Note that in order to get the PL01X driver in the Raspberry Pi 3 to
work with U-Boot the device tree must set "skip-init" in the uart0
block, for example this device tree fragment would do it:

	fragment at 0 {
		target = <&uart0>;
		__overlay__ {
			skip-init;
		};
	};

Test: Booted a rpi3 with either UART output.
Signed-off-by: Alex Deymo <deymo at google.com>
---
 board/raspberrypi/rpi/rpi.c             | 78 +++++++++++++++++++++++----------
 drivers/serial/serial_pl01x.c           |  3 ++
 include/configs/rpi.h                   |  8 +++-
 include/dm/platform_data/serial_pl01x.h |  2 +
 4 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 2146534b36..58f07953f5 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -18,6 +18,7 @@
 #include <asm/arch/mbox.h>
 #include <asm/arch/sdhci.h>
 #include <asm/global_data.h>
+#include <dm/platform_data/serial_pl01x.h>
 #include <dm/platform_data/serial_bcm283x_mu.h>
 #ifdef CONFIG_ARM64
 #include <asm/armv8/mmu.h>
@@ -442,8 +443,19 @@ static void get_board_rev(void)
 	printf("RPI %s (0x%x)\n", model->name, revision);
 }
 
-#ifndef CONFIG_PL01X_SERIAL
-static bool rpi_is_serial_active(void)
+/* An enum describing the pin muxing selection for the UART RX/TX pins. */
+enum rpi_uart_mux {
+	/* The pin is associated with the internal "miniuart" block. */
+	RPI_UART_BCM283X_MU,
+
+	/* The pin is associated with the PL01X uart driver. */
+	RPI_UART_PL01X,
+
+	/* The pin is associated with a different function. */
+	RPI_UART_OTHER,
+};
+
+static enum rpi_uart_mux rpi_get_uart_mux_setting(void)
 {
 	int serial_gpio = 15;
 	struct udevice *dev;
@@ -452,41 +464,61 @@ static bool rpi_is_serial_active(void)
 	 * The RPi3 disables the mini uart by default. The easiest way to find
 	 * out whether it is available is to check if the RX pin is muxed.
 	 */
-
 	if (uclass_first_device(UCLASS_GPIO, &dev) || !dev)
-		return true;
-
-	if (bcm2835_gpio_get_func_id(dev, serial_gpio) != BCM2835_GPIO_ALT5)
-		return false;
+		return RPI_UART_OTHER;
 
-	return true;
+	switch (bcm2835_gpio_get_func_id(dev, serial_gpio)) {
+	case BCM2835_GPIO_ALT5:
+		return RPI_UART_BCM283X_MU;
+	case BCM2835_GPIO_ALT0:
+		return RPI_UART_PL01X;
+	}
+	return RPI_UART_OTHER;
 }
 
-/* Disable mini-UART I/O if it's not pinmuxed to our pins.
- * The firmware only enables it if explicitly done in config.txt: enable_uart=1
+/* Disable UART I/O for the mini-UART and PL01X UART if they are not pinmuxed to
+ * the Raspberry Pi header. The mini-UART is only enabled in the header if
+ * explicitly done in config.txt: enable_uart=1, and the PL01X is only enabled
+ * if not used for Bluetooth and explicitly exposed in config.txt as either
+ * dtoverlay=pi3-disable-bt or dtoverlay=pi3-miniuart-bt.
  */
-static void rpi_disable_inactive_uart(void)
+static void rpi_disable_inactive_uarts(void)
 {
 	struct udevice *dev;
-	struct bcm283x_mu_serial_platdata *plat;
+	enum rpi_uart_mux mux;
 
-	if (uclass_get_device_by_driver(UCLASS_SERIAL,
-					DM_GET_DRIVER(serial_bcm283x_mu),
-					&dev) || !dev)
-		return;
+	mux = rpi_get_uart_mux_setting();
+
+#ifdef CONFIG_BCM283X_MU_SERIAL
+	struct bcm283x_mu_serial_platdata *bcm283x_mu_plat;
 
-	if (!rpi_is_serial_active()) {
-		plat = dev_get_platdata(dev);
-		plat->disabled = true;
+	if (mux != RPI_UART_BCM283X_MU &&
+	    !uclass_get_device_by_driver(UCLASS_SERIAL,
+					 DM_GET_DRIVER(serial_bcm283x_mu),
+					 &dev) &&
+	    dev) {
+		bcm283x_mu_plat = dev_get_platdata(dev);
+		bcm283x_mu_plat->disabled = true;
 	}
+#endif  /* CONFIG_BCM283X_MU_SERIAL */
+
+#ifdef CONFIG_PL01X_SERIAL
+	struct pl01x_serial_platdata *pl01x_plat;
+
+	if (mux != RPI_UART_PL01X &&
+	    !uclass_get_device_by_driver(UCLASS_SERIAL,
+					 DM_GET_DRIVER(serial_pl01x),
+					 &dev) &&
+	    dev) {
+		pl01x_plat = dev_get_platdata(dev);
+		pl01x_plat->disabled = true;
+	}
+#endif  /* CONFIG_PL01X_SERIAL */
 }
-#endif
 
 int board_init(void)
 {
-#ifndef CONFIG_PL01X_SERIAL
-	rpi_disable_inactive_uart();
-#endif
+	rpi_disable_inactive_uarts();
 
 	get_board_rev();
 
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index a49134a95a..7748e7632b 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -297,6 +297,9 @@ static int pl01x_serial_probe(struct udevice *dev)
 	struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
 	struct pl01x_priv *priv = dev_get_priv(dev);
 
+	if (plat->disabled)
+		return -ENODEV;
+
 	priv->regs = (struct pl01x_regs *)plat->base;
 	priv->type = plat->type;
 	if (!plat->skip_init)
diff --git a/include/configs/rpi.h b/include/configs/rpi.h
index 92eb792989..767d5d8e0d 100644
--- a/include/configs/rpi.h
+++ b/include/configs/rpi.h
@@ -94,10 +94,14 @@
 
 /* Console UART */
 #ifdef CONFIG_BCM2837
+/*
+ * Raspberry Pi 3 uses the miniuart by default unless the device tree re-assigns
+ * the PL01X from Bluetooth to the header pins. We enable support for both in
+ * the Raspberry Pi 3 only and disable the unused one at runtime.
+ */
 #define CONFIG_BCM283X_MU_SERIAL
-#else
-#define CONFIG_PL01X_SERIAL
 #endif
+#define CONFIG_PL01X_SERIAL
 #define CONFIG_CONS_INDEX		0
 
 /* Console configuration */
diff --git a/include/dm/platform_data/serial_pl01x.h b/include/dm/platform_data/serial_pl01x.h
index ccfa808e23..1396137d26 100644
--- a/include/dm/platform_data/serial_pl01x.h
+++ b/include/dm/platform_data/serial_pl01x.h
@@ -19,12 +19,14 @@ enum pl01x_type {
  * @clock: Input clock rate, used for calculating the baud rate divisor
  * @skip_init: Don't attempt to change port configuration (also means @clock
  * is ignored)
+ * @disabled: Whether the driver should be disabled and not report any device.
  */
 struct pl01x_serial_platdata {
 	unsigned long base;
 	enum pl01x_type type;
 	unsigned int clock;
 	bool skip_init;
+	bool disabled;
 };
 
 #endif
-- 
2.12.2.564.g063fe858b8-goog



More information about the U-Boot mailing list