uboot/drivers/serial/serial_sifive.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
   4 */
   5
   6#include <common.h>
   7#include <clk.h>
   8#include <debug_uart.h>
   9#include <dm.h>
  10#include <errno.h>
  11#include <fdtdec.h>
  12#include <log.h>
  13#include <watchdog.h>
  14#include <asm/global_data.h>
  15#include <asm/io.h>
  16#include <linux/compiler.h>
  17#include <serial.h>
  18#include <linux/err.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22#define UART_TXFIFO_FULL        0x80000000
  23#define UART_RXFIFO_EMPTY       0x80000000
  24#define UART_RXFIFO_DATA        0x000000ff
  25#define UART_TXCTRL_TXEN        0x1
  26#define UART_RXCTRL_RXEN        0x1
  27
  28/* IP register */
  29#define UART_IP_RXWM            0x2
  30
  31struct uart_sifive {
  32        u32 txfifo;
  33        u32 rxfifo;
  34        u32 txctrl;
  35        u32 rxctrl;
  36        u32 ie;
  37        u32 ip;
  38        u32 div;
  39};
  40
  41struct sifive_uart_plat {
  42        unsigned long clock;
  43        struct uart_sifive *regs;
  44};
  45
  46/**
  47 * Find minimum divisor divides in_freq to max_target_hz;
  48 * Based on uart driver n SiFive FSBL.
  49 *
  50 * f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
  51 * The nearest integer solution requires rounding up as to not exceed
  52 * max_target_hz.
  53 * div  = ceil(f_in / f_baud) - 1
  54 *      = floor((f_in - 1 + f_baud) / f_baud) - 1
  55 * This should not overflow as long as (f_in - 1 + f_baud) does not exceed
  56 * 2^32 - 1, which is unlikely since we represent frequencies in kHz.
  57 */
  58static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
  59                                                unsigned long max_target_hz)
  60{
  61        unsigned long quotient =
  62                        (in_freq + max_target_hz - 1) / (max_target_hz);
  63        /* Avoid underflow */
  64        if (quotient == 0)
  65                return 0;
  66        else
  67                return quotient - 1;
  68}
  69
  70/* Set up the baud rate in gd struct */
  71static void _sifive_serial_setbrg(struct uart_sifive *regs,
  72                                  unsigned long clock, unsigned long baud)
  73{
  74        writel((uart_min_clk_divisor(clock, baud)), &regs->div);
  75}
  76
  77static void _sifive_serial_init(struct uart_sifive *regs)
  78{
  79        writel(UART_TXCTRL_TXEN, &regs->txctrl);
  80        writel(UART_RXCTRL_RXEN, &regs->rxctrl);
  81        writel(0, &regs->ie);
  82}
  83
  84static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
  85{
  86        if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
  87                return -EAGAIN;
  88
  89        writel(c, &regs->txfifo);
  90
  91        return 0;
  92}
  93
  94static int _sifive_serial_getc(struct uart_sifive *regs)
  95{
  96        int ch = readl(&regs->rxfifo);
  97
  98        if (ch & UART_RXFIFO_EMPTY)
  99                return -EAGAIN;
 100        ch &= UART_RXFIFO_DATA;
 101
 102        return ch;
 103}
 104
 105static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
 106{
 107        int ret;
 108        struct clk clk;
 109        struct sifive_uart_plat *plat = dev_get_plat(dev);
 110        u32 clock = 0;
 111
 112        ret = clk_get_by_index(dev, 0, &clk);
 113        if (IS_ERR_VALUE(ret)) {
 114                debug("SiFive UART failed to get clock\n");
 115                ret = dev_read_u32(dev, "clock-frequency", &clock);
 116                if (IS_ERR_VALUE(ret)) {
 117                        debug("SiFive UART clock not defined\n");
 118                        return 0;
 119                }
 120        } else {
 121                clock = clk_get_rate(&clk);
 122                if (IS_ERR_VALUE(clock)) {
 123                        debug("SiFive UART clock get rate failed\n");
 124                        return 0;
 125                }
 126        }
 127        plat->clock = clock;
 128        _sifive_serial_setbrg(plat->regs, plat->clock, baudrate);
 129
 130        return 0;
 131}
 132
 133static int sifive_serial_probe(struct udevice *dev)
 134{
 135        struct sifive_uart_plat *plat = dev_get_plat(dev);
 136
 137        /* No need to reinitialize the UART after relocation */
 138        if (gd->flags & GD_FLG_RELOC)
 139                return 0;
 140
 141        _sifive_serial_init(plat->regs);
 142
 143        return 0;
 144}
 145
 146static int sifive_serial_getc(struct udevice *dev)
 147{
 148        int c;
 149        struct sifive_uart_plat *plat = dev_get_plat(dev);
 150        struct uart_sifive *regs = plat->regs;
 151
 152        while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
 153
 154        return c;
 155}
 156
 157static int sifive_serial_putc(struct udevice *dev, const char ch)
 158{
 159        int rc;
 160        struct sifive_uart_plat *plat = dev_get_plat(dev);
 161
 162        while ((rc = _sifive_serial_putc(plat->regs, ch)) == -EAGAIN) ;
 163
 164        return rc;
 165}
 166
 167static int sifive_serial_pending(struct udevice *dev, bool input)
 168{
 169        struct sifive_uart_plat *plat = dev_get_plat(dev);
 170        struct uart_sifive *regs = plat->regs;
 171
 172        if (input)
 173                return (readl(&regs->ip) & UART_IP_RXWM);
 174        else
 175                return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
 176}
 177
 178static int sifive_serial_of_to_plat(struct udevice *dev)
 179{
 180        struct sifive_uart_plat *plat = dev_get_plat(dev);
 181
 182        plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev);
 183        if (IS_ERR(plat->regs))
 184                return PTR_ERR(plat->regs);
 185
 186        return 0;
 187}
 188
 189static const struct dm_serial_ops sifive_serial_ops = {
 190        .putc = sifive_serial_putc,
 191        .getc = sifive_serial_getc,
 192        .pending = sifive_serial_pending,
 193        .setbrg = sifive_serial_setbrg,
 194};
 195
 196static const struct udevice_id sifive_serial_ids[] = {
 197        { .compatible = "sifive,uart0" },
 198        { }
 199};
 200
 201U_BOOT_DRIVER(serial_sifive) = {
 202        .name   = "serial_sifive",
 203        .id     = UCLASS_SERIAL,
 204        .of_match = sifive_serial_ids,
 205        .of_to_plat = sifive_serial_of_to_plat,
 206        .plat_auto      = sizeof(struct sifive_uart_plat),
 207        .probe = sifive_serial_probe,
 208        .ops    = &sifive_serial_ops,
 209};
 210
 211#ifdef CONFIG_DEBUG_UART_SIFIVE
 212static inline void _debug_uart_init(void)
 213{
 214        struct uart_sifive *regs =
 215                        (struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
 216
 217        _sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
 218                              CONFIG_BAUDRATE);
 219        _sifive_serial_init(regs);
 220}
 221
 222static inline void _debug_uart_putc(int ch)
 223{
 224        struct uart_sifive *regs =
 225                        (struct uart_sifive *)CONFIG_VAL(DEBUG_UART_BASE);
 226
 227        while (_sifive_serial_putc(regs, ch) == -EAGAIN)
 228                schedule();
 229}
 230
 231DEBUG_UART_FUNCS
 232
 233#endif
 234