xref: /freebsd/sys/dev/uart/uart_dev_quicc.c (revision a7941b3326a38f203dab0b92a51e549499081a08)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Juniper Networks
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/conf.h>
36 #include <sys/endian.h>
37 #include <machine/bus.h>
38 
39 #include <dev/ic/quicc.h>
40 
41 #include <dev/uart/uart.h>
42 #include <dev/uart/uart_cpu.h>
43 #include <dev/uart/uart_bus.h>
44 
45 #include "uart_if.h"
46 
47 #define	DEFAULT_RCLK	((266000000 * 2) / 16)
48 
49 #define	quicc_read2(bas, reg)		\
50 	bus_space_read_2((bas)->bst, (bas)->bsh, reg)
51 #define	quicc_read4(bas, reg)		\
52 	bus_space_read_4((bas)->bst, (bas)->bsh, reg)
53 
54 #define	quicc_write2(bas, reg, val)	\
55 	bus_space_write_2((bas)->bst, (bas)->bsh, reg, val)
56 #define	quicc_write4(bas, reg, val)	\
57 	bus_space_write_4((bas)->bst, (bas)->bsh, reg, val)
58 
59 static int
60 quicc_divisor(int rclk, int baudrate)
61 {
62 	int act_baud, divisor, error;
63 
64 	if (baudrate == 0)
65 		return (-1);
66 
67 	divisor = rclk / baudrate / 16;
68 	if (divisor > 4096)
69 		divisor = ((divisor >> 3) - 2) | 1;
70 	else if (divisor >= 0)
71 		divisor = (divisor - 1) << 1;
72 	if (divisor < 0 || divisor >= 8192)
73 		return (-1);
74 	act_baud = rclk / (((divisor >> 1) + 1) << ((divisor & 1) ? 8 : 4));
75 
76 	/* 10 times error in percent: */
77 	error = ((act_baud - baudrate) * 2000 / baudrate + 1) >> 1;
78 
79 	/* 3.0% maximum error tolerance: */
80 	if (error < -30 || error > 30)
81 		return (-1);
82 
83 	return (divisor);
84 }
85 
86 static int
87 quicc_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
88     int parity)
89 {
90 	int divisor;
91 	uint16_t psmr;
92 
93 	if (baudrate > 0) {
94 		divisor = quicc_divisor(bas->rclk, baudrate);
95 		if (divisor == -1)
96 			return (EINVAL);
97 		quicc_write4(bas, QUICC_REG_BRG(bas->chan - 1),
98 		    divisor | 0x10000);
99 	}
100 
101 	psmr = 0;
102 	switch (databits) {
103 	case 5:		psmr |= 0x0000; break;
104 	case 6:		psmr |= 0x1000; break;
105 	case 7:		psmr |= 0x2000; break;
106 	case 8:		psmr |= 0x3000; break;
107 	default:	return (EINVAL);
108 	}
109 	switch (stopbits) {
110 	case 1:		psmr |= 0x0000; break;
111 	case 2:		psmr |= 0x4000; break;
112 	default:	return (EINVAL);
113 	}
114 	switch (parity) {
115 	case UART_PARITY_EVEN:	psmr |= 0x1a; break;
116 	case UART_PARITY_MARK:	psmr |= 0x1f; break;
117 	case UART_PARITY_NONE:	psmr |= 0x00; break;
118 	case UART_PARITY_ODD:	psmr |= 0x10; break;
119 	case UART_PARITY_SPACE:	psmr |= 0x15; break;
120 	default:		return (EINVAL);
121 	}
122 	quicc_write2(bas, QUICC_REG_SCC_PSMR(bas->chan - 1), psmr);
123 	return (0);
124 }
125 
126 static void
127 quicc_setup(struct uart_bas *bas, int baudrate, int databits, int stopbits,
128     int parity)
129 {
130 
131 	if (bas->rclk == 0)
132 		bas->rclk = DEFAULT_RCLK;
133 
134 	/*
135 	 * GSMR_L = 0x00028034
136 	 * GSMR_H = 0x00000020
137 	 */
138 	quicc_param(bas, baudrate, databits, stopbits, parity);
139 
140 	quicc_write2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1), ~0);
141 	quicc_write2(bas, QUICC_REG_SCC_SCCM(bas->chan - 1), 0x0027);
142 }
143 
144 /*
145  * Low-level UART interface.
146  */
147 static int quicc_probe(struct uart_bas *bas);
148 static void quicc_init(struct uart_bas *bas, int, int, int, int);
149 static void quicc_term(struct uart_bas *bas);
150 static void quicc_putc(struct uart_bas *bas, int);
151 static int quicc_rxready(struct uart_bas *bas);
152 static int quicc_getc(struct uart_bas *bas, struct mtx *);
153 
154 static struct uart_ops uart_quicc_ops = {
155 	.probe = quicc_probe,
156 	.init = quicc_init,
157 	.term = quicc_term,
158 	.putc = quicc_putc,
159 	.rxready = quicc_rxready,
160 	.getc = quicc_getc,
161 };
162 
163 static int
164 quicc_probe(struct uart_bas *bas)
165 {
166 
167 	return (0);
168 }
169 
170 static void
171 quicc_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
172     int parity)
173 {
174 
175 	quicc_setup(bas, baudrate, databits, stopbits, parity);
176 }
177 
178 static void
179 quicc_term(struct uart_bas *bas)
180 {
181 }
182 
183 static void
184 quicc_putc(struct uart_bas *bas, int c)
185 {
186 	int unit;
187 	uint16_t toseq;
188 
189 	unit = bas->chan - 1;
190 	while (quicc_read2(bas, QUICC_PRAM_SCC_UART_TOSEQ(unit)) & 0x2000)
191 		DELAY(10);
192 
193 	toseq = 0x2000 | (c & 0xff);
194 	quicc_write2(bas, QUICC_PRAM_SCC_UART_TOSEQ(unit), toseq);
195 }
196 
197 static int
198 quicc_rxready(struct uart_bas *bas)
199 {
200 	uint16_t rb;
201 
202 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
203 	return ((quicc_read2(bas, rb) & 0x8000) ? 0 : 1);
204 }
205 
206 static int
207 quicc_getc(struct uart_bas *bas, struct mtx *hwmtx)
208 {
209 	volatile char *buf;
210 	int c;
211 	uint16_t rb, sc;
212 
213 	uart_lock(hwmtx);
214 
215 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
216 
217 	while ((sc = quicc_read2(bas, rb)) & 0x8000) {
218 		uart_unlock(hwmtx);
219 		DELAY(4);
220 		uart_lock(hwmtx);
221 	}
222 
223 	buf = (void *)(uintptr_t)quicc_read4(bas, rb + 4);
224 	c = *buf;
225 	quicc_write2(bas, rb, sc | 0x8000);
226 
227 	uart_unlock(hwmtx);
228 
229 	return (c);
230 }
231 
232 /*
233  * High-level UART interface.
234  */
235 struct quicc_softc {
236 	struct uart_softc base;
237 };
238 
239 static int quicc_bus_attach(struct uart_softc *);
240 static int quicc_bus_detach(struct uart_softc *);
241 static int quicc_bus_flush(struct uart_softc *, int);
242 static int quicc_bus_getsig(struct uart_softc *);
243 static int quicc_bus_ioctl(struct uart_softc *, int, intptr_t);
244 static int quicc_bus_ipend(struct uart_softc *);
245 static int quicc_bus_param(struct uart_softc *, int, int, int, int);
246 static int quicc_bus_probe(struct uart_softc *);
247 static int quicc_bus_receive(struct uart_softc *);
248 static int quicc_bus_setsig(struct uart_softc *, int);
249 static int quicc_bus_transmit(struct uart_softc *);
250 static void quicc_bus_grab(struct uart_softc *);
251 static void quicc_bus_ungrab(struct uart_softc *);
252 
253 static kobj_method_t quicc_methods[] = {
254 	KOBJMETHOD(uart_attach,		quicc_bus_attach),
255 	KOBJMETHOD(uart_detach,		quicc_bus_detach),
256 	KOBJMETHOD(uart_flush,		quicc_bus_flush),
257 	KOBJMETHOD(uart_getsig,		quicc_bus_getsig),
258 	KOBJMETHOD(uart_ioctl,		quicc_bus_ioctl),
259 	KOBJMETHOD(uart_ipend,		quicc_bus_ipend),
260 	KOBJMETHOD(uart_param,		quicc_bus_param),
261 	KOBJMETHOD(uart_probe,		quicc_bus_probe),
262 	KOBJMETHOD(uart_receive,	quicc_bus_receive),
263 	KOBJMETHOD(uart_setsig,		quicc_bus_setsig),
264 	KOBJMETHOD(uart_transmit,	quicc_bus_transmit),
265 	KOBJMETHOD(uart_grab,		quicc_bus_grab),
266 	KOBJMETHOD(uart_ungrab,		quicc_bus_ungrab),
267 	{ 0, 0 }
268 };
269 
270 struct uart_class uart_quicc_class = {
271 	"quicc",
272 	quicc_methods,
273 	sizeof(struct quicc_softc),
274 	.uc_ops = &uart_quicc_ops,
275 	.uc_range = 2,
276 	.uc_rclk = DEFAULT_RCLK,
277 	.uc_rshift = 0
278 };
279 
280 #define	SIGCHG(c, i, s, d)				\
281 	if (c) {					\
282 		i |= (i & s) ? s : s | d;		\
283 	} else {					\
284 		i = (i & s) ? (i & ~s) | d : i;		\
285 	}
286 
287 static int
288 quicc_bus_attach(struct uart_softc *sc)
289 {
290 	struct uart_bas *bas;
291 	struct uart_devinfo *di;
292 	uint16_t st, rb;
293 
294 	bas = &sc->sc_bas;
295 	if (sc->sc_sysdev != NULL) {
296 		di = sc->sc_sysdev;
297 		quicc_param(bas, di->baudrate, di->databits, di->stopbits,
298 		    di->parity);
299 	} else {
300 		quicc_setup(bas, 9600, 8, 1, UART_PARITY_NONE);
301 	}
302 
303 	/* Enable interrupts on the receive buffer. */
304 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
305 	st = quicc_read2(bas, rb);
306 	quicc_write2(bas, rb, st | 0x9000);
307 
308 	(void)quicc_bus_getsig(sc);
309 
310 	return (0);
311 }
312 
313 static int
314 quicc_bus_detach(struct uart_softc *sc)
315 {
316 
317 	return (0);
318 }
319 
320 static int
321 quicc_bus_flush(struct uart_softc *sc, int what)
322 {
323 
324 	return (0);
325 }
326 
327 static int
328 quicc_bus_getsig(struct uart_softc *sc)
329 {
330 	uint32_t new, old, sig;
331 	uint32_t dummy;
332 
333 	do {
334 		old = sc->sc_hwsig;
335 		sig = old;
336 		uart_lock(sc->sc_hwmtx);
337 		/* XXX SIGNALS */
338 		dummy = 0;
339 		uart_unlock(sc->sc_hwmtx);
340 		SIGCHG(dummy, sig, SER_CTS, SER_DCTS);
341 		SIGCHG(dummy, sig, SER_DCD, SER_DDCD);
342 		SIGCHG(dummy, sig, SER_DSR, SER_DDSR);
343 		new = sig & ~SER_MASK_DELTA;
344 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
345 	return (sig);
346 }
347 
348 static int
349 quicc_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
350 {
351 	struct uart_bas *bas;
352 	uint32_t brg;
353 	int baudrate, error;
354 
355 	bas = &sc->sc_bas;
356 	error = 0;
357 	uart_lock(sc->sc_hwmtx);
358 	switch (request) {
359 	case UART_IOCTL_BREAK:
360 		break;
361 	case UART_IOCTL_BAUD:
362 		brg = quicc_read4(bas, QUICC_REG_BRG(bas->chan - 1)) & 0x1fff;
363 		brg = (brg & 1) ? (brg + 1) << 3 : (brg + 2) >> 1;
364 		baudrate = bas->rclk / (brg * 16);
365 		*(int*)data = baudrate;
366 		break;
367 	default:
368 		error = EINVAL;
369 		break;
370 	}
371 	uart_unlock(sc->sc_hwmtx);
372 	return (error);
373 }
374 
375 static int
376 quicc_bus_ipend(struct uart_softc *sc)
377 {
378 	struct uart_bas *bas;
379 	int ipend;
380 	uint16_t scce;
381 
382 	bas = &sc->sc_bas;
383 	ipend = 0;
384 
385 	uart_lock(sc->sc_hwmtx);
386 	scce = quicc_read2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1));
387 	quicc_write2(bas, QUICC_REG_SCC_SCCE(bas->chan - 1), ~0);
388 	uart_unlock(sc->sc_hwmtx);
389 	if (scce & 0x0001)
390 		ipend |= SER_INT_RXREADY;
391 	if (scce & 0x0002)
392 		ipend |= SER_INT_TXIDLE;
393 	if (scce & 0x0004)
394 		ipend |= SER_INT_OVERRUN;
395 	if (scce & 0x0020)
396 		ipend |= SER_INT_BREAK;
397 	/* XXX SIGNALS */
398 	return (ipend);
399 }
400 
401 static int
402 quicc_bus_param(struct uart_softc *sc, int baudrate, int databits,
403     int stopbits, int parity)
404 {
405 	int error;
406 
407 	uart_lock(sc->sc_hwmtx);
408 	error = quicc_param(&sc->sc_bas, baudrate, databits, stopbits,
409 	    parity);
410 	uart_unlock(sc->sc_hwmtx);
411 	return (error);
412 }
413 
414 static int
415 quicc_bus_probe(struct uart_softc *sc)
416 {
417 	char buf[80];
418 	int error;
419 
420 	error = quicc_probe(&sc->sc_bas);
421 	if (error)
422 		return (error);
423 
424 	sc->sc_rxfifosz = 1;
425 	sc->sc_txfifosz = 1;
426 
427 	snprintf(buf, sizeof(buf), "quicc, channel %d", sc->sc_bas.chan);
428 	device_set_desc_copy(sc->sc_dev, buf);
429 	return (0);
430 }
431 
432 static int
433 quicc_bus_receive(struct uart_softc *sc)
434 {
435 	struct uart_bas *bas;
436 	volatile char *buf;
437 	uint16_t st, rb;
438 
439 	bas = &sc->sc_bas;
440 	uart_lock(sc->sc_hwmtx);
441 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
442 	st = quicc_read2(bas, rb);
443 	buf = (void *)(uintptr_t)quicc_read4(bas, rb + 4);
444 	uart_rx_put(sc, *buf);
445 	quicc_write2(bas, rb, st | 0x9000);
446 	uart_unlock(sc->sc_hwmtx);
447 	return (0);
448 }
449 
450 static int
451 quicc_bus_setsig(struct uart_softc *sc, int sig)
452 {
453 	struct uart_bas *bas;
454 	uint32_t new, old;
455 
456 	bas = &sc->sc_bas;
457 	do {
458 		old = sc->sc_hwsig;
459 		new = old;
460 		if (sig & SER_DDTR) {
461 			SIGCHG(sig & SER_DTR, new, SER_DTR,
462 			    SER_DDTR);
463 		}
464 		if (sig & SER_DRTS) {
465 			SIGCHG(sig & SER_RTS, new, SER_RTS,
466 			    SER_DRTS);
467 		}
468 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
469 
470 	uart_lock(sc->sc_hwmtx);
471 	/* XXX SIGNALS */
472 	uart_unlock(sc->sc_hwmtx);
473 	return (0);
474 }
475 
476 static int
477 quicc_bus_transmit(struct uart_softc *sc)
478 {
479 	volatile char *buf;
480 	struct uart_bas *bas;
481 	uint16_t st, tb;
482 
483 	bas = &sc->sc_bas;
484 	uart_lock(sc->sc_hwmtx);
485 	tb = quicc_read2(bas, QUICC_PRAM_SCC_TBASE(bas->chan - 1));
486 	st = quicc_read2(bas, tb);
487 	buf = (void *)(uintptr_t)quicc_read4(bas, tb + 4);
488 	*buf = sc->sc_txbuf[0];
489 	quicc_write2(bas, tb + 2, 1);
490 	quicc_write2(bas, tb, st | 0x9000);
491 	sc->sc_txbusy = 1;
492 	uart_unlock(sc->sc_hwmtx);
493 	return (0);
494 }
495 
496 static void
497 quicc_bus_grab(struct uart_softc *sc)
498 {
499 	struct uart_bas *bas;
500 	uint16_t st, rb;
501 
502 	/* Disable interrupts on the receive buffer. */
503 	bas = &sc->sc_bas;
504 	uart_lock(sc->sc_hwmtx);
505 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
506 	st = quicc_read2(bas, rb);
507 	quicc_write2(bas, rb, st & ~0x9000);
508 	uart_unlock(sc->sc_hwmtx);
509 }
510 
511 static void
512 quicc_bus_ungrab(struct uart_softc *sc)
513 {
514 	struct uart_bas *bas;
515 	uint16_t st, rb;
516 
517 	/* Enable interrupts on the receive buffer. */
518 	bas = &sc->sc_bas;
519 	uart_lock(sc->sc_hwmtx);
520 	rb = quicc_read2(bas, QUICC_PRAM_SCC_RBASE(bas->chan - 1));
521 	st = quicc_read2(bas, rb);
522 	quicc_write2(bas, rb, st | 0x9000);
523 	uart_unlock(sc->sc_hwmtx);
524 }
525