uboot/drivers/serial/serial_mtk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * MediaTek High-speed UART driver
   4 *
   5 * Copyright (C) 2018 MediaTek Inc.
   6 * Author: Weijie Gao <weijie.gao@mediatek.com>
   7 */
   8
   9#include <clk.h>
  10#include <common.h>
  11#include <div64.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <log.h>
  15#include <serial.h>
  16#include <watchdog.h>
  17#include <asm/global_data.h>
  18#include <asm/io.h>
  19#include <asm/types.h>
  20#include <linux/err.h>
  21
  22struct mtk_serial_regs {
  23        u32 rbr;
  24        u32 ier;
  25        u32 fcr;
  26        u32 lcr;
  27        u32 mcr;
  28        u32 lsr;
  29        u32 msr;
  30        u32 spr;
  31        u32 mdr1;
  32        u32 highspeed;
  33        u32 sample_count;
  34        u32 sample_point;
  35        u32 fracdiv_l;
  36        u32 fracdiv_m;
  37        u32 escape_en;
  38        u32 guard;
  39        u32 rx_sel;
  40};
  41
  42#define thr rbr
  43#define iir fcr
  44#define dll rbr
  45#define dlm ier
  46
  47#define UART_LCR_WLS_8  0x03            /* 8 bit character length */
  48#define UART_LCR_DLAB   0x80            /* Divisor latch access bit */
  49
  50#define UART_LSR_DR     0x01            /* Data ready */
  51#define UART_LSR_THRE   0x20            /* Xmit holding register empty */
  52#define UART_LSR_TEMT   0x40            /* Xmitter empty */
  53
  54#define UART_MCR_DTR    0x01            /* DTR   */
  55#define UART_MCR_RTS    0x02            /* RTS   */
  56
  57#define UART_FCR_FIFO_EN        0x01    /* Fifo enable */
  58#define UART_FCR_RXSR           0x02    /* Receiver soft reset */
  59#define UART_FCR_TXSR           0x04    /* Transmitter soft reset */
  60
  61#define UART_MCRVAL (UART_MCR_DTR | \
  62                     UART_MCR_RTS)
  63
  64/* Clear & enable FIFOs */
  65#define UART_FCRVAL (UART_FCR_FIFO_EN | \
  66                     UART_FCR_RXSR |    \
  67                     UART_FCR_TXSR)
  68
  69/* the data is correct if the real baud is within 3%. */
  70#define BAUD_ALLOW_MAX(baud)    ((baud) + (baud) * 3 / 100)
  71#define BAUD_ALLOW_MIX(baud)    ((baud) - (baud) * 3 / 100)
  72
  73struct mtk_serial_priv {
  74        struct mtk_serial_regs __iomem *regs;
  75        u32 clock;
  76        bool force_highspeed;
  77};
  78
  79static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
  80{
  81        u32 quot, realbaud, samplecount = 1;
  82
  83        /* Special case for low baud clock */
  84        if (baud <= 115200 && priv->clock <= 12000000) {
  85                writel(3, &priv->regs->highspeed);
  86
  87                quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
  88                if (quot == 0)
  89                        quot = 1;
  90
  91                samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
  92
  93                realbaud = priv->clock / samplecount / quot;
  94                if (realbaud > BAUD_ALLOW_MAX(baud) ||
  95                    realbaud < BAUD_ALLOW_MIX(baud)) {
  96                        pr_info("baud %d can't be handled\n", baud);
  97                }
  98
  99                goto set_baud;
 100        }
 101
 102        if (priv->force_highspeed)
 103                goto use_hs3;
 104
 105        if (baud <= 115200) {
 106                writel(0, &priv->regs->highspeed);
 107                quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
 108        } else if (baud <= 576000) {
 109                writel(2, &priv->regs->highspeed);
 110
 111                /* Set to next lower baudrate supported */
 112                if ((baud == 500000) || (baud == 576000))
 113                        baud = 460800;
 114
 115                quot = DIV_ROUND_UP(priv->clock, 4 * baud);
 116        } else {
 117use_hs3:
 118                writel(3, &priv->regs->highspeed);
 119
 120                quot = DIV_ROUND_UP(priv->clock, 256 * baud);
 121                samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
 122        }
 123
 124set_baud:
 125        /* set divisor */
 126        writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
 127        writel(quot & 0xff, &priv->regs->dll);
 128        writel((quot >> 8) & 0xff, &priv->regs->dlm);
 129        writel(UART_LCR_WLS_8, &priv->regs->lcr);
 130
 131        /* set highspeed mode sample count & point */
 132        writel(samplecount - 1, &priv->regs->sample_count);
 133        writel((samplecount - 2) >> 1, &priv->regs->sample_point);
 134}
 135
 136static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch)
 137{
 138        if (!(readl(&priv->regs->lsr) & UART_LSR_THRE))
 139                return -EAGAIN;
 140
 141        writel(ch, &priv->regs->thr);
 142
 143        if (ch == '\n')
 144                WATCHDOG_RESET();
 145
 146        return 0;
 147}
 148
 149static int _mtk_serial_getc(struct mtk_serial_priv *priv)
 150{
 151        if (!(readl(&priv->regs->lsr) & UART_LSR_DR))
 152                return -EAGAIN;
 153
 154        return readl(&priv->regs->rbr);
 155}
 156
 157static int _mtk_serial_pending(struct mtk_serial_priv *priv, bool input)
 158{
 159        if (input)
 160                return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0;
 161        else
 162                return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
 163}
 164
 165#if defined(CONFIG_DM_SERIAL) && \
 166        (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_DM))
 167static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
 168{
 169        struct mtk_serial_priv *priv = dev_get_priv(dev);
 170
 171        _mtk_serial_setbrg(priv, baudrate);
 172
 173        return 0;
 174}
 175
 176static int mtk_serial_putc(struct udevice *dev, const char ch)
 177{
 178        struct mtk_serial_priv *priv = dev_get_priv(dev);
 179
 180        return _mtk_serial_putc(priv, ch);
 181}
 182
 183static int mtk_serial_getc(struct udevice *dev)
 184{
 185        struct mtk_serial_priv *priv = dev_get_priv(dev);
 186
 187        return _mtk_serial_getc(priv);
 188}
 189
 190static int mtk_serial_pending(struct udevice *dev, bool input)
 191{
 192        struct mtk_serial_priv *priv = dev_get_priv(dev);
 193
 194        return _mtk_serial_pending(priv, input);
 195}
 196
 197static int mtk_serial_probe(struct udevice *dev)
 198{
 199        struct mtk_serial_priv *priv = dev_get_priv(dev);
 200
 201        /* Disable interrupt */
 202        writel(0, &priv->regs->ier);
 203
 204        writel(UART_MCRVAL, &priv->regs->mcr);
 205        writel(UART_FCRVAL, &priv->regs->fcr);
 206
 207        return 0;
 208}
 209
 210static int mtk_serial_of_to_plat(struct udevice *dev)
 211{
 212        struct mtk_serial_priv *priv = dev_get_priv(dev);
 213        fdt_addr_t addr;
 214        struct clk clk;
 215        int err;
 216
 217        addr = dev_read_addr(dev);
 218        if (addr == FDT_ADDR_T_NONE)
 219                return -EINVAL;
 220
 221        priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
 222
 223        err = clk_get_by_index(dev, 0, &clk);
 224        if (!err) {
 225                err = clk_get_rate(&clk);
 226                if (!IS_ERR_VALUE(err))
 227                        priv->clock = err;
 228        } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
 229                debug("mtk_serial: failed to get clock\n");
 230                return err;
 231        }
 232
 233        if (!priv->clock)
 234                priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
 235
 236        if (!priv->clock) {
 237                debug("mtk_serial: clock not defined\n");
 238                return -EINVAL;
 239        }
 240
 241        priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed");
 242
 243        return 0;
 244}
 245
 246static const struct dm_serial_ops mtk_serial_ops = {
 247        .putc = mtk_serial_putc,
 248        .pending = mtk_serial_pending,
 249        .getc = mtk_serial_getc,
 250        .setbrg = mtk_serial_setbrg,
 251};
 252
 253static const struct udevice_id mtk_serial_ids[] = {
 254        { .compatible = "mediatek,hsuart" },
 255        { .compatible = "mediatek,mt6577-uart" },
 256        { }
 257};
 258
 259U_BOOT_DRIVER(serial_mtk) = {
 260        .name = "serial_mtk",
 261        .id = UCLASS_SERIAL,
 262        .of_match = mtk_serial_ids,
 263        .of_to_plat = mtk_serial_of_to_plat,
 264        .priv_auto      = sizeof(struct mtk_serial_priv),
 265        .probe = mtk_serial_probe,
 266        .ops = &mtk_serial_ops,
 267        .flags = DM_FLAG_PRE_RELOC,
 268};
 269#else
 270
 271DECLARE_GLOBAL_DATA_PTR;
 272
 273#define DECLARE_HSUART_PRIV(port) \
 274        static struct mtk_serial_priv mtk_hsuart##port = { \
 275        .regs = (struct mtk_serial_regs *)CONFIG_SYS_NS16550_COM##port, \
 276        .clock = CONFIG_SYS_NS16550_CLK \
 277};
 278
 279#define DECLARE_HSUART_FUNCTIONS(port) \
 280        static int mtk_serial##port##_init(void) \
 281        { \
 282                writel(0, &mtk_hsuart##port.regs->ier); \
 283                writel(UART_MCRVAL, &mtk_hsuart##port.regs->mcr); \
 284                writel(UART_FCRVAL, &mtk_hsuart##port.regs->fcr); \
 285                _mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
 286                return 0 ; \
 287        } \
 288        static void mtk_serial##port##_setbrg(void) \
 289        { \
 290                _mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
 291        } \
 292        static int mtk_serial##port##_getc(void) \
 293        { \
 294                int err; \
 295                do { \
 296                        err = _mtk_serial_getc(&mtk_hsuart##port); \
 297                        if (err == -EAGAIN) \
 298                                WATCHDOG_RESET(); \
 299                } while (err == -EAGAIN); \
 300                return err >= 0 ? err : 0; \
 301        } \
 302        static int mtk_serial##port##_tstc(void) \
 303        { \
 304                return _mtk_serial_pending(&mtk_hsuart##port, true); \
 305        } \
 306        static void mtk_serial##port##_putc(const char c) \
 307        { \
 308                int err; \
 309                if (c == '\n') \
 310                        mtk_serial##port##_putc('\r'); \
 311                do { \
 312                        err = _mtk_serial_putc(&mtk_hsuart##port, c); \
 313                } while (err == -EAGAIN); \
 314        } \
 315        static void mtk_serial##port##_puts(const char *s) \
 316        { \
 317                while (*s) { \
 318                        mtk_serial##port##_putc(*s++); \
 319                } \
 320        }
 321
 322/* Serial device descriptor */
 323#define INIT_HSUART_STRUCTURE(port, __name) {   \
 324        .name   = __name,                       \
 325        .start  = mtk_serial##port##_init,      \
 326        .stop   = NULL,                         \
 327        .setbrg = mtk_serial##port##_setbrg,    \
 328        .getc   = mtk_serial##port##_getc,      \
 329        .tstc   = mtk_serial##port##_tstc,      \
 330        .putc   = mtk_serial##port##_putc,      \
 331        .puts   = mtk_serial##port##_puts,      \
 332}
 333
 334#define DECLARE_HSUART(port, __name) \
 335        DECLARE_HSUART_PRIV(port); \
 336        DECLARE_HSUART_FUNCTIONS(port); \
 337        struct serial_device mtk_hsuart##port##_device = \
 338                INIT_HSUART_STRUCTURE(port, __name);
 339
 340#if !defined(CONFIG_CONS_INDEX)
 341#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6)
 342#error  "Invalid console index value."
 343#endif
 344
 345#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
 346#error  "Console port 1 defined but not configured."
 347#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
 348#error  "Console port 2 defined but not configured."
 349#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
 350#error  "Console port 3 defined but not configured."
 351#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
 352#error  "Console port 4 defined but not configured."
 353#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5)
 354#error  "Console port 5 defined but not configured."
 355#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6)
 356#error  "Console port 6 defined but not configured."
 357#endif
 358
 359#if defined(CONFIG_SYS_NS16550_COM1)
 360DECLARE_HSUART(1, "mtk-hsuart0");
 361#endif
 362#if defined(CONFIG_SYS_NS16550_COM2)
 363DECLARE_HSUART(2, "mtk-hsuart1");
 364#endif
 365#if defined(CONFIG_SYS_NS16550_COM3)
 366DECLARE_HSUART(3, "mtk-hsuart2");
 367#endif
 368#if defined(CONFIG_SYS_NS16550_COM4)
 369DECLARE_HSUART(4, "mtk-hsuart3");
 370#endif
 371#if defined(CONFIG_SYS_NS16550_COM5)
 372DECLARE_HSUART(5, "mtk-hsuart4");
 373#endif
 374#if defined(CONFIG_SYS_NS16550_COM6)
 375DECLARE_HSUART(6, "mtk-hsuart5");
 376#endif
 377
 378__weak struct serial_device *default_serial_console(void)
 379{
 380#if CONFIG_CONS_INDEX == 1
 381        return &mtk_hsuart1_device;
 382#elif CONFIG_CONS_INDEX == 2
 383        return &mtk_hsuart2_device;
 384#elif CONFIG_CONS_INDEX == 3
 385        return &mtk_hsuart3_device;
 386#elif CONFIG_CONS_INDEX == 4
 387        return &mtk_hsuart4_device;
 388#elif CONFIG_CONS_INDEX == 5
 389        return &mtk_hsuart5_device;
 390#elif CONFIG_CONS_INDEX == 6
 391        return &mtk_hsuart6_device;
 392#else
 393#error "Bad CONFIG_CONS_INDEX."
 394#endif
 395}
 396
 397void mtk_serial_initialize(void)
 398{
 399#if defined(CONFIG_SYS_NS16550_COM1)
 400        serial_register(&mtk_hsuart1_device);
 401#endif
 402#if defined(CONFIG_SYS_NS16550_COM2)
 403        serial_register(&mtk_hsuart2_device);
 404#endif
 405#if defined(CONFIG_SYS_NS16550_COM3)
 406        serial_register(&mtk_hsuart3_device);
 407#endif
 408#if defined(CONFIG_SYS_NS16550_COM4)
 409        serial_register(&mtk_hsuart4_device);
 410#endif
 411#if defined(CONFIG_SYS_NS16550_COM5)
 412        serial_register(&mtk_hsuart5_device);
 413#endif
 414#if defined(CONFIG_SYS_NS16550_COM6)
 415        serial_register(&mtk_hsuart6_device);
 416#endif
 417}
 418
 419#endif
 420
 421#ifdef CONFIG_DEBUG_UART_MTK
 422
 423#include <debug_uart.h>
 424
 425static inline void _debug_uart_init(void)
 426{
 427        struct mtk_serial_priv priv;
 428
 429        priv.regs = (void *) CONFIG_DEBUG_UART_BASE;
 430        priv.clock = CONFIG_DEBUG_UART_CLOCK;
 431
 432        writel(0, &priv.regs->ier);
 433        writel(UART_MCRVAL, &priv.regs->mcr);
 434        writel(UART_FCRVAL, &priv.regs->fcr);
 435
 436        _mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
 437}
 438
 439static inline void _debug_uart_putc(int ch)
 440{
 441        struct mtk_serial_regs __iomem *regs =
 442                (void *) CONFIG_DEBUG_UART_BASE;
 443
 444        while (!(readl(&regs->lsr) & UART_LSR_THRE))
 445                ;
 446
 447        writel(ch, &regs->thr);
 448}
 449
 450DEBUG_UART_FUNCS
 451
 452#endif
 453