uboot/drivers/serial/serial_ar933x.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
   3 *
   4 * SPDX-License-Identifier: GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <div64.h>
  10#include <errno.h>
  11#include <serial.h>
  12#include <asm/io.h>
  13#include <asm/addrspace.h>
  14#include <asm/types.h>
  15#include <dm/pinctrl.h>
  16#include <mach/ar71xx_regs.h>
  17
  18#define AR933X_UART_DATA_REG            0x00
  19#define AR933X_UART_CS_REG              0x04
  20#define AR933X_UART_CLK_REG             0x08
  21
  22#define AR933X_UART_DATA_TX_RX_MASK     0xff
  23#define AR933X_UART_DATA_RX_CSR         BIT(8)
  24#define AR933X_UART_DATA_TX_CSR         BIT(9)
  25#define AR933X_UART_CS_IF_MODE_S        2
  26#define AR933X_UART_CS_IF_MODE_M        0x3
  27#define AR933X_UART_CS_IF_MODE_DTE      1
  28#define AR933X_UART_CS_IF_MODE_DCE      2
  29#define AR933X_UART_CS_TX_RDY_ORIDE     BIT(7)
  30#define AR933X_UART_CS_RX_RDY_ORIDE     BIT(8)
  31#define AR933X_UART_CLK_STEP_M          0xffff
  32#define AR933X_UART_CLK_SCALE_M         0xfff
  33#define AR933X_UART_CLK_SCALE_S         16
  34#define AR933X_UART_CLK_STEP_S          0
  35
  36struct ar933x_serial_priv {
  37        void __iomem *regs;
  38};
  39
  40/*
  41 * Baudrate algorithm come from Linux/drivers/tty/serial/ar933x_uart.c
  42 * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
  43 */
  44static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step)
  45{
  46        u64 t;
  47        u32 div;
  48
  49        div = (2 << 16) * (scale + 1);
  50        t = clk;
  51        t *= step;
  52        t += (div / 2);
  53        do_div(t, div);
  54
  55        return t;
  56}
  57
  58static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
  59                                         u32 *scale, u32 *step)
  60{
  61        u32 tscale, baudrate;
  62        long min_diff;
  63
  64        *scale = 0;
  65        *step = 0;
  66
  67        min_diff = baud;
  68        for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
  69                u64 tstep;
  70                int diff;
  71
  72                tstep = baud * (tscale + 1);
  73                tstep *= (2 << 16);
  74                do_div(tstep, clk);
  75
  76                if (tstep > AR933X_UART_CLK_STEP_M)
  77                        break;
  78
  79                baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
  80                diff = abs(baudrate - baud);
  81                if (diff < min_diff) {
  82                        min_diff = diff;
  83                        *scale = tscale;
  84                        *step = tstep;
  85                }
  86        }
  87}
  88
  89static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
  90{
  91        struct ar933x_serial_priv *priv = dev_get_priv(dev);
  92        u32 val, scale, step;
  93
  94        val = get_serial_clock();
  95        ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
  96
  97        val  = (scale & AR933X_UART_CLK_SCALE_M)
  98                        << AR933X_UART_CLK_SCALE_S;
  99        val |= (step & AR933X_UART_CLK_STEP_M)
 100                        << AR933X_UART_CLK_STEP_S;
 101        writel(val, priv->regs + AR933X_UART_CLK_REG);
 102
 103        return 0;
 104}
 105
 106static int ar933x_serial_putc(struct udevice *dev, const char c)
 107{
 108        struct ar933x_serial_priv *priv = dev_get_priv(dev);
 109        u32 data;
 110
 111        data = readl(priv->regs + AR933X_UART_DATA_REG);
 112        if (!(data & AR933X_UART_DATA_TX_CSR))
 113                return -EAGAIN;
 114
 115        data  = (u32)c | AR933X_UART_DATA_TX_CSR;
 116        writel(data, priv->regs + AR933X_UART_DATA_REG);
 117
 118        return 0;
 119}
 120
 121static int ar933x_serial_getc(struct udevice *dev)
 122{
 123        struct ar933x_serial_priv *priv = dev_get_priv(dev);
 124        u32 data;
 125
 126        data = readl(priv->regs + AR933X_UART_DATA_REG);
 127        if (!(data & AR933X_UART_DATA_RX_CSR))
 128                return -EAGAIN;
 129
 130        writel(AR933X_UART_DATA_RX_CSR, priv->regs + AR933X_UART_DATA_REG);
 131        return data & AR933X_UART_DATA_TX_RX_MASK;
 132}
 133
 134static int ar933x_serial_pending(struct udevice *dev, bool input)
 135{
 136        struct ar933x_serial_priv *priv = dev_get_priv(dev);
 137        u32 data;
 138
 139        data = readl(priv->regs + AR933X_UART_DATA_REG);
 140        if (input)
 141                return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
 142        else
 143                return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
 144}
 145
 146static int ar933x_serial_probe(struct udevice *dev)
 147{
 148        struct ar933x_serial_priv *priv = dev_get_priv(dev);
 149        fdt_addr_t addr;
 150        u32 val;
 151
 152        addr = devfdt_get_addr(dev);
 153        if (addr == FDT_ADDR_T_NONE)
 154                return -EINVAL;
 155
 156        priv->regs = map_physmem(addr, AR933X_UART_SIZE,
 157                                 MAP_NOCACHE);
 158
 159        /*
 160         * UART controller configuration:
 161         * - no DMA
 162         * - no interrupt
 163         * - DCE mode
 164         * - no flow control
 165         * - set RX ready oride
 166         * - set TX ready oride
 167         */
 168        val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
 169              AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
 170        writel(val, priv->regs + AR933X_UART_CS_REG);
 171        return 0;
 172}
 173
 174static const struct dm_serial_ops ar933x_serial_ops = {
 175        .putc = ar933x_serial_putc,
 176        .pending = ar933x_serial_pending,
 177        .getc = ar933x_serial_getc,
 178        .setbrg = ar933x_serial_setbrg,
 179};
 180
 181static const struct udevice_id ar933x_serial_ids[] = {
 182        { .compatible = "qca,ar9330-uart" },
 183        { }
 184};
 185
 186U_BOOT_DRIVER(serial_ar933x) = {
 187        .name   = "serial_ar933x",
 188        .id = UCLASS_SERIAL,
 189        .of_match = ar933x_serial_ids,
 190        .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
 191        .probe = ar933x_serial_probe,
 192        .ops    = &ar933x_serial_ops,
 193        .flags = DM_FLAG_PRE_RELOC,
 194};
 195
 196#ifdef CONFIG_DEBUG_UART_AR933X
 197
 198#include <debug_uart.h>
 199
 200static inline void _debug_uart_init(void)
 201{
 202        void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
 203        u32 val, scale, step;
 204
 205        /*
 206         * UART controller configuration:
 207         * - no DMA
 208         * - no interrupt
 209         * - DCE mode
 210         * - no flow control
 211         * - set RX ready oride
 212         * - set TX ready oride
 213         */
 214        val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
 215              AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
 216        writel(val, regs + AR933X_UART_CS_REG);
 217
 218        ar933x_serial_get_scale_step(CONFIG_DEBUG_UART_CLOCK,
 219                                     CONFIG_BAUDRATE, &scale, &step);
 220
 221        val  = (scale & AR933X_UART_CLK_SCALE_M)
 222                        << AR933X_UART_CLK_SCALE_S;
 223        val |= (step & AR933X_UART_CLK_STEP_M)
 224                        << AR933X_UART_CLK_STEP_S;
 225        writel(val, regs + AR933X_UART_CLK_REG);
 226}
 227
 228static inline void _debug_uart_putc(int c)
 229{
 230        void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
 231        u32 data;
 232
 233        do {
 234                data = readl(regs + AR933X_UART_DATA_REG);
 235        } while (!(data & AR933X_UART_DATA_TX_CSR));
 236
 237        data  = (u32)c | AR933X_UART_DATA_TX_CSR;
 238        writel(data, regs + AR933X_UART_DATA_REG);
 239}
 240
 241DEBUG_UART_FUNCS
 242
 243#endif
 244