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 <serial.h>
  15#include <watchdog.h>
  16#include <asm/io.h>
  17#include <asm/types.h>
  18
  19struct mtk_serial_regs {
  20        u32 rbr;
  21        u32 ier;
  22        u32 fcr;
  23        u32 lcr;
  24        u32 mcr;
  25        u32 lsr;
  26        u32 msr;
  27        u32 spr;
  28        u32 mdr1;
  29        u32 highspeed;
  30        u32 sample_count;
  31        u32 sample_point;
  32        u32 fracdiv_l;
  33        u32 fracdiv_m;
  34        u32 escape_en;
  35        u32 guard;
  36        u32 rx_sel;
  37};
  38
  39#define thr rbr
  40#define iir fcr
  41#define dll rbr
  42#define dlm ier
  43
  44#define UART_LCR_WLS_8  0x03            /* 8 bit character length */
  45#define UART_LCR_DLAB   0x80            /* Divisor latch access bit */
  46
  47#define UART_LSR_DR     0x01            /* Data ready */
  48#define UART_LSR_THRE   0x20            /* Xmit holding register empty */
  49
  50/* the data is correct if the real baud is within 3%. */
  51#define BAUD_ALLOW_MAX(baud)    ((baud) + (baud) * 3 / 100)
  52#define BAUD_ALLOW_MIX(baud)    ((baud) - (baud) * 3 / 100)
  53
  54struct mtk_serial_priv {
  55        struct mtk_serial_regs __iomem *regs;
  56        u32 clock;
  57};
  58
  59static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
  60{
  61        bool support_clk12m_baud115200;
  62        u32 quot, samplecount, realbaud;
  63
  64        if ((baud <= 115200) && (priv->clock == 12000000))
  65                support_clk12m_baud115200 = true;
  66        else
  67                support_clk12m_baud115200 = false;
  68
  69        if (baud <= 115200) {
  70                writel(0, &priv->regs->highspeed);
  71                quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
  72
  73                if (support_clk12m_baud115200) {
  74                        writel(3, &priv->regs->highspeed);
  75                        quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
  76                        if (quot == 0)
  77                                quot = 1;
  78
  79                        samplecount = DIV_ROUND_CLOSEST(priv->clock,
  80                                                        quot * baud);
  81                        if (samplecount != 0) {
  82                                realbaud = priv->clock / samplecount / quot;
  83                                if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
  84                                    (realbaud < BAUD_ALLOW_MIX(baud))) {
  85                                        pr_info("baud %d can't be handled\n",
  86                                                baud);
  87                                }
  88                        } else {
  89                                pr_info("samplecount is 0\n");
  90                        }
  91                }
  92        } else if (baud <= 576000) {
  93                writel(2, &priv->regs->highspeed);
  94
  95                /* Set to next lower baudrate supported */
  96                if ((baud == 500000) || (baud == 576000))
  97                        baud = 460800;
  98                quot = DIV_ROUND_UP(priv->clock, 4 * baud);
  99        } else {
 100                writel(3, &priv->regs->highspeed);
 101                quot = DIV_ROUND_UP(priv->clock, 256 * baud);
 102        }
 103
 104        /* set divisor */
 105        writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
 106        writel(quot & 0xff, &priv->regs->dll);
 107        writel((quot >> 8) & 0xff, &priv->regs->dlm);
 108        writel(UART_LCR_WLS_8, &priv->regs->lcr);
 109
 110        if (baud > 460800) {
 111                u32 tmp;
 112
 113                tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
 114                writel(tmp - 1, &priv->regs->sample_count);
 115                writel((tmp - 2) >> 1, &priv->regs->sample_point);
 116        } else {
 117                writel(0, &priv->regs->sample_count);
 118                writel(0xff, &priv->regs->sample_point);
 119        }
 120
 121        if (support_clk12m_baud115200) {
 122                writel(samplecount - 1, &priv->regs->sample_count);
 123                writel((samplecount - 2) >> 1, &priv->regs->sample_point);
 124        }
 125}
 126
 127static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
 128{
 129        struct mtk_serial_priv *priv = dev_get_priv(dev);
 130
 131        _mtk_serial_setbrg(priv, baudrate);
 132
 133        return 0;
 134}
 135
 136static int mtk_serial_putc(struct udevice *dev, const char ch)
 137{
 138        struct mtk_serial_priv *priv = dev_get_priv(dev);
 139
 140        if (!(readl(&priv->regs->lsr) & UART_LSR_THRE))
 141                return -EAGAIN;
 142
 143        writel(ch, &priv->regs->thr);
 144
 145        if (ch == '\n')
 146                WATCHDOG_RESET();
 147
 148        return 0;
 149}
 150
 151static int mtk_serial_getc(struct udevice *dev)
 152{
 153        struct mtk_serial_priv *priv = dev_get_priv(dev);
 154
 155        if (!(readl(&priv->regs->lsr) & UART_LSR_DR))
 156                return -EAGAIN;
 157
 158        return readl(&priv->regs->rbr);
 159}
 160
 161static int mtk_serial_pending(struct udevice *dev, bool input)
 162{
 163        struct mtk_serial_priv *priv = dev_get_priv(dev);
 164
 165        if (input)
 166                return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0;
 167        else
 168                return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
 169}
 170
 171static int mtk_serial_probe(struct udevice *dev)
 172{
 173        struct mtk_serial_priv *priv = dev_get_priv(dev);
 174
 175        /* Disable interrupt */
 176        writel(0, &priv->regs->ier);
 177
 178        return 0;
 179}
 180
 181static int mtk_serial_ofdata_to_platdata(struct udevice *dev)
 182{
 183        struct mtk_serial_priv *priv = dev_get_priv(dev);
 184        fdt_addr_t addr;
 185        struct clk clk;
 186        int err;
 187
 188        addr = dev_read_addr(dev);
 189        if (addr == FDT_ADDR_T_NONE)
 190                return -EINVAL;
 191
 192        priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
 193
 194        err = clk_get_by_index(dev, 0, &clk);
 195        if (!err) {
 196                err = clk_get_rate(&clk);
 197                if (!IS_ERR_VALUE(err))
 198                        priv->clock = err;
 199        } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
 200                debug("mtk_serial: failed to get clock\n");
 201                return err;
 202        }
 203
 204        if (!priv->clock)
 205                priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
 206
 207        if (!priv->clock) {
 208                debug("mtk_serial: clock not defined\n");
 209                return -EINVAL;
 210        }
 211
 212        return 0;
 213}
 214
 215static const struct dm_serial_ops mtk_serial_ops = {
 216        .putc = mtk_serial_putc,
 217        .pending = mtk_serial_pending,
 218        .getc = mtk_serial_getc,
 219        .setbrg = mtk_serial_setbrg,
 220};
 221
 222static const struct udevice_id mtk_serial_ids[] = {
 223        { .compatible = "mediatek,hsuart" },
 224        { .compatible = "mediatek,mt6577-uart" },
 225        { }
 226};
 227
 228U_BOOT_DRIVER(serial_mtk) = {
 229        .name = "serial_mtk",
 230        .id = UCLASS_SERIAL,
 231        .of_match = mtk_serial_ids,
 232        .ofdata_to_platdata = mtk_serial_ofdata_to_platdata,
 233        .priv_auto_alloc_size = sizeof(struct mtk_serial_priv),
 234        .probe = mtk_serial_probe,
 235        .ops = &mtk_serial_ops,
 236        .flags = DM_FLAG_PRE_RELOC,
 237};
 238
 239#ifdef CONFIG_DEBUG_UART_MTK
 240
 241#include <debug_uart.h>
 242
 243static inline void _debug_uart_init(void)
 244{
 245        struct mtk_serial_priv priv;
 246
 247        priv.regs = (void *) CONFIG_DEBUG_UART_BASE;
 248        priv.clock = CONFIG_DEBUG_UART_CLOCK;
 249
 250        writel(0, &priv.regs->ier);
 251
 252        _mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
 253}
 254
 255static inline void _debug_uart_putc(int ch)
 256{
 257        struct mtk_serial_regs __iomem *regs =
 258                (void *) CONFIG_DEBUG_UART_BASE;
 259
 260        while (!(readl(&regs->lsr) & UART_LSR_THRE))
 261                ;
 262
 263        writel(ch, &regs->thr);
 264}
 265
 266DEBUG_UART_FUNCS
 267
 268#endif