uboot/drivers/serial/serial_bcm6345.c
<<
>>
Prefs
   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        clk_free(&clk);
 243
 244        /* initialize serial */
 245        return bcm6345_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
 246}
 247
 248static 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
 255static const struct udevice_id bcm6345_serial_ids[] = {
 256        { .compatible = "brcm,bcm6345-uart" },
 257        { /* sentinel */ }
 258};
 259
 260U_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      = sizeof(struct bcm6345_serial_priv),
 266        .ops = &bcm6345_serial_ops,
 267};
 268
 269#ifdef CONFIG_DEBUG_UART_BCM6345
 270static inline void _debug_uart_init(void)
 271{
 272        void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
 273
 274        bcm6345_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
 275}
 276
 277static inline void wait_xfered(void __iomem *base)
 278{
 279        do {
 280                u32 val = readl(base + UART_IR_REG);
 281                if (val & UART_IR_STAT(UART_IR_TXEMPTY))
 282                        break;
 283        } while (1);
 284}
 285
 286static inline void _debug_uart_putc(int ch)
 287{
 288        void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
 289
 290        wait_xfered(base);
 291        writel(ch, base + UART_FIFO_REG);
 292        wait_xfered(base);
 293}
 294
 295DEBUG_UART_FUNCS
 296#endif
 297