uart_dev_pl011.c revision 283324
1/*-
2 * Copyright (c) 2012 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/10/sys/dev/uart/uart_dev_pl011.c 283324 2015-05-23 20:01:20Z ian $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/bus.h>
34#include <machine/bus.h>
35
36#include <dev/uart/uart.h>
37#include <dev/uart/uart_cpu.h>
38#include <dev/uart/uart_bus.h>
39#include "uart_if.h"
40
41#include <sys/kdb.h>
42
43/* PL011 UART registers and masks*/
44#define	UART_DR		0x00		/* Data register */
45#define	DR_FE		(1 << 8)	/* Framing error */
46#define	DR_PE		(1 << 9)	/* Parity error */
47#define	DR_BE		(1 << 10)	/* Break error */
48#define	DR_OE		(1 << 11)	/* Overrun error */
49
50#define	UART_FR		0x06		/* Flag register */
51#define	FR_TXFF		(1 << 5)	/* Transmit FIFO/reg full */
52#define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
53#define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
54
55#define	UART_IBRD	0x09		/* Integer baud rate register */
56#define	IBRD_BDIVINT	0xffff	/* Significant part of int. divisor value */
57
58#define	UART_FBRD	0x0a		/* Fractional baud rate register */
59#define	FBRD_BDIVFRAC	0x3f	/* Significant part of frac. divisor value */
60
61#define	UART_LCR_H	0x0b		/* Line control register */
62#define	LCR_H_WLEN8	(0x3 << 5)
63#define	LCR_H_WLEN7	(0x2 << 5)
64#define	LCR_H_WLEN6	(0x1 << 5)
65#define	LCR_H_FEN	(1 << 4)	/* FIFO mode enable */
66#define	LCR_H_STP2	(1 << 3)	/* 2 stop frames at the end */
67#define	LCR_H_EPS	(1 << 2)	/* Even parity select */
68#define	LCR_H_PEN	(1 << 1)	/* Parity enable */
69
70#define	UART_CR		0x0c		/* Control register */
71#define	CR_RXE		(1 << 9)	/* Receive enable */
72#define	CR_TXE		(1 << 8)	/* Transmit enable */
73#define	CR_UARTEN	(1 << 0)	/* UART enable */
74
75#define	UART_IMSC	0x0e		/* Interrupt mask set/clear register */
76#define	IMSC_MASK_ALL	0x7ff		/* Mask all interrupts */
77
78#define	UART_RIS	0x0f		/* Raw interrupt status register */
79#define	UART_RXREADY	(1 << 4)	/* RX buffer full */
80#define	UART_TXEMPTY	(1 << 5)	/* TX buffer empty */
81#define	RIS_RTIM	(1 << 6)	/* Receive timeout */
82#define	RIS_FE		(1 << 7)	/* Framing error interrupt status */
83#define	RIS_PE		(1 << 8)	/* Parity error interrupt status */
84#define	RIS_BE		(1 << 9)	/* Break error interrupt status */
85#define	RIS_OE		(1 << 10)	/* Overrun interrupt status */
86
87#define	UART_MIS	0x10		/* Masked interrupt status register */
88#define	UART_ICR	0x11		/* Interrupt clear register */
89
90/*
91 * FIXME: actual register size is SoC-dependent, we need to handle it
92 */
93#define	__uart_getreg(bas, reg)		\
94	bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
95#define	__uart_setreg(bas, reg, value)	\
96	bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
97
98/*
99 * Low-level UART interface.
100 */
101static int uart_pl011_probe(struct uart_bas *bas);
102static void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
103static void uart_pl011_term(struct uart_bas *bas);
104static void uart_pl011_putc(struct uart_bas *bas, int);
105static int uart_pl011_rxready(struct uart_bas *bas);
106static int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
107
108static struct uart_ops uart_pl011_ops = {
109	.probe = uart_pl011_probe,
110	.init = uart_pl011_init,
111	.term = uart_pl011_term,
112	.putc = uart_pl011_putc,
113	.rxready = uart_pl011_rxready,
114	.getc = uart_pl011_getc,
115};
116
117static int
118uart_pl011_probe(struct uart_bas *bas)
119{
120
121	return (0);
122}
123
124static void
125uart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
126    int parity)
127{
128	uint32_t ctrl, line;
129	uint32_t baud;
130
131	/*
132	 * Zero all settings to make sure
133	 * UART is disabled and not configured
134	 */
135	ctrl = line = 0x0;
136	__uart_setreg(bas, UART_CR, ctrl);
137
138	/* As we know UART is disabled we may setup the line */
139	switch (databits) {
140	case 7:
141		line |= LCR_H_WLEN7;
142		break;
143	case 6:
144		line |= LCR_H_WLEN6;
145		break;
146	case 8:
147	default:
148		line |= LCR_H_WLEN8;
149		break;
150	}
151
152	if (stopbits == 2)
153		line |= LCR_H_STP2;
154	else
155		line &= ~LCR_H_STP2;
156
157	if (parity)
158		line |= LCR_H_PEN;
159	else
160		line &= ~LCR_H_PEN;
161
162	/* Configure the rest */
163	line &=  ~LCR_H_FEN;
164	ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
165
166	if (bas->rclk != 0 && baudrate != 0) {
167		baud = bas->rclk * 4 / baudrate;
168		__uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 6)) & IBRD_BDIVINT);
169		__uart_setreg(bas, UART_FBRD, (uint32_t)(baud & 0x3F) & FBRD_BDIVFRAC);
170	}
171
172	/* Add config. to line before reenabling UART */
173	__uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
174	    ~0xff) | line);
175
176	__uart_setreg(bas, UART_CR, ctrl);
177}
178
179static void
180uart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
181    int parity)
182{
183	/* Mask all interrupts */
184	__uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
185	    ~IMSC_MASK_ALL);
186
187	uart_pl011_param(bas, baudrate, databits, stopbits, parity);
188}
189
190static void
191uart_pl011_term(struct uart_bas *bas)
192{
193}
194
195static void
196uart_pl011_putc(struct uart_bas *bas, int c)
197{
198
199	/* Wait when TX FIFO full. Push character otherwise. */
200	while (__uart_getreg(bas, UART_FR) & FR_TXFF)
201		;
202	__uart_setreg(bas, UART_DR, c & 0xff);
203}
204
205static int
206uart_pl011_rxready(struct uart_bas *bas)
207{
208
209	return (__uart_getreg(bas, UART_FR) & FR_RXFF);
210}
211
212static int
213uart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
214{
215	int c;
216
217	while (!uart_pl011_rxready(bas))
218		;
219	c = __uart_getreg(bas, UART_DR) & 0xff;
220
221	return (c);
222}
223
224/*
225 * High-level UART interface.
226 */
227struct uart_pl011_softc {
228	struct uart_softc base;
229	uint8_t		fcr;
230	uint8_t		ier;
231	uint8_t		mcr;
232
233	uint8_t		ier_mask;
234	uint8_t		ier_rxbits;
235};
236
237static int uart_pl011_bus_attach(struct uart_softc *);
238static int uart_pl011_bus_detach(struct uart_softc *);
239static int uart_pl011_bus_flush(struct uart_softc *, int);
240static int uart_pl011_bus_getsig(struct uart_softc *);
241static int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
242static int uart_pl011_bus_ipend(struct uart_softc *);
243static int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
244static int uart_pl011_bus_probe(struct uart_softc *);
245static int uart_pl011_bus_receive(struct uart_softc *);
246static int uart_pl011_bus_setsig(struct uart_softc *, int);
247static int uart_pl011_bus_transmit(struct uart_softc *);
248static void uart_pl011_bus_grab(struct uart_softc *);
249static void uart_pl011_bus_ungrab(struct uart_softc *);
250
251static kobj_method_t uart_pl011_methods[] = {
252	KOBJMETHOD(uart_attach,		uart_pl011_bus_attach),
253	KOBJMETHOD(uart_detach,		uart_pl011_bus_detach),
254	KOBJMETHOD(uart_flush,		uart_pl011_bus_flush),
255	KOBJMETHOD(uart_getsig,		uart_pl011_bus_getsig),
256	KOBJMETHOD(uart_ioctl,		uart_pl011_bus_ioctl),
257	KOBJMETHOD(uart_ipend,		uart_pl011_bus_ipend),
258	KOBJMETHOD(uart_param,		uart_pl011_bus_param),
259	KOBJMETHOD(uart_probe,		uart_pl011_bus_probe),
260	KOBJMETHOD(uart_receive,	uart_pl011_bus_receive),
261	KOBJMETHOD(uart_setsig,		uart_pl011_bus_setsig),
262	KOBJMETHOD(uart_transmit,	uart_pl011_bus_transmit),
263	KOBJMETHOD(uart_grab,		uart_pl011_bus_grab),
264	KOBJMETHOD(uart_ungrab,		uart_pl011_bus_ungrab),
265
266	{ 0, 0 }
267};
268
269struct uart_class uart_pl011_class = {
270	"uart_pl011",
271	uart_pl011_methods,
272	sizeof(struct uart_pl011_softc),
273	.uc_ops = &uart_pl011_ops,
274	.uc_range = 0x48,
275	.uc_rclk = 0
276};
277
278static int
279uart_pl011_bus_attach(struct uart_softc *sc)
280{
281	struct uart_bas *bas;
282	int reg;
283
284	bas = &sc->sc_bas;
285
286	/* Enable interrupts */
287	reg = (UART_RXREADY | RIS_RTIM | UART_TXEMPTY);
288	__uart_setreg(bas, UART_IMSC, reg);
289
290	/* Clear interrupts */
291	__uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
292
293	return (0);
294}
295
296static int
297uart_pl011_bus_detach(struct uart_softc *sc)
298{
299
300	return (0);
301}
302
303static int
304uart_pl011_bus_flush(struct uart_softc *sc, int what)
305{
306
307	return (0);
308}
309
310static int
311uart_pl011_bus_getsig(struct uart_softc *sc)
312{
313
314	return (0);
315}
316
317static int
318uart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
319{
320	struct uart_bas *bas;
321	int error;
322
323	bas = &sc->sc_bas;
324	error = 0;
325	uart_lock(sc->sc_hwmtx);
326	switch (request) {
327	case UART_IOCTL_BREAK:
328		break;
329	case UART_IOCTL_BAUD:
330		*(int*)data = 115200;
331		break;
332	default:
333		error = EINVAL;
334		break;
335	}
336	uart_unlock(sc->sc_hwmtx);
337
338	return (error);
339}
340
341static int
342uart_pl011_bus_ipend(struct uart_softc *sc)
343{
344	struct uart_bas *bas;
345	uint32_t ints;
346	int ipend;
347	int reg;
348
349	bas = &sc->sc_bas;
350	uart_lock(sc->sc_hwmtx);
351	ints = __uart_getreg(bas, UART_MIS);
352	ipend = 0;
353
354	if (ints & (UART_RXREADY | RIS_RTIM))
355		ipend |= SER_INT_RXREADY;
356	if (ints & RIS_BE)
357		ipend |= SER_INT_BREAK;
358	if (ints & RIS_OE)
359		ipend |= SER_INT_OVERRUN;
360	if (ints & UART_TXEMPTY) {
361		if (sc->sc_txbusy)
362			ipend |= SER_INT_TXIDLE;
363
364		/* Disable TX interrupt */
365		reg = __uart_getreg(bas, UART_IMSC);
366		reg &= ~(UART_TXEMPTY);
367		__uart_setreg(bas, UART_IMSC, reg);
368	}
369
370	uart_unlock(sc->sc_hwmtx);
371
372	return (ipend);
373}
374
375static int
376uart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
377    int stopbits, int parity)
378{
379
380	uart_lock(sc->sc_hwmtx);
381	uart_pl011_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
382	uart_unlock(sc->sc_hwmtx);
383
384	return (0);
385}
386
387static int
388uart_pl011_bus_probe(struct uart_softc *sc)
389{
390
391	device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
392
393	sc->sc_rxfifosz = 1;
394	sc->sc_txfifosz = 1;
395
396	return (0);
397}
398
399static int
400uart_pl011_bus_receive(struct uart_softc *sc)
401{
402	struct uart_bas *bas;
403	uint32_t ints, xc;
404	int rx;
405
406	bas = &sc->sc_bas;
407	uart_lock(sc->sc_hwmtx);
408
409	ints = __uart_getreg(bas, UART_MIS);
410	while (ints & (UART_RXREADY | RIS_RTIM)) {
411		if (uart_rx_full(sc)) {
412			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
413			break;
414		}
415		xc = __uart_getreg(bas, UART_DR);
416		rx = xc & 0xff;
417
418		if (xc & DR_FE)
419			rx |= UART_STAT_FRAMERR;
420		if (xc & DR_PE)
421			rx |= UART_STAT_PARERR;
422
423		__uart_setreg(bas, UART_ICR, (UART_RXREADY | RIS_RTIM));
424
425		uart_rx_put(sc, rx);
426		ints = __uart_getreg(bas, UART_MIS);
427	}
428
429	uart_unlock(sc->sc_hwmtx);
430
431	return (0);
432}
433
434static int
435uart_pl011_bus_setsig(struct uart_softc *sc, int sig)
436{
437
438	return (0);
439}
440
441static int
442uart_pl011_bus_transmit(struct uart_softc *sc)
443{
444	struct uart_bas *bas;
445	int reg;
446	int i;
447
448	bas = &sc->sc_bas;
449	uart_lock(sc->sc_hwmtx);
450
451	for (i = 0; i < sc->sc_txdatasz; i++) {
452		__uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
453		uart_barrier(bas);
454	}
455	sc->sc_txbusy = 1;
456
457	/* Enable TX interrupt */
458	reg = __uart_getreg(bas, UART_IMSC);
459	reg |= (UART_TXEMPTY);
460	__uart_setreg(bas, UART_IMSC, reg);
461
462	uart_unlock(sc->sc_hwmtx);
463
464	return (0);
465}
466
467static void
468uart_pl011_bus_grab(struct uart_softc *sc)
469{
470	struct uart_bas *bas;
471
472	bas = &sc->sc_bas;
473	uart_lock(sc->sc_hwmtx);
474	__uart_setreg(bas, UART_IMSC, 	/* Switch to RX polling while grabbed */
475	    ~UART_RXREADY & __uart_getreg(bas, UART_IMSC));
476	uart_unlock(sc->sc_hwmtx);
477}
478
479static void
480uart_pl011_bus_ungrab(struct uart_softc *sc)
481{
482	struct uart_bas *bas;
483
484	bas = &sc->sc_bas;
485	uart_lock(sc->sc_hwmtx);
486	__uart_setreg(bas, UART_IMSC,	/* Switch to RX interrupts while not grabbed */
487	    UART_RXREADY | __uart_getreg(bas, UART_IMSC));
488	uart_unlock(sc->sc_hwmtx);
489}
490