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