xref: /freebsd/sys/riscv/sifive/sifive_uart.c (revision d0b2dbfa)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Axiado Corporation
5  * All rights reserved.
6  *
7  * This software was developed in part by Kristof Provost under contract for
8  * Axiado Corporation.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/rman.h>
41 
42 #include <machine/bus.h>
43 #include <machine/cpu.h>
44 
45 #include <dev/extres/clk/clk.h>
46 
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49 #include <dev/ofw/openfirm.h>
50 
51 #include <dev/uart/uart.h>
52 #include <dev/uart/uart_bus.h>
53 #include <dev/uart/uart_cpu.h>
54 #include <dev/uart/uart_cpu_fdt.h>
55 
56 #include "uart_if.h"
57 
58 #define	SFUART_TXDATA			0x00
59 #define		SFUART_TXDATA_FULL	(1 << 31)
60 #define	SFUART_RXDATA			0x04
61 #define		SFUART_RXDATA_EMPTY	(1 << 31)
62 #define	SFUART_TXCTRL			0x08
63 #define		SFUART_TXCTRL_ENABLE	0x01
64 #define		SFUART_TXCTRL_NSTOP	0x02
65 #define		SFUART_TXCTRL_TXCNT	0x70000
66 #define		SFUART_TXCTRL_TXCNT_SHIFT	16
67 #define	SFUART_RXCTRL			0x0c
68 #define		SFUART_RXCTRL_ENABLE	0x01
69 #define		SFUART_RXCTRL_RXCNT	0x70000
70 #define		SFUART_RXCTRL_RXCNT_SHIFT	16
71 #define	SFUART_IRQ_ENABLE		0x10
72 #define		SFUART_IRQ_ENABLE_TXWM	0x01
73 #define		SFUART_IRQ_ENABLE_RXWM	0x02
74 #define	SFUART_IRQ_PENDING		0x14
75 #define		SFUART_IRQ_PENDING_TXWM	0x01
76 #define		SFUART_IRQ_PENDING_RXQM	0x02
77 #define	SFUART_DIV			0x18
78 #define	SFUART_REGS_SIZE		0x1c
79 
80 #define	SFUART_RX_FIFO_DEPTH		8
81 #define	SFUART_TX_FIFO_DEPTH		8
82 
83 struct sfuart_softc {
84 	struct uart_softc	uart_softc;
85 	clk_t			clk;
86 };
87 
88 static int
89 sfuart_probe(struct uart_bas *bas)
90 {
91 
92 	bas->regiowidth = 4;
93 
94 	return (0);
95 }
96 
97 static void
98 sfuart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
99     int parity)
100 {
101 	uint32_t reg;
102 
103 	uart_setreg(bas, SFUART_IRQ_ENABLE, 0);
104 
105 	/* Enable RX and configure the watermark so that we get an interrupt
106 	 * when a single character arrives (if interrupts are enabled). */
107 	reg = SFUART_RXCTRL_ENABLE;
108 	reg |= (0 << SFUART_RXCTRL_RXCNT_SHIFT);
109 	uart_setreg(bas, SFUART_RXCTRL, reg);
110 
111 	/* Enable TX and configure the watermark so that we get an interrupt
112 	 * when there's room for one more character in the TX fifo (if
113 	 * interrupts are enabled). */
114 	reg = SFUART_TXCTRL_ENABLE;
115 	reg |= (1 << SFUART_TXCTRL_TXCNT_SHIFT);
116 	if (stopbits == 2)
117 		reg |= SFUART_TXCTRL_NSTOP;
118 	uart_setreg(bas, SFUART_TXCTRL, reg);
119 
120 	/* Don't touch DIV. Assume that's set correctly until we can
121 	 * reconfigure. */
122 }
123 
124 static void
125 sfuart_putc(struct uart_bas *bas, int c)
126 {
127 
128 	while ((uart_getreg(bas, SFUART_TXDATA) & SFUART_TXDATA_FULL)
129 	    != 0)
130 		cpu_spinwait();
131 
132 	uart_setreg(bas, SFUART_TXDATA, c);
133 }
134 
135 static int
136 sfuart_rxready(struct uart_bas *bas)
137 {
138 	/*
139 	 * Unfortunately the FIFO empty flag is in the FIFO data register so
140 	 * reading it would dequeue the character. Instead, rely on the fact
141 	 * we've configured the watermark to be 0 and that interrupts are off
142 	 * when using the low-level console function, and read the interrupt
143 	 * pending state instead.
144 	 */
145 	return ((uart_getreg(bas, SFUART_IRQ_PENDING) &
146 	    SFUART_IRQ_PENDING_RXQM) != 0);
147 }
148 
149 static int
150 sfuart_getc(struct uart_bas *bas, struct mtx *hwmtx)
151 {
152 	int c;
153 
154 	uart_lock(hwmtx);
155 
156 	while (((c = uart_getreg(bas, SFUART_RXDATA)) &
157 	    SFUART_RXDATA_EMPTY) != 0) {
158 		uart_unlock(hwmtx);
159 		DELAY(4);
160 		uart_lock(hwmtx);
161 	}
162 
163 	uart_unlock(hwmtx);
164 
165 	return (c & 0xff);
166 }
167 
168 static int
169 sfuart_bus_probe(struct uart_softc *sc)
170 {
171 	int error;
172 
173 	error = sfuart_probe(&sc->sc_bas);
174 	if (error)
175 		return (error);
176 
177 	sc->sc_rxfifosz = SFUART_RX_FIFO_DEPTH;
178 	sc->sc_txfifosz = SFUART_TX_FIFO_DEPTH;
179 	sc->sc_hwiflow = 0;
180 	sc->sc_hwoflow = 0;
181 
182 	device_set_desc(sc->sc_dev, "SiFive UART");
183 
184 	return (0);
185 }
186 
187 static int
188 sfuart_bus_attach(struct uart_softc *sc)
189 {
190 	struct uart_bas *bas;
191 	struct sfuart_softc *sfsc;
192 	uint64_t freq;
193 	uint32_t reg;
194 	int error;
195 
196 	sfsc = (struct sfuart_softc *)sc;
197 	bas = &sc->sc_bas;
198 
199 	error = clk_get_by_ofw_index(sc->sc_dev, 0, 0, &sfsc->clk);
200 	if (error) {
201 		device_printf(sc->sc_dev, "couldn't allocate clock\n");
202 		return (ENXIO);
203 	}
204 
205 	error = clk_enable(sfsc->clk);
206 	if (error) {
207 		device_printf(sc->sc_dev, "couldn't enable clock\n");
208 		return (ENXIO);
209 	}
210 
211 	error = clk_get_freq(sfsc->clk, &freq);
212 	if (error || freq == 0) {
213 		clk_disable(sfsc->clk);
214 		device_printf(sc->sc_dev, "couldn't get clock frequency\n");
215 		return (ENXIO);
216 	}
217 
218 	bas->rclk = freq;
219 
220 	/* Enable RX/RX */
221 	reg = SFUART_RXCTRL_ENABLE;
222 	reg |= (0 << SFUART_RXCTRL_RXCNT_SHIFT);
223 	uart_setreg(bas, SFUART_RXCTRL, reg);
224 
225 	reg = SFUART_TXCTRL_ENABLE;
226 	reg |= (1 << SFUART_TXCTRL_TXCNT_SHIFT);
227 	uart_setreg(bas, SFUART_TXCTRL, reg);
228 
229 	/* Enable RX interrupt */
230 	uart_setreg(bas, SFUART_IRQ_ENABLE, SFUART_IRQ_ENABLE_RXWM);
231 
232 	return (0);
233 }
234 
235 static int
236 sfuart_bus_detach(struct uart_softc *sc)
237 {
238 	struct sfuart_softc *sfsc;
239 	struct uart_bas *bas;
240 
241 	sfsc = (struct sfuart_softc *)sc;
242 	bas = &sc->sc_bas;
243 
244 	/* Disable RX/TX */
245 	uart_setreg(bas, SFUART_RXCTRL, 0);
246 	uart_setreg(bas, SFUART_TXCTRL, 0);
247 
248 	/* Disable interrupts */
249 	uart_setreg(bas, SFUART_IRQ_ENABLE, 0);
250 
251 	clk_disable(sfsc->clk);
252 
253 	return (0);
254 }
255 
256 static int
257 sfuart_bus_flush(struct uart_softc *sc, int what)
258 {
259 	struct uart_bas *bas;
260 	uint32_t reg;
261 
262 	bas = &sc->sc_bas;
263 	uart_lock(sc->sc_hwmtx);
264 
265 	if (what & UART_FLUSH_TRANSMITTER) {
266 		do {
267 			reg = uart_getreg(bas, SFUART_TXDATA);
268 		} while ((reg & SFUART_TXDATA_FULL) != 0);
269 	}
270 
271 	if (what & UART_FLUSH_RECEIVER) {
272 		do {
273 			reg = uart_getreg(bas, SFUART_RXDATA);
274 		} while ((reg & SFUART_RXDATA_EMPTY) == 0);
275 	}
276 	uart_unlock(sc->sc_hwmtx);
277 
278 	return (0);
279 }
280 
281 #define	SIGCHG(c, i, s, d)						\
282 	do {								\
283 		if (c)							\
284 			i |= ((i) & (s)) ? (s) : (s) | (d);		\
285 		else		 					\
286 			i = ((i) & (s)) ? ((i) & ~(s)) | (d) : (i);	\
287 	} while (0)
288 
289 static int
290 sfuart_bus_getsig(struct uart_softc *sc)
291 {
292 	uint32_t new, old, sig;
293 
294 	do {
295 		old = sc->sc_hwsig;
296 		sig = old;
297 		SIGCHG(1, sig, SER_DSR, SER_DDSR);
298 		SIGCHG(1, sig, SER_DCD, SER_DDCD);
299 		SIGCHG(1, sig, SER_CTS, SER_DCTS);
300 		new = sig & ~SER_MASK_DELTA;
301 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
302 
303 	return (sig);
304 }
305 
306 static int
307 sfuart_bus_setsig(struct uart_softc *sc, int sig)
308 {
309 	uint32_t new, old;
310 
311 	do {
312 		old = sc->sc_hwsig;
313 		new = old;
314 		if (sig & SER_DDTR) {
315 			SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
316 		}
317 		if (sig & SER_DRTS) {
318 			SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
319 		}
320 	 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
321 
322 	return (0);
323 }
324 
325 static int
326 sfuart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
327 {
328 	struct uart_bas *bas;
329 	uint32_t reg;
330 	int error;
331 
332 	bas = &sc->sc_bas;
333 
334 	uart_lock(sc->sc_hwmtx);
335 
336 	switch (request) {
337 	case UART_IOCTL_BAUD:
338 		reg = uart_getreg(bas, SFUART_DIV);
339 		if (reg == 0) {
340 			/* Possible if the divisor hasn't been set up yet. */
341 			error = ENXIO;
342 			break;
343 		}
344 		*(int*)data = bas->rclk / (reg + 1);
345 		error = 0;
346 		break;
347 	default:
348 		error = EINVAL;
349 		break;
350 	}
351 
352 	uart_unlock(sc->sc_hwmtx);
353 
354 	return (error);
355 }
356 
357 static int
358 sfuart_bus_ipend(struct uart_softc *sc)
359 {
360 	struct uart_bas *bas;
361 	int ipend;
362 	uint32_t reg, ie;
363 
364 	bas = &sc->sc_bas;
365 	uart_lock(sc->sc_hwmtx);
366 
367 	ipend = 0;
368 	reg = uart_getreg(bas, SFUART_IRQ_PENDING);
369 	ie = uart_getreg(bas, SFUART_IRQ_ENABLE);
370 
371 	if ((reg & SFUART_IRQ_PENDING_TXWM) != 0 &&
372 	    (ie & SFUART_IRQ_ENABLE_TXWM) != 0) {
373 		ipend |= SER_INT_TXIDLE;
374 
375 		/* Disable TX interrupt */
376 		ie &= ~(SFUART_IRQ_ENABLE_TXWM);
377 		uart_setreg(bas, SFUART_IRQ_ENABLE, ie);
378 	}
379 
380 	if ((reg & SFUART_IRQ_PENDING_RXQM) != 0)
381 		ipend |= SER_INT_RXREADY;
382 
383 	uart_unlock(sc->sc_hwmtx);
384 
385 	return (ipend);
386 }
387 
388 static int
389 sfuart_bus_param(struct uart_softc *sc, int baudrate, int databits,
390     int stopbits, int parity)
391 {
392 	struct uart_bas *bas;
393 	uint32_t reg;
394 
395 	bas = &sc->sc_bas;
396 
397 	if (databits != 8)
398 		return (EINVAL);
399 
400 	if (parity != UART_PARITY_NONE)
401 		return (EINVAL);
402 
403 	uart_lock(sc->sc_hwmtx);
404 
405 	reg = uart_getreg(bas, SFUART_TXCTRL);
406 	if (stopbits == 2) {
407 		reg |= SFUART_TXCTRL_NSTOP;
408 	} else if (stopbits == 1) {
409 		reg &= ~SFUART_TXCTRL_NSTOP;
410 	} else {
411 		uart_unlock(sc->sc_hwmtx);
412 		return (EINVAL);
413 	}
414 
415 	if (baudrate > 0 && bas->rclk != 0) {
416 		reg = (bas->rclk / baudrate) - 1;
417 		uart_setreg(bas, SFUART_DIV, reg);
418 	}
419 
420 	uart_unlock(sc->sc_hwmtx);
421 	return (0);
422 }
423 
424 static int
425 sfuart_bus_receive(struct uart_softc *sc)
426 {
427 	struct uart_bas *bas;
428 	uint32_t reg;
429 
430 	bas = &sc->sc_bas;
431 	uart_lock(sc->sc_hwmtx);
432 
433 	reg = uart_getreg(bas, SFUART_RXDATA);
434 	while ((reg & SFUART_RXDATA_EMPTY) == 0) {
435 		if (uart_rx_full(sc)) {
436 			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
437 			break;
438 		}
439 
440 		uart_rx_put(sc, reg & 0xff);
441 
442 		reg = uart_getreg(bas, SFUART_RXDATA);
443 	}
444 
445 	uart_unlock(sc->sc_hwmtx);
446 
447 	return (0);
448 }
449 
450 static int
451 sfuart_bus_transmit(struct uart_softc *sc)
452 {
453 	struct uart_bas *bas;
454 	int i;
455 	uint32_t reg;
456 
457 	bas = &sc->sc_bas;
458 	uart_lock(sc->sc_hwmtx);
459 
460 	reg = uart_getreg(bas, SFUART_IRQ_ENABLE);
461 	reg |= SFUART_IRQ_ENABLE_TXWM;
462 	uart_setreg(bas, SFUART_IRQ_ENABLE, reg);
463 
464 	for (i = 0; i < sc->sc_txdatasz; i++)
465 		sfuart_putc(bas, sc->sc_txbuf[i]);
466 
467 	sc->sc_txbusy = 1;
468 
469 	uart_unlock(sc->sc_hwmtx);
470 
471 	return (0);
472 }
473 
474 static void
475 sfuart_bus_grab(struct uart_softc *sc)
476 {
477 	struct uart_bas *bas;
478 	uint32_t reg;
479 
480 	bas = &sc->sc_bas;
481 	uart_lock(sc->sc_hwmtx);
482 
483 	reg = uart_getreg(bas, SFUART_IRQ_ENABLE);
484 	reg &= ~(SFUART_IRQ_ENABLE_TXWM | SFUART_IRQ_PENDING_RXQM);
485 	uart_setreg(bas, SFUART_IRQ_ENABLE, reg);
486 
487 	uart_unlock(sc->sc_hwmtx);
488 }
489 
490 static void
491 sfuart_bus_ungrab(struct uart_softc *sc)
492 {
493 	struct uart_bas *bas;
494 	uint32_t reg;
495 
496 	bas = &sc->sc_bas;
497 	uart_lock(sc->sc_hwmtx);
498 
499 	reg = uart_getreg(bas, SFUART_IRQ_ENABLE);
500 	reg |= SFUART_IRQ_ENABLE_TXWM | SFUART_IRQ_PENDING_RXQM;
501 	uart_setreg(bas, SFUART_IRQ_ENABLE, reg);
502 
503 	uart_unlock(sc->sc_hwmtx);
504 }
505 
506 static kobj_method_t sfuart_methods[] = {
507 	KOBJMETHOD(uart_probe,		sfuart_bus_probe),
508 	KOBJMETHOD(uart_attach,		sfuart_bus_attach),
509 	KOBJMETHOD(uart_detach,		sfuart_bus_detach),
510 	KOBJMETHOD(uart_flush,		sfuart_bus_flush),
511 	KOBJMETHOD(uart_getsig,		sfuart_bus_getsig),
512 	KOBJMETHOD(uart_setsig,		sfuart_bus_setsig),
513 	KOBJMETHOD(uart_ioctl,		sfuart_bus_ioctl),
514 	KOBJMETHOD(uart_ipend,		sfuart_bus_ipend),
515 	KOBJMETHOD(uart_param,		sfuart_bus_param),
516 	KOBJMETHOD(uart_receive,	sfuart_bus_receive),
517 	KOBJMETHOD(uart_transmit,	sfuart_bus_transmit),
518 	KOBJMETHOD(uart_grab,		sfuart_bus_grab),
519 	KOBJMETHOD(uart_ungrab,		sfuart_bus_ungrab),
520 	KOBJMETHOD_END
521 };
522 
523 static struct uart_ops sfuart_ops = {
524 	.probe = sfuart_probe,
525 	.init = sfuart_init,
526 	.term = NULL,
527 	.putc = sfuart_putc,
528 	.rxready = sfuart_rxready,
529 	.getc = sfuart_getc,
530 };
531 
532 struct uart_class sfuart_class = {
533 	"sifiveuart",
534 	sfuart_methods,
535 	sizeof(struct sfuart_softc),
536 	.uc_ops = &sfuart_ops,
537 	.uc_range = SFUART_REGS_SIZE,
538 	.uc_rclk = 0,
539 	.uc_rshift = 0
540 };
541 
542 static struct ofw_compat_data compat_data[] = {
543 	{ "sifive,uart0",	(uintptr_t)&sfuart_class },
544 	{ NULL,			(uintptr_t)NULL }
545 };
546 
547 UART_FDT_CLASS_AND_DEVICE(compat_data);
548