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