uart_dev_pl011.c revision 239919
1239919Sgonzo/*-
2239919Sgonzo * Copyright (c) 2012 Semihalf.
3239919Sgonzo * All rights reserved.
4239919Sgonzo *
5239919Sgonzo * Redistribution and use in source and binary forms, with or without
6239919Sgonzo * modification, are permitted provided that the following conditions
7239919Sgonzo * are met:
8239919Sgonzo * 1. Redistributions of source code must retain the above copyright
9239919Sgonzo *    notice, this list of conditions and the following disclaimer.
10239919Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11239919Sgonzo *    notice, this list of conditions and the following disclaimer in the
12239919Sgonzo *    documentation and/or other materials provided with the distribution.
13239919Sgonzo *
14239919Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239919Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239919Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239919Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239919Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239919Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239919Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239919Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239919Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239919Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239919Sgonzo * SUCH DAMAGE.
25239919Sgonzo */
26239919Sgonzo
27239919Sgonzo#include <sys/cdefs.h>
28239919Sgonzo__FBSDID("$FreeBSD: head/sys/dev/uart/uart_dev_pl011.c 239919 2012-08-30 20:31:53Z gonzo $");
29239919Sgonzo
30239919Sgonzo#include <sys/param.h>
31239919Sgonzo#include <sys/systm.h>
32239919Sgonzo#include <sys/kernel.h>
33239919Sgonzo#include <sys/bus.h>
34239919Sgonzo#include <machine/bus.h>
35239919Sgonzo
36239919Sgonzo#include <dev/uart/uart.h>
37239919Sgonzo#include <dev/uart/uart_cpu.h>
38239919Sgonzo#include <dev/uart/uart_bus.h>
39239919Sgonzo#include "uart_if.h"
40239919Sgonzo
41239919Sgonzo#include <sys/kdb.h>
42239919Sgonzo
43239919Sgonzo/* PL011 UART registers and masks*/
44239919Sgonzo#define	UART_DR		0x00		/* Data register */
45239919Sgonzo#define	DR_FE		(1 << 8)	/* Framing error */
46239919Sgonzo#define	DR_PE		(1 << 9)	/* Parity error */
47239919Sgonzo#define	DR_BE		(1 << 10)	/* Break error */
48239919Sgonzo#define	DR_OE		(1 << 11)	/* Overrun error */
49239919Sgonzo
50239919Sgonzo#define	UART_FR		0x06		/* Flag register */
51239919Sgonzo#define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
52239919Sgonzo#define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
53239919Sgonzo
54239919Sgonzo#define	UART_IBRD	0x09		/* Integer baud rate register */
55239919Sgonzo#define	IBRD_BDIVINT	0xffff	/* Significant part of int. divisor value */
56239919Sgonzo
57239919Sgonzo#define	UART_FBRD	0x0a		/* Fractional baud rate register */
58239919Sgonzo#define	FBRD_BDIVFRAC	0x3f	/* Significant part of frac. divisor value */
59239919Sgonzo
60239919Sgonzo#define	UART_LCR_H	0x0b		/* Line control register */
61239919Sgonzo#define	LCR_H_WLEN8	(0x3 << 5)
62239919Sgonzo#define	LCR_H_WLEN7	(0x2 << 5)
63239919Sgonzo#define	LCR_H_WLEN6	(0x1 << 5)
64239919Sgonzo#define	LCR_H_FEN	(1 << 4)	/* FIFO mode enable */
65239919Sgonzo#define	LCR_H_STP2	(1 << 3)	/* 2 stop frames at the end */
66239919Sgonzo#define	LCR_H_EPS	(1 << 2)	/* Even parity select */
67239919Sgonzo#define	LCR_H_PEN	(1 << 1)	/* Parity enable */
68239919Sgonzo
69239919Sgonzo#define	UART_CR		0x0c		/* Control register */
70239919Sgonzo#define	CR_RXE		(1 << 9)	/* Receive enable */
71239919Sgonzo#define	CR_TXE		(1 << 8)	/* Transmit enable */
72239919Sgonzo#define	CR_UARTEN	(1 << 0)	/* UART enable */
73239919Sgonzo
74239919Sgonzo#define	UART_IMSC	0x0e		/* Interrupt mask set/clear register */
75239919Sgonzo#define	IMSC_MASK_ALL	0x7ff		/* Mask all interrupts */
76239919Sgonzo
77239919Sgonzo#define	UART_RIS	0x0f		/* Raw interrupt status register */
78239919Sgonzo#define	UART_RXREADY	(1 << 4)	/* RX buffer full */
79239919Sgonzo#define	UART_TXEMPTY	(1 << 5)	/* TX buffer empty */
80239919Sgonzo#define	RIS_FE		(1 << 7)	/* Framing error interrupt status */
81239919Sgonzo#define	RIS_PE		(1 << 8)	/* Parity error interrupt status */
82239919Sgonzo#define	RIS_BE		(1 << 9)	/* Break error interrupt status */
83239919Sgonzo#define	RIS_OE		(1 << 10)	/* Overrun interrupt status */
84239919Sgonzo
85239919Sgonzo#define	UART_MIS	0x10		/* Masked interrupt status register */
86239919Sgonzo#define	UART_ICR	0x11		/* Interrupt clear register */
87239919Sgonzo
88239919Sgonzo/*
89239919Sgonzo * FIXME: actual register size is SoC-dependent, we need to handle it
90239919Sgonzo */
91239919Sgonzo#define	__uart_getreg(bas, reg)		\
92239919Sgonzo	bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
93239919Sgonzo#define	__uart_setreg(bas, reg, value)	\
94239919Sgonzo	bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
95239919Sgonzo
96239919Sgonzo/*
97239919Sgonzo * Low-level UART interface.
98239919Sgonzo */
99239919Sgonzostatic int uart_pl011_probe(struct uart_bas *bas);
100239919Sgonzostatic void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
101239919Sgonzostatic void uart_pl011_term(struct uart_bas *bas);
102239919Sgonzostatic void uart_pl011_putc(struct uart_bas *bas, int);
103239919Sgonzostatic int uart_pl011_rxready(struct uart_bas *bas);
104239919Sgonzostatic int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
105239919Sgonzo
106239919Sgonzostatic struct uart_ops uart_pl011_ops = {
107239919Sgonzo	.probe = uart_pl011_probe,
108239919Sgonzo	.init = uart_pl011_init,
109239919Sgonzo	.term = uart_pl011_term,
110239919Sgonzo	.putc = uart_pl011_putc,
111239919Sgonzo	.rxready = uart_pl011_rxready,
112239919Sgonzo	.getc = uart_pl011_getc,
113239919Sgonzo};
114239919Sgonzo
115239919Sgonzostatic int
116239919Sgonzouart_pl011_probe(struct uart_bas *bas)
117239919Sgonzo{
118239919Sgonzo
119239919Sgonzo	return (0);
120239919Sgonzo}
121239919Sgonzo
122239919Sgonzostatic void
123239919Sgonzouart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
124239919Sgonzo    int parity)
125239919Sgonzo{
126239919Sgonzo	uint32_t ctrl, line;
127239919Sgonzo	uint32_t baud;
128239919Sgonzo
129239919Sgonzo	/* Mask all interrupts */
130239919Sgonzo	__uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
131239919Sgonzo	    ~IMSC_MASK_ALL);
132239919Sgonzo
133239919Sgonzo	/*
134239919Sgonzo	 * Zero all settings to make sure
135239919Sgonzo	 * UART is disabled and not configured
136239919Sgonzo	 */
137239919Sgonzo	ctrl = line = 0x0;
138239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
139239919Sgonzo
140239919Sgonzo	/* As we know UART is disabled we may setup the line */
141239919Sgonzo	switch (databits) {
142239919Sgonzo	case 7:
143239919Sgonzo		line |= LCR_H_WLEN7;
144239919Sgonzo		break;
145239919Sgonzo	case 6:
146239919Sgonzo		line |= LCR_H_WLEN6;
147239919Sgonzo		break;
148239919Sgonzo	case 8:
149239919Sgonzo	default:
150239919Sgonzo		line |= LCR_H_WLEN8;
151239919Sgonzo		break;
152239919Sgonzo	}
153239919Sgonzo
154239919Sgonzo	/* TODO: Calculate divisors */
155239919Sgonzo	baud = (0x1 << 16) | 0x28;
156239919Sgonzo
157239919Sgonzo	if (stopbits == 2)
158239919Sgonzo		line |= LCR_H_STP2;
159239919Sgonzo	else
160239919Sgonzo		line &= ~LCR_H_STP2;
161239919Sgonzo
162239919Sgonzo	if (parity)
163239919Sgonzo		line |= LCR_H_PEN;
164239919Sgonzo	else
165239919Sgonzo		line &= ~LCR_H_PEN;
166239919Sgonzo
167239919Sgonzo	/* Configure the rest */
168239919Sgonzo	line &=  ~LCR_H_FEN;
169239919Sgonzo	ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
170239919Sgonzo
171239919Sgonzo	__uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 16)) & IBRD_BDIVINT);
172239919Sgonzo	__uart_setreg(bas, UART_FBRD, (uint32_t)(baud) & FBRD_BDIVFRAC);
173239919Sgonzo
174239919Sgonzo	/* Add config. to line before reenabling UART */
175239919Sgonzo	__uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
176239919Sgonzo	    ~0xff) | line);
177239919Sgonzo
178239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
179239919Sgonzo}
180239919Sgonzo
181239919Sgonzostatic void
182239919Sgonzouart_pl011_term(struct uart_bas *bas)
183239919Sgonzo{
184239919Sgonzo}
185239919Sgonzo
186239919Sgonzostatic void
187239919Sgonzouart_pl011_putc(struct uart_bas *bas, int c)
188239919Sgonzo{
189239919Sgonzo
190239919Sgonzo	while (!(__uart_getreg(bas, UART_FR) & FR_TXFE))
191239919Sgonzo		;
192239919Sgonzo	__uart_setreg(bas, UART_DR, c & 0xff);
193239919Sgonzo}
194239919Sgonzo
195239919Sgonzostatic int
196239919Sgonzouart_pl011_rxready(struct uart_bas *bas)
197239919Sgonzo{
198239919Sgonzo
199239919Sgonzo	return (__uart_getreg(bas, UART_FR) & FR_RXFF);
200239919Sgonzo}
201239919Sgonzo
202239919Sgonzostatic int
203239919Sgonzouart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
204239919Sgonzo{
205239919Sgonzo	int c;
206239919Sgonzo
207239919Sgonzo	while (!uart_pl011_rxready(bas))
208239919Sgonzo		;
209239919Sgonzo	c = __uart_getreg(bas, UART_DR) & 0xff;
210239919Sgonzo
211239919Sgonzo	return (c);
212239919Sgonzo}
213239919Sgonzo
214239919Sgonzo/*
215239919Sgonzo * High-level UART interface.
216239919Sgonzo */
217239919Sgonzostruct uart_pl011_softc {
218239919Sgonzo	struct uart_softc base;
219239919Sgonzo	uint8_t		fcr;
220239919Sgonzo	uint8_t		ier;
221239919Sgonzo	uint8_t		mcr;
222239919Sgonzo
223239919Sgonzo	uint8_t		ier_mask;
224239919Sgonzo	uint8_t		ier_rxbits;
225239919Sgonzo};
226239919Sgonzo
227239919Sgonzostatic int uart_pl011_bus_attach(struct uart_softc *);
228239919Sgonzostatic int uart_pl011_bus_detach(struct uart_softc *);
229239919Sgonzostatic int uart_pl011_bus_flush(struct uart_softc *, int);
230239919Sgonzostatic int uart_pl011_bus_getsig(struct uart_softc *);
231239919Sgonzostatic int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
232239919Sgonzostatic int uart_pl011_bus_ipend(struct uart_softc *);
233239919Sgonzostatic int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
234239919Sgonzostatic int uart_pl011_bus_probe(struct uart_softc *);
235239919Sgonzostatic int uart_pl011_bus_receive(struct uart_softc *);
236239919Sgonzostatic int uart_pl011_bus_setsig(struct uart_softc *, int);
237239919Sgonzostatic int uart_pl011_bus_transmit(struct uart_softc *);
238239919Sgonzo
239239919Sgonzostatic kobj_method_t uart_pl011_methods[] = {
240239919Sgonzo	KOBJMETHOD(uart_attach,		uart_pl011_bus_attach),
241239919Sgonzo	KOBJMETHOD(uart_detach,		uart_pl011_bus_detach),
242239919Sgonzo	KOBJMETHOD(uart_flush,		uart_pl011_bus_flush),
243239919Sgonzo	KOBJMETHOD(uart_getsig,		uart_pl011_bus_getsig),
244239919Sgonzo	KOBJMETHOD(uart_ioctl,		uart_pl011_bus_ioctl),
245239919Sgonzo	KOBJMETHOD(uart_ipend,		uart_pl011_bus_ipend),
246239919Sgonzo	KOBJMETHOD(uart_param,		uart_pl011_bus_param),
247239919Sgonzo	KOBJMETHOD(uart_probe,		uart_pl011_bus_probe),
248239919Sgonzo	KOBJMETHOD(uart_receive,	uart_pl011_bus_receive),
249239919Sgonzo	KOBJMETHOD(uart_setsig,		uart_pl011_bus_setsig),
250239919Sgonzo	KOBJMETHOD(uart_transmit,	uart_pl011_bus_transmit),
251239919Sgonzo	{ 0, 0 }
252239919Sgonzo};
253239919Sgonzo
254239919Sgonzostruct uart_class uart_pl011_class = {
255239919Sgonzo	"uart_pl011",
256239919Sgonzo	uart_pl011_methods,
257239919Sgonzo	sizeof(struct uart_pl011_softc),
258239919Sgonzo	.uc_ops = &uart_pl011_ops,
259239919Sgonzo	.uc_range = 0x48,
260239919Sgonzo	.uc_rclk = 0
261239919Sgonzo};
262239919Sgonzo
263239919Sgonzostatic int
264239919Sgonzouart_pl011_bus_attach(struct uart_softc *sc)
265239919Sgonzo{
266239919Sgonzo	struct uart_bas *bas;
267239919Sgonzo
268239919Sgonzo	bas = &sc->sc_bas;
269239919Sgonzo	/* Enable RX & TX interrupts */
270239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
271239919Sgonzo	/* Clear RX & TX interrupts */
272239919Sgonzo	__uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
273239919Sgonzo
274239919Sgonzo	sc->sc_rxfifosz = 1;
275239919Sgonzo	sc->sc_txfifosz = 1;
276239919Sgonzo
277239919Sgonzo	return (0);
278239919Sgonzo}
279239919Sgonzo
280239919Sgonzostatic int
281239919Sgonzouart_pl011_bus_detach(struct uart_softc *sc)
282239919Sgonzo{
283239919Sgonzo
284239919Sgonzo	return (0);
285239919Sgonzo}
286239919Sgonzo
287239919Sgonzostatic int
288239919Sgonzouart_pl011_bus_flush(struct uart_softc *sc, int what)
289239919Sgonzo{
290239919Sgonzo
291239919Sgonzo	return (0);
292239919Sgonzo}
293239919Sgonzo
294239919Sgonzostatic int
295239919Sgonzouart_pl011_bus_getsig(struct uart_softc *sc)
296239919Sgonzo{
297239919Sgonzo
298239919Sgonzo	return (0);
299239919Sgonzo}
300239919Sgonzo
301239919Sgonzostatic int
302239919Sgonzouart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
303239919Sgonzo{
304239919Sgonzo	struct uart_bas *bas;
305239919Sgonzo	int error;
306239919Sgonzo
307239919Sgonzo	bas = &sc->sc_bas;
308239919Sgonzo	error = 0;
309239919Sgonzo	uart_lock(sc->sc_hwmtx);
310239919Sgonzo	switch (request) {
311239919Sgonzo	case UART_IOCTL_BREAK:
312239919Sgonzo		break;
313239919Sgonzo	case UART_IOCTL_BAUD:
314239919Sgonzo		*(int*)data = 115200;
315239919Sgonzo		break;
316239919Sgonzo	default:
317239919Sgonzo		error = EINVAL;
318239919Sgonzo		break;
319239919Sgonzo	}
320239919Sgonzo	uart_unlock(sc->sc_hwmtx);
321239919Sgonzo
322239919Sgonzo	return (error);
323239919Sgonzo}
324239919Sgonzo
325239919Sgonzostatic int
326239919Sgonzouart_pl011_bus_ipend(struct uart_softc *sc)
327239919Sgonzo{
328239919Sgonzo	struct uart_bas *bas;
329239919Sgonzo	int ipend;
330239919Sgonzo	uint32_t ints;
331239919Sgonzo
332239919Sgonzo	bas = &sc->sc_bas;
333239919Sgonzo	uart_lock(sc->sc_hwmtx);
334239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
335239919Sgonzo	ipend = 0;
336239919Sgonzo
337239919Sgonzo	if (ints & UART_RXREADY)
338239919Sgonzo		ipend |= SER_INT_RXREADY;
339239919Sgonzo	if (ints & RIS_BE)
340239919Sgonzo		ipend |= SER_INT_BREAK;
341239919Sgonzo	if (ints & RIS_OE)
342239919Sgonzo		ipend |= SER_INT_OVERRUN;
343239919Sgonzo	if (ints & UART_TXEMPTY) {
344239919Sgonzo		if (sc->sc_txbusy)
345239919Sgonzo			ipend |= SER_INT_TXIDLE;
346239919Sgonzo
347239919Sgonzo		__uart_setreg(bas, UART_IMSC, UART_RXREADY);
348239919Sgonzo	}
349239919Sgonzo
350239919Sgonzo	uart_unlock(sc->sc_hwmtx);
351239919Sgonzo
352239919Sgonzo	return (ipend);
353239919Sgonzo}
354239919Sgonzo
355239919Sgonzostatic int
356239919Sgonzouart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
357239919Sgonzo    int stopbits, int parity)
358239919Sgonzo{
359239919Sgonzo
360239919Sgonzo	uart_lock(sc->sc_hwmtx);
361239919Sgonzo	uart_pl011_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
362239919Sgonzo	uart_unlock(sc->sc_hwmtx);
363239919Sgonzo
364239919Sgonzo	return (0);
365239919Sgonzo}
366239919Sgonzo
367239919Sgonzostatic int
368239919Sgonzouart_pl011_bus_probe(struct uart_softc *sc)
369239919Sgonzo{
370239919Sgonzo
371239919Sgonzo	device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
372239919Sgonzo
373239919Sgonzo	return (0);
374239919Sgonzo}
375239919Sgonzo
376239919Sgonzostatic int
377239919Sgonzouart_pl011_bus_receive(struct uart_softc *sc)
378239919Sgonzo{
379239919Sgonzo	struct uart_bas *bas;
380239919Sgonzo	int rx;
381239919Sgonzo	uint32_t ints, xc;
382239919Sgonzo
383239919Sgonzo	bas = &sc->sc_bas;
384239919Sgonzo	uart_lock(sc->sc_hwmtx);
385239919Sgonzo
386239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
387239919Sgonzo	while (ints & UART_RXREADY) {
388239919Sgonzo		if (uart_rx_full(sc)) {
389239919Sgonzo			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
390239919Sgonzo			break;
391239919Sgonzo		}
392239919Sgonzo		xc = __uart_getreg(bas, UART_DR);
393239919Sgonzo		rx = xc & 0xff;
394239919Sgonzo
395239919Sgonzo		if (xc & DR_FE)
396239919Sgonzo			rx |= UART_STAT_FRAMERR;
397239919Sgonzo		if (xc & DR_PE)
398239919Sgonzo			rx |= UART_STAT_PARERR;
399239919Sgonzo
400239919Sgonzo		__uart_setreg(bas, UART_ICR, UART_RXREADY);
401239919Sgonzo
402239919Sgonzo		uart_rx_put(sc, rx);
403239919Sgonzo		ints = __uart_getreg(bas, UART_MIS);
404239919Sgonzo	}
405239919Sgonzo
406239919Sgonzo	uart_unlock(sc->sc_hwmtx);
407239919Sgonzo
408239919Sgonzo	return (0);
409239919Sgonzo}
410239919Sgonzo
411239919Sgonzostatic int
412239919Sgonzouart_pl011_bus_setsig(struct uart_softc *sc, int sig)
413239919Sgonzo{
414239919Sgonzo
415239919Sgonzo	return (0);
416239919Sgonzo}
417239919Sgonzo
418239919Sgonzostatic int
419239919Sgonzouart_pl011_bus_transmit(struct uart_softc *sc)
420239919Sgonzo{
421239919Sgonzo	struct uart_bas *bas;
422239919Sgonzo	int i;
423239919Sgonzo
424239919Sgonzo	bas = &sc->sc_bas;
425239919Sgonzo	uart_lock(sc->sc_hwmtx);
426239919Sgonzo
427239919Sgonzo	for (i = 0; i < sc->sc_txdatasz; i++) {
428239919Sgonzo		__uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
429239919Sgonzo		uart_barrier(bas);
430239919Sgonzo	}
431239919Sgonzo	sc->sc_txbusy = 1;
432239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
433239919Sgonzo	uart_unlock(sc->sc_hwmtx);
434239919Sgonzo
435239919Sgonzo	return (0);
436239919Sgonzo}
437