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)), &regs->div);
70 }
71 
72 static void _sifive_serial_init(struct uart_sifive *regs)
73 {
74 	writel(UART_TXCTRL_TXEN, &regs->txctrl);
75 	writel(UART_RXCTRL_RXEN, &regs->rxctrl);
76 	writel(0, &regs->ie);
77 }
78 
79 static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
80 {
81 	if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
82 		return -EAGAIN;
83 
84 	writel(c, &regs->txfifo);
85 
86 	return 0;
87 }
88 
89 static int _sifive_serial_getc(struct uart_sifive *regs)
90 {
91 	int ch = readl(&regs->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(&regs->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