bcm2835_pl011_serial: Add BCM2835 specific serial driver

On bcm2835 we need to ensure we only access serial devices that are
muxed to the serial output pins of the pin header. To achieve this
for the pl011 device, add a bcm2835 specific pl011 wrapper device
that does this check but otherwise behaves like a pl011 device.

Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Alexander Graf 2018-01-25 12:05:55 +01:00 committed by Tom Rini
parent 958d55f26c
commit 6001985f92
6 changed files with 101 additions and 9 deletions

View file

@ -99,6 +99,7 @@ F: drivers/gpio/bcm2835_gpio.c
F: drivers/mmc/bcm2835_sdhci.c
F: drivers/mmc/bcm2835_sdhost.c
F: drivers/serial/serial_bcm283x_mu.c
F: drivers/serial/serial_bcm283x_pl011.c
F: drivers/video/bcm2835.c
F: include/dm/platform_data/serial_bcm283x_mu.h
F: drivers/pinctrl/broadcom/

View file

@ -395,6 +395,15 @@ config BCM283X_MU_SERIAL
help
Select this to enable Mini-UART support on BCM283X family of SoCs.
config BCM283X_PL011_SERIAL
bool "Support for BCM283x PL011 UART"
depends on PL01X_SERIAL && ARCH_BCM283X
default y
help
Select this to enable an overriding PL011 driver for BCM283X SoCs
that supports automatic disable, so that it only gets used when
the UART is actually muxed.
config BCM6345_SERIAL
bool "Support for BCM6345 UART"
depends on DM_SERIAL && ARCH_BMIPS

View file

@ -46,6 +46,7 @@ obj-$(CONFIG_STI_ASC_SERIAL) += serial_sti_asc.o
obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o
obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o
obj-$(CONFIG_BCM283X_PL011_SERIAL) += serial_bcm283x_pl011.o
obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o
obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2018 Alexander Graf <agraf@suse.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <asm/gpio.h>
#include <dm/pinctrl.h>
#include <dm/platform_data/serial_pl01x.h>
#include "serial_pl01x_internal.h"
/*
* Check if this serial device is muxed
*
* The serial device will only work properly if it has been muxed to the serial
* pins by firmware. Check whether that happened here.
*
* @return true if serial device is muxed, false if not
*/
static bool bcm283x_is_serial_muxed(void)
{
int serial_gpio = 15;
struct udevice *dev;
if (uclass_first_device(UCLASS_PINCTRL, &dev) || !dev)
return false;
if (pinctrl_get_gpio_mux(dev, 0, serial_gpio) != BCM2835_GPIO_ALT0)
return false;
return true;
}
static int bcm283x_pl011_serial_ofdata_to_platdata(struct udevice *dev)
{
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
int ret;
/* Don't spawn the device if it's not muxed */
if (!bcm283x_is_serial_muxed())
return -ENODEV;
ret = pl01x_serial_ofdata_to_platdata(dev);
if (ret)
return ret;
/*
* TODO: Reinitialization doesn't always work for now, just skip
* init always - we know we're already initialized
*/
plat->skip_init = true;
return 0;
}
static const struct udevice_id bcm283x_pl011_serial_id[] = {
{.compatible = "brcm,bcm2835-pl011", .data = TYPE_PL011},
{}
};
U_BOOT_DRIVER(bcm283x_pl011_uart) = {
.name = "bcm283x_pl011",
.id = UCLASS_SERIAL,
.of_match = of_match_ptr(bcm283x_pl011_serial_id),
.ofdata_to_platdata = of_match_ptr(bcm283x_pl011_serial_ofdata_to_platdata),
.platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
.probe = pl01x_serial_probe,
.ops = &pl01x_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
.priv_auto_alloc_size = sizeof(struct pl01x_priv),
};

View file

@ -273,11 +273,6 @@ __weak struct serial_device *default_serial_console(void)
#ifdef CONFIG_DM_SERIAL
struct pl01x_priv {
struct pl01x_regs *regs;
enum pl01x_type type;
};
static int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
{
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
@ -291,7 +286,7 @@ static int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
return 0;
}
static int pl01x_serial_probe(struct udevice *dev)
int pl01x_serial_probe(struct udevice *dev)
{
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
struct pl01x_priv *priv = dev_get_priv(dev);
@ -329,7 +324,7 @@ static int pl01x_serial_pending(struct udevice *dev, bool input)
return fr & UART_PL01x_FR_TXFF ? 0 : 1;
}
static const struct dm_serial_ops pl01x_serial_ops = {
const struct dm_serial_ops pl01x_serial_ops = {
.putc = pl01x_serial_putc,
.pending = pl01x_serial_pending,
.getc = pl01x_serial_getc,
@ -343,7 +338,7 @@ static const struct udevice_id pl01x_serial_id[] ={
{}
};
static int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
{
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
fdt_addr_t addr;

View file

@ -38,7 +38,20 @@ struct pl01x_regs {
u32 pl011_lcrh; /* 0x2C Line control register */
u32 pl011_cr; /* 0x30 Control register */
};
#endif
#ifdef CONFIG_DM_SERIAL
int pl01x_serial_ofdata_to_platdata(struct udevice *dev);
int pl01x_serial_probe(struct udevice *dev);
extern const struct dm_serial_ops pl01x_serial_ops;
struct pl01x_priv {
struct pl01x_regs *regs;
enum pl01x_type type;
};
#endif /* CONFIG_DM_SERIAL */
#endif /* !__ASSEMBLY__ */
#define UART_PL01x_RSR_OE 0x08
#define UART_PL01x_RSR_BE 0x04