Home | History | Annotate | Download | only in serial
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2017 lvaro Fernndez Rojas <noltari (at) gmail.com>
      4  *
      5  * Derived from linux/drivers/tty/serial/bcm63xx_uart.c:
      6  *	Copyright (C) 2008 Maxime Bizon <mbizon (at) freebox.fr>
      7  */
      8 
      9 #include <clk.h>
     10 #include <dm.h>
     11 #include <debug_uart.h>
     12 #include <errno.h>
     13 #include <serial.h>
     14 #include <asm/io.h>
     15 #include <asm/types.h>
     16 
     17 /* UART Control register */
     18 #define UART_CTL_REG			0x0
     19 #define UART_CTL_RXTIMEOUT_MASK		0x1f
     20 #define UART_CTL_RXTIMEOUT_5		0x5
     21 #define UART_CTL_RSTRXFIFO_SHIFT	6
     22 #define UART_CTL_RSTRXFIFO_MASK		(1 << UART_CTL_RSTRXFIFO_SHIFT)
     23 #define UART_CTL_RSTTXFIFO_SHIFT	7
     24 #define UART_CTL_RSTTXFIFO_MASK		(1 << UART_CTL_RSTTXFIFO_SHIFT)
     25 #define UART_CTL_STOPBITS_SHIFT		8
     26 #define UART_CTL_STOPBITS_MASK		(0xf << UART_CTL_STOPBITS_SHIFT)
     27 #define UART_CTL_STOPBITS_1		(0x7 << UART_CTL_STOPBITS_SHIFT)
     28 #define UART_CTL_BITSPERSYM_SHIFT	12
     29 #define UART_CTL_BITSPERSYM_MASK	(0x3 << UART_CTL_BITSPERSYM_SHIFT)
     30 #define UART_CTL_BITSPERSYM_8		(0x3 << UART_CTL_BITSPERSYM_SHIFT)
     31 #define UART_CTL_XMITBRK_SHIFT		14
     32 #define UART_CTL_XMITBRK_MASK		(1 << UART_CTL_XMITBRK_SHIFT)
     33 #define UART_CTL_RSVD_SHIFT		15
     34 #define UART_CTL_RSVD_MASK		(1 << UART_CTL_RSVD_SHIFT)
     35 #define UART_CTL_RXPAREVEN_SHIFT	16
     36 #define UART_CTL_RXPAREVEN_MASK		(1 << UART_CTL_RXPAREVEN_SHIFT)
     37 #define UART_CTL_RXPAREN_SHIFT		17
     38 #define UART_CTL_RXPAREN_MASK		(1 << UART_CTL_RXPAREN_SHIFT)
     39 #define UART_CTL_TXPAREVEN_SHIFT	18
     40 #define UART_CTL_TXPAREVEN_MASK		(1 << UART_CTL_TXPAREVEN_SHIFT)
     41 #define UART_CTL_TXPAREN_SHIFT		19
     42 #define UART_CTL_TXPAREN_MASK		(1 << UART_CTL_TXPAREN_SHIFT)
     43 #define UART_CTL_LOOPBACK_SHIFT		20
     44 #define UART_CTL_LOOPBACK_MASK		(1 << UART_CTL_LOOPBACK_SHIFT)
     45 #define UART_CTL_RXEN_SHIFT		21
     46 #define UART_CTL_RXEN_MASK		(1 << UART_CTL_RXEN_SHIFT)
     47 #define UART_CTL_TXEN_SHIFT		22
     48 #define UART_CTL_TXEN_MASK		(1 << UART_CTL_TXEN_SHIFT)
     49 #define UART_CTL_BRGEN_SHIFT		23
     50 #define UART_CTL_BRGEN_MASK		(1 << UART_CTL_BRGEN_SHIFT)
     51 
     52 /* UART Baudword register */
     53 #define UART_BAUD_REG			0x4
     54 
     55 /* UART FIFO Config register */
     56 #define UART_FIFO_CFG_REG		0x8
     57 #define UART_FIFO_CFG_RX_SHIFT		8
     58 #define UART_FIFO_CFG_RX_MASK		(0xf << UART_FIFO_CFG_RX_SHIFT)
     59 #define UART_FIFO_CFG_RX_4		(0x4 << UART_FIFO_CFG_RX_SHIFT)
     60 #define UART_FIFO_CFG_TX_SHIFT		12
     61 #define UART_FIFO_CFG_TX_MASK		(0xf << UART_FIFO_CFG_TX_SHIFT)
     62 #define UART_FIFO_CFG_TX_4		(0x4 << UART_FIFO_CFG_TX_SHIFT)
     63 
     64 /* UART Interrupt register */
     65 #define UART_IR_REG			0x10
     66 #define UART_IR_STAT(x)			(1 << (x))
     67 #define UART_IR_TXEMPTY			5
     68 #define UART_IR_RXOVER			7
     69 #define UART_IR_RXNOTEMPTY		11
     70 
     71 /* UART FIFO register */
     72 #define UART_FIFO_REG			0x14
     73 #define UART_FIFO_VALID_MASK		0xff
     74 #define UART_FIFO_FRAMEERR_SHIFT	8
     75 #define UART_FIFO_FRAMEERR_MASK		(1 << UART_FIFO_FRAMEERR_SHIFT)
     76 #define UART_FIFO_PARERR_SHIFT		9
     77 #define UART_FIFO_PARERR_MASK		(1 << UART_FIFO_PARERR_SHIFT)
     78 #define UART_FIFO_BRKDET_SHIFT		10
     79 #define UART_FIFO_BRKDET_MASK		(1 << UART_FIFO_BRKDET_SHIFT)
     80 #define UART_FIFO_ANYERR_MASK		(UART_FIFO_FRAMEERR_MASK |	\
     81 					UART_FIFO_PARERR_MASK |		\
     82 					UART_FIFO_BRKDET_MASK)
     83 
     84 struct bcm6345_serial_priv {
     85 	void __iomem *base;
     86 	ulong uartclk;
     87 };
     88 
     89 /* enable rx & tx operation on uart */
     90 static void bcm6345_serial_enable(void __iomem *base)
     91 {
     92 	setbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
     93 		     UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
     94 }
     95 
     96 /* disable rx & tx operation on uart */
     97 static void bcm6345_serial_disable(void __iomem *base)
     98 {
     99 	clrbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
    100 		     UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
    101 }
    102 
    103 /* clear all unread data in rx fifo and unsent data in tx fifo */
    104 static void bcm6345_serial_flush(void __iomem *base)
    105 {
    106 	/* empty rx and tx fifo */
    107 	setbits_be32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK |
    108 		     UART_CTL_RSTTXFIFO_MASK);
    109 
    110 	/* read any pending char to make sure all irq status are cleared */
    111 	readl_be(base + UART_FIFO_REG);
    112 }
    113 
    114 static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate)
    115 {
    116 	u32 val;
    117 
    118 	/* mask all irq and flush port */
    119 	bcm6345_serial_disable(base);
    120 	bcm6345_serial_flush(base);
    121 
    122 	/* set uart control config */
    123 	clrsetbits_be32(base + UART_CTL_REG,
    124 			/* clear rx timeout */
    125 			UART_CTL_RXTIMEOUT_MASK |
    126 			/* clear stop bits */
    127 			UART_CTL_STOPBITS_MASK |
    128 			/* clear bits per symbol */
    129 			UART_CTL_BITSPERSYM_MASK |
    130 			/* clear xmit break */
    131 			UART_CTL_XMITBRK_MASK |
    132 			/* clear reserved bit */
    133 			UART_CTL_RSVD_MASK |
    134 			/* disable parity */
    135 			UART_CTL_RXPAREN_MASK |
    136 			UART_CTL_TXPAREN_MASK |
    137 			/* disable loopback */
    138 			UART_CTL_LOOPBACK_MASK,
    139 			/* set timeout to 5 */
    140 			UART_CTL_RXTIMEOUT_5 |
    141 			/* set 8 bits/symbol */
    142 			UART_CTL_BITSPERSYM_8 |
    143 			/* set 1 stop bit */
    144 			UART_CTL_STOPBITS_1 |
    145 			/* set parity to even */
    146 			UART_CTL_RXPAREVEN_MASK |
    147 			UART_CTL_TXPAREVEN_MASK);
    148 
    149 	/* set uart fifo config */
    150 	clrsetbits_be32(base + UART_FIFO_CFG_REG,
    151 			/* clear fifo config */
    152 			UART_FIFO_CFG_RX_MASK |
    153 			UART_FIFO_CFG_TX_MASK,
    154 			/* set fifo config to 4 */
    155 			UART_FIFO_CFG_RX_4 |
    156 			UART_FIFO_CFG_TX_4);
    157 
    158 	/* set baud rate */
    159 	val = ((clk / baudrate) >> 4);
    160 	if (val & 0x1)
    161 		val = (val >> 1);
    162 	else
    163 		val = (val >> 1) - 1;
    164 	writel_be(val, base + UART_BAUD_REG);
    165 
    166 	/* clear interrupts */
    167 	writel_be(0, base + UART_IR_REG);
    168 
    169 	/* enable uart */
    170 	bcm6345_serial_enable(base);
    171 
    172 	return 0;
    173 }
    174 
    175 static int bcm6345_serial_pending(struct udevice *dev, bool input)
    176 {
    177 	struct bcm6345_serial_priv *priv = dev_get_priv(dev);
    178 	u32 val = readl_be(priv->base + UART_IR_REG);
    179 
    180 	if (input)
    181 		return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY));
    182 	else
    183 		return !(val & UART_IR_STAT(UART_IR_TXEMPTY));
    184 }
    185 
    186 static int bcm6345_serial_setbrg(struct udevice *dev, int baudrate)
    187 {
    188 	struct bcm6345_serial_priv *priv = dev_get_priv(dev);
    189 
    190 	return bcm6345_serial_init(priv->base, priv->uartclk, baudrate);
    191 }
    192 
    193 static int bcm6345_serial_putc(struct udevice *dev, const char ch)
    194 {
    195 	struct bcm6345_serial_priv *priv = dev_get_priv(dev);
    196 	u32 val;
    197 
    198 	val = readl_be(priv->base + UART_IR_REG);
    199 	if (!(val & UART_IR_STAT(UART_IR_TXEMPTY)))
    200 		return -EAGAIN;
    201 
    202 	writel_be(ch, priv->base + UART_FIFO_REG);
    203 
    204 	return 0;
    205 }
    206 
    207 static int bcm6345_serial_getc(struct udevice *dev)
    208 {
    209 	struct bcm6345_serial_priv *priv = dev_get_priv(dev);
    210 	u32 val;
    211 
    212 	val = readl_be(priv->base + UART_IR_REG);
    213 	if (val & UART_IR_STAT(UART_IR_RXOVER))
    214 		setbits_be32(priv->base + UART_CTL_REG,
    215 			     UART_CTL_RSTRXFIFO_MASK);
    216 	if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
    217 		return -EAGAIN;
    218 
    219 	val = readl_be(priv->base + UART_FIFO_REG);
    220 	if (val & UART_FIFO_ANYERR_MASK)
    221 		return -EAGAIN;
    222 
    223 	return val & UART_FIFO_VALID_MASK;
    224 }
    225 
    226 static int bcm6345_serial_probe(struct udevice *dev)
    227 {
    228 	struct bcm6345_serial_priv *priv = dev_get_priv(dev);
    229 	struct clk clk;
    230 	int ret;
    231 
    232 	/* get address */
    233 	priv->base = dev_remap_addr(dev);
    234 	if (!priv->base)
    235 		return -EINVAL;
    236 
    237 	/* get clock rate */
    238 	ret = clk_get_by_index(dev, 0, &clk);
    239 	if (ret < 0)
    240 		return ret;
    241 	priv->uartclk = clk_get_rate(&clk);
    242 	clk_free(&clk);
    243 
    244 	/* initialize serial */
    245 	return bcm6345_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
    246 }
    247 
    248 static const struct dm_serial_ops bcm6345_serial_ops = {
    249 	.putc = bcm6345_serial_putc,
    250 	.pending = bcm6345_serial_pending,
    251 	.getc = bcm6345_serial_getc,
    252 	.setbrg = bcm6345_serial_setbrg,
    253 };
    254 
    255 static const struct udevice_id bcm6345_serial_ids[] = {
    256 	{ .compatible = "brcm,bcm6345-uart" },
    257 	{ /* sentinel */ }
    258 };
    259 
    260 U_BOOT_DRIVER(bcm6345_serial) = {
    261 	.name = "bcm6345-uart",
    262 	.id = UCLASS_SERIAL,
    263 	.of_match = bcm6345_serial_ids,
    264 	.probe = bcm6345_serial_probe,
    265 	.priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
    266 	.ops = &bcm6345_serial_ops,
    267 	.flags = DM_FLAG_PRE_RELOC,
    268 };
    269 
    270 #ifdef CONFIG_DEBUG_UART_BCM6345
    271 static inline void _debug_uart_init(void)
    272 {
    273 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
    274 
    275 	bcm6345_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
    276 }
    277 
    278 static inline void wait_xfered(void __iomem *base)
    279 {
    280 	do {
    281 		u32 val = readl_be(base + UART_IR_REG);
    282 		if (val & UART_IR_STAT(UART_IR_TXEMPTY))
    283 			break;
    284 	} while (1);
    285 }
    286 
    287 static inline void _debug_uart_putc(int ch)
    288 {
    289 	void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
    290 
    291 	wait_xfered(base);
    292 	writel_be(ch, base + UART_FIFO_REG);
    293 	wait_xfered(base);
    294 }
    295 
    296 DEBUG_UART_FUNCS
    297 #endif
    298