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)), ®s->div); 75} 76 77static void _sifive_serial_init(struct uart_sifive *regs) 78{ 79 writel(UART_TXCTRL_TXEN, ®s->txctrl); 80 writel(UART_RXCTRL_RXEN, ®s->rxctrl); 81 writel(0, ®s->ie); 82} 83 84static int _sifive_serial_putc(struct uart_sifive *regs, const char c) 85{ 86 if (readl(®s->txfifo) & UART_TXFIFO_FULL) 87 return -EAGAIN; 88 89 writel(c, ®s->txfifo); 90 91 return 0; 92} 93 94static int _sifive_serial_getc(struct uart_sifive *regs) 95{ 96 int ch = readl(®s->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(®s->ip) & UART_IP_RXWM); 174 else 175 return !!(readl(®s->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