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