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

Fabian Vogt fvogt at suse.com
Sun Apr 2 09:29:42 UTC 2017


Hi,

Am Sonntag, 2. April 2017, 09:20:06 CEST schrieb Alex Deymo:
> 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;
> 		};
> 	};

This is already done in arch/arm/dts/bcm283x-uboot.dtsi:

&uart0 {
        skip-init;
        u-boot,dm-pre-reloc;
};

&uart1 {
        skip-init;
        u-boot,dm-pre-reloc;
};

> Test: Booted a rpi3 with either UART output.
> Signed-off-by: Alex Deymo <deymo at google.com>

Acked-by: Fabian Vogt <fvogt at suse.com>

Cheers,
Fabian

> ---
>  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
> 




More information about the U-Boot mailing list