diff options
| author | Tom Rini <[email protected]> | 2018-11-17 08:19:40 -0500 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2018-11-17 08:19:40 -0500 |
| commit | 0c4b382f9041f9f2f00246c8a0ece90dae5451be (patch) | |
| tree | a2307a0658de178c47d7a063c169347e60e1810c /drivers/serial | |
| parent | 1d6edcbfed2af33c748f2beb399810a0441888da (diff) | |
| parent | ad890cace37d0e2d3e0f9649bdb9c320947e4bb0 (diff) | |
Merge branch '2018-11-16-master-imports'
- Initial bcm968580xref, am65x_evm_r5 support
- lpc32xx, omap3_logic/am3517_evm updates
- pinctrl command
- fs_loader available for SPL
Diffstat (limited to 'drivers/serial')
| -rw-r--r-- | drivers/serial/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/serial/Makefile | 1 | ||||
| -rw-r--r-- | drivers/serial/ns16550.c | 43 | ||||
| -rw-r--r-- | drivers/serial/serial_bcm6858.c | 300 |
4 files changed, 348 insertions, 2 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 597db4b9cbb..6625a65b584 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -500,6 +500,12 @@ config BCM6345_SERIAL help Select this to enable UART on BCM6345 SoCs. +config BCM6858_SERIAL + bool "Support for BCM6858 UART" + depends on DM_SERIAL && ARCH_BCM6858 + help + Select this to enable UART on BCM6358 SoCs. + config FSL_LINFLEXUART bool "Freescale Linflex UART support" depends on DM_SERIAL diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 03dc29ee2ec..a48458f9553 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_AR933X_UART) += serial_ar933x.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o +obj-$(CONFIG_BCM6858_SERIAL) += serial_bcm6858.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 1e6fc6c6683..f21c240e64a 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -148,10 +148,13 @@ int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate) static void NS16550_setbrg(NS16550_t com_port, int baud_divisor) { - serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr); + /* to keep serial format, read lcr before writing BKSE */ + int lcr_val = serial_in(&com_port->lcr) & ~UART_LCR_BKSE; + + serial_out(UART_LCR_BKSE | lcr_val, &com_port->lcr); serial_out(baud_divisor & 0xff, &com_port->dll); serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm); - serial_out(UART_LCRVAL, &com_port->lcr); + serial_out(lcr_val, &com_port->lcr); } void NS16550_init(NS16550_t com_port, int baud_divisor) @@ -181,6 +184,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) serial_out(UART_MCRVAL, &com_port->mcr); serial_out(ns16550_getfcr(com_port), &com_port->fcr); + /* initialize serial config to 8N1 before writing baudrate */ + serial_out(UART_LCRVAL, &com_port->lcr); if (baud_divisor != -1) NS16550_setbrg(com_port, baud_divisor); #if defined(CONFIG_ARCH_OMAP2PLUS) || defined(CONFIG_SOC_DA8XX) || \ @@ -348,6 +353,39 @@ static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) return 0; } +static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config) +{ + struct NS16550 *const com_port = dev_get_priv(dev); + int lcr_val = UART_LCR_WLS_8; + uint parity = SERIAL_GET_PARITY(serial_config); + uint bits = SERIAL_GET_BITS(serial_config); + uint stop = SERIAL_GET_STOP(serial_config); + + /* + * only parity config is implemented, check if other serial settings + * are the default one. + */ + if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP) + return -ENOTSUPP; /* not supported in driver*/ + + switch (parity) { + case SERIAL_PAR_NONE: + /* no bits to add */ + break; + case SERIAL_PAR_ODD: + lcr_val |= UART_LCR_PEN; + break; + case SERIAL_PAR_EVEN: + lcr_val |= UART_LCR_PEN | UART_LCR_EPS; + break; + default: + return -ENOTSUPP; /* not supported in driver*/ + } + + serial_out(lcr_val, &com_port->lcr); + return 0; +} + int ns16550_serial_probe(struct udevice *dev) { struct NS16550 *const com_port = dev_get_priv(dev); @@ -454,6 +492,7 @@ const struct dm_serial_ops ns16550_serial_ops = { .pending = ns16550_serial_pending, .getc = ns16550_serial_getc, .setbrg = ns16550_serial_setbrg, + .setconfig = ns16550_serial_setconfig }; #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) diff --git a/drivers/serial/serial_bcm6858.c b/drivers/serial/serial_bcm6858.c new file mode 100644 index 00000000000..8aa37055f0b --- /dev/null +++ b/drivers/serial/serial_bcm6858.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Philippe Reynes <[email protected]> + * + * Derived from linux/drivers/tty/serial/bcm63xx_uart.c: + * Copyright (C) 2008 Maxime Bizon <[email protected]> + * Derived from linux/drivers/tty/serial/serial_bcm6345.c + * Copyright (C) 2017 Álvaro Fernández Rojas <[email protected]> + */ + +#include <clk.h> +#include <dm.h> +#include <debug_uart.h> +#include <errno.h> +#include <serial.h> +#include <asm/io.h> +#include <asm/types.h> + +/* UART Control register */ +#define UART_CTL_REG 0x0 +#define UART_CTL_RXTIMEOUT_MASK 0x1f +#define UART_CTL_RXTIMEOUT_5 0x5 +#define UART_CTL_RSTRXFIFO_SHIFT 6 +#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT) +#define UART_CTL_RSTTXFIFO_SHIFT 7 +#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT) +#define UART_CTL_STOPBITS_SHIFT 8 +#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT) +#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT) +#define UART_CTL_BITSPERSYM_SHIFT 12 +#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT) +#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT) +#define UART_CTL_XMITBRK_SHIFT 14 +#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT) +#define UART_CTL_RSVD_SHIFT 15 +#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT) +#define UART_CTL_RXPAREVEN_SHIFT 16 +#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT) +#define UART_CTL_RXPAREN_SHIFT 17 +#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT) +#define UART_CTL_TXPAREVEN_SHIFT 18 +#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT) +#define UART_CTL_TXPAREN_SHIFT 19 +#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT) +#define UART_CTL_LOOPBACK_SHIFT 20 +#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT) +#define UART_CTL_RXEN_SHIFT 21 +#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT) +#define UART_CTL_TXEN_SHIFT 22 +#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT) +#define UART_CTL_BRGEN_SHIFT 23 +#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT) + +/* UART Baudword register */ +#define UART_BAUD_REG 0x4 + +/* UART FIFO Config register */ +#define UART_FIFO_CFG_REG 0x8 +#define UART_FIFO_CFG_RX_SHIFT 8 +#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT) +#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT) +#define UART_FIFO_CFG_TX_SHIFT 12 +#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT) +#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT) + +/* UART Interrupt register */ +#define UART_IR_REG 0x10 +#define UART_IR_STAT(x) (1 << (x)) +#define UART_IR_TXEMPTY 5 +#define UART_IR_RXOVER 7 +#define UART_IR_RXNOTEMPTY 11 + +/* UART FIFO register */ +#define UART_FIFO_REG 0x14 +#define UART_FIFO_VALID_MASK 0xff +#define UART_FIFO_FRAMEERR_SHIFT 8 +#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT) +#define UART_FIFO_PARERR_SHIFT 9 +#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT) +#define UART_FIFO_BRKDET_SHIFT 10 +#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT) +#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \ + UART_FIFO_PARERR_MASK | \ + UART_FIFO_BRKDET_MASK) + +struct bcm6858_serial_priv { + void __iomem *base; + ulong uartclk; +}; + +/* enable rx & tx operation on uart */ +static void bcm6858_serial_enable(void __iomem *base) +{ + setbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); +} + +/* disable rx & tx operation on uart */ +static void bcm6858_serial_disable(void __iomem *base) +{ + clrbits_le32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK | + UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK); +} + +/* clear all unread data in rx fifo and unsent data in tx fifo */ +static void bcm6858_serial_flush(void __iomem *base) +{ + /* empty rx and tx fifo */ + setbits_le32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK | + UART_CTL_RSTTXFIFO_MASK); + + /* read any pending char to make sure all irq status are cleared */ + readl(base + UART_FIFO_REG); +} + +static int bcm6858_serial_init(void __iomem *base, ulong clk, u32 baudrate) +{ + u32 val; + + /* mask all irq and flush port */ + bcm6858_serial_disable(base); + bcm6858_serial_flush(base); + + /* set uart control config */ + clrsetbits_le32(base + UART_CTL_REG, + /* clear rx timeout */ + UART_CTL_RXTIMEOUT_MASK | + /* clear stop bits */ + UART_CTL_STOPBITS_MASK | + /* clear bits per symbol */ + UART_CTL_BITSPERSYM_MASK | + /* clear xmit break */ + UART_CTL_XMITBRK_MASK | + /* clear reserved bit */ + UART_CTL_RSVD_MASK | + /* disable parity */ + UART_CTL_RXPAREN_MASK | + UART_CTL_TXPAREN_MASK | + /* disable loopback */ + UART_CTL_LOOPBACK_MASK, + /* set timeout to 5 */ + UART_CTL_RXTIMEOUT_5 | + /* set 8 bits/symbol */ + UART_CTL_BITSPERSYM_8 | + /* set 1 stop bit */ + UART_CTL_STOPBITS_1 | + /* set parity to even */ + UART_CTL_RXPAREVEN_MASK | + UART_CTL_TXPAREVEN_MASK); + + /* set uart fifo config */ + clrsetbits_le32(base + UART_FIFO_CFG_REG, + /* clear fifo config */ + UART_FIFO_CFG_RX_MASK | + UART_FIFO_CFG_TX_MASK, + /* set fifo config to 4 */ + UART_FIFO_CFG_RX_4 | + UART_FIFO_CFG_TX_4); + + /* set baud rate */ + val = ((clk / baudrate) >> 4); + if (val & 0x1) + val = (val >> 1); + else + val = (val >> 1) - 1; + writel(val, base + UART_BAUD_REG); + + /* clear interrupts */ + writel(0, base + UART_IR_REG); + + /* enable uart */ + bcm6858_serial_enable(base); + + return 0; +} + +static int bcm6858_serial_pending(struct udevice *dev, bool input) +{ + struct bcm6858_serial_priv *priv = dev_get_priv(dev); + u32 val = readl(priv->base + UART_IR_REG); + + if (input) + return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)); + else + return !(val & UART_IR_STAT(UART_IR_TXEMPTY)); +} + +static int bcm6858_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct bcm6858_serial_priv *priv = dev_get_priv(dev); + + return bcm6858_serial_init(priv->base, priv->uartclk, baudrate); +} + +static int bcm6858_serial_putc(struct udevice *dev, const char ch) +{ + struct bcm6858_serial_priv *priv = dev_get_priv(dev); + u32 val; + + val = readl(priv->base + UART_IR_REG); + if (!(val & UART_IR_STAT(UART_IR_TXEMPTY))) + return -EAGAIN; + + writel(ch, priv->base + UART_FIFO_REG); + + return 0; +} + +static int bcm6858_serial_getc(struct udevice *dev) +{ + struct bcm6858_serial_priv *priv = dev_get_priv(dev); + u32 val; + + val = readl(priv->base + UART_IR_REG); + if (val & UART_IR_STAT(UART_IR_RXOVER)) + setbits_le32(priv->base + UART_CTL_REG, + UART_CTL_RSTRXFIFO_MASK); + + if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY))) + return -EAGAIN; + + val = readl(priv->base + UART_FIFO_REG); + if (val & UART_FIFO_ANYERR_MASK) + return -EAGAIN; + + return val & UART_FIFO_VALID_MASK; +} + +static int bcm6858_serial_probe(struct udevice *dev) +{ + struct bcm6858_serial_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + /* get address */ + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + /* get clock rate */ + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + priv->uartclk = clk_get_rate(&clk); + clk_free(&clk); + + /* initialize serial */ + return bcm6858_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE); +} + +static const struct dm_serial_ops bcm6858_serial_ops = { + .putc = bcm6858_serial_putc, + .pending = bcm6858_serial_pending, + .getc = bcm6858_serial_getc, + .setbrg = bcm6858_serial_setbrg, +}; + +static const struct udevice_id bcm6858_serial_ids[] = { + { .compatible = "brcm,bcm6858-uart" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(bcm6858_serial) = { + .name = "bcm6858-uart", + .id = UCLASS_SERIAL, + .of_match = bcm6858_serial_ids, + .probe = bcm6858_serial_probe, + .priv_auto_alloc_size = sizeof(struct bcm6858_serial_priv), + .ops = &bcm6858_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#ifdef CONFIG_DEBUG_UART_BCM6858 +static inline void _debug_uart_init(void) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + bcm6858_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); +} + +static inline void wait_xfered(void __iomem *base) +{ + do { + u32 val = readl(base + UART_IR_REG); + if (val & UART_IR_STAT(UART_IR_TXEMPTY)) + break; + } while (1); +} + +static inline void _debug_uart_putc(int ch) +{ + void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE; + + wait_xfered(base); + writel(ch, base + UART_FIFO_REG); + wait_xfered(base); +} + +DEBUG_UART_FUNCS +#endif |
