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