uart_dev_pl011.c revision 283321
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: stable/10/sys/dev/uart/uart_dev_pl011.c 283321 2015-05-23 19:27:04Z ian $");
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 */
51283321Sian#define	FR_TXFF		(1 << 5)	/* Transmit FIFO/reg full */
52239919Sgonzo#define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
53239919Sgonzo#define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
54239919Sgonzo
55239919Sgonzo#define	UART_IBRD	0x09		/* Integer baud rate register */
56239919Sgonzo#define	IBRD_BDIVINT	0xffff	/* Significant part of int. divisor value */
57239919Sgonzo
58239919Sgonzo#define	UART_FBRD	0x0a		/* Fractional baud rate register */
59239919Sgonzo#define	FBRD_BDIVFRAC	0x3f	/* Significant part of frac. divisor value */
60239919Sgonzo
61239919Sgonzo#define	UART_LCR_H	0x0b		/* Line control register */
62239919Sgonzo#define	LCR_H_WLEN8	(0x3 << 5)
63239919Sgonzo#define	LCR_H_WLEN7	(0x2 << 5)
64239919Sgonzo#define	LCR_H_WLEN6	(0x1 << 5)
65239919Sgonzo#define	LCR_H_FEN	(1 << 4)	/* FIFO mode enable */
66239919Sgonzo#define	LCR_H_STP2	(1 << 3)	/* 2 stop frames at the end */
67239919Sgonzo#define	LCR_H_EPS	(1 << 2)	/* Even parity select */
68239919Sgonzo#define	LCR_H_PEN	(1 << 1)	/* Parity enable */
69239919Sgonzo
70239919Sgonzo#define	UART_CR		0x0c		/* Control register */
71239919Sgonzo#define	CR_RXE		(1 << 9)	/* Receive enable */
72239919Sgonzo#define	CR_TXE		(1 << 8)	/* Transmit enable */
73239919Sgonzo#define	CR_UARTEN	(1 << 0)	/* UART enable */
74239919Sgonzo
75239919Sgonzo#define	UART_IMSC	0x0e		/* Interrupt mask set/clear register */
76239919Sgonzo#define	IMSC_MASK_ALL	0x7ff		/* Mask all interrupts */
77239919Sgonzo
78239919Sgonzo#define	UART_RIS	0x0f		/* Raw interrupt status register */
79239919Sgonzo#define	UART_RXREADY	(1 << 4)	/* RX buffer full */
80239919Sgonzo#define	UART_TXEMPTY	(1 << 5)	/* TX buffer empty */
81239919Sgonzo#define	RIS_FE		(1 << 7)	/* Framing error interrupt status */
82239919Sgonzo#define	RIS_PE		(1 << 8)	/* Parity error interrupt status */
83239919Sgonzo#define	RIS_BE		(1 << 9)	/* Break error interrupt status */
84239919Sgonzo#define	RIS_OE		(1 << 10)	/* Overrun interrupt status */
85239919Sgonzo
86239919Sgonzo#define	UART_MIS	0x10		/* Masked interrupt status register */
87239919Sgonzo#define	UART_ICR	0x11		/* Interrupt clear register */
88239919Sgonzo
89239919Sgonzo/*
90239919Sgonzo * FIXME: actual register size is SoC-dependent, we need to handle it
91239919Sgonzo */
92239919Sgonzo#define	__uart_getreg(bas, reg)		\
93239919Sgonzo	bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
94239919Sgonzo#define	__uart_setreg(bas, reg, value)	\
95239919Sgonzo	bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
96239919Sgonzo
97239919Sgonzo/*
98239919Sgonzo * Low-level UART interface.
99239919Sgonzo */
100239919Sgonzostatic int uart_pl011_probe(struct uart_bas *bas);
101239919Sgonzostatic void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
102239919Sgonzostatic void uart_pl011_term(struct uart_bas *bas);
103239919Sgonzostatic void uart_pl011_putc(struct uart_bas *bas, int);
104239919Sgonzostatic int uart_pl011_rxready(struct uart_bas *bas);
105239919Sgonzostatic int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
106239919Sgonzo
107239919Sgonzostatic struct uart_ops uart_pl011_ops = {
108239919Sgonzo	.probe = uart_pl011_probe,
109239919Sgonzo	.init = uart_pl011_init,
110239919Sgonzo	.term = uart_pl011_term,
111239919Sgonzo	.putc = uart_pl011_putc,
112239919Sgonzo	.rxready = uart_pl011_rxready,
113239919Sgonzo	.getc = uart_pl011_getc,
114239919Sgonzo};
115239919Sgonzo
116239919Sgonzostatic int
117239919Sgonzouart_pl011_probe(struct uart_bas *bas)
118239919Sgonzo{
119239919Sgonzo
120239919Sgonzo	return (0);
121239919Sgonzo}
122239919Sgonzo
123239919Sgonzostatic void
124242333Sgonzouart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
125239919Sgonzo    int parity)
126239919Sgonzo{
127239919Sgonzo	uint32_t ctrl, line;
128239919Sgonzo	uint32_t baud;
129239919Sgonzo
130239919Sgonzo	/*
131239919Sgonzo	 * Zero all settings to make sure
132239919Sgonzo	 * UART is disabled and not configured
133239919Sgonzo	 */
134239919Sgonzo	ctrl = line = 0x0;
135239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
136239919Sgonzo
137239919Sgonzo	/* As we know UART is disabled we may setup the line */
138239919Sgonzo	switch (databits) {
139239919Sgonzo	case 7:
140239919Sgonzo		line |= LCR_H_WLEN7;
141239919Sgonzo		break;
142239919Sgonzo	case 6:
143239919Sgonzo		line |= LCR_H_WLEN6;
144239919Sgonzo		break;
145239919Sgonzo	case 8:
146239919Sgonzo	default:
147239919Sgonzo		line |= LCR_H_WLEN8;
148239919Sgonzo		break;
149239919Sgonzo	}
150239919Sgonzo
151239919Sgonzo	if (stopbits == 2)
152239919Sgonzo		line |= LCR_H_STP2;
153239919Sgonzo	else
154239919Sgonzo		line &= ~LCR_H_STP2;
155239919Sgonzo
156239919Sgonzo	if (parity)
157239919Sgonzo		line |= LCR_H_PEN;
158239919Sgonzo	else
159239919Sgonzo		line &= ~LCR_H_PEN;
160239919Sgonzo
161239919Sgonzo	/* Configure the rest */
162239919Sgonzo	line &=  ~LCR_H_FEN;
163239919Sgonzo	ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
164239919Sgonzo
165259319Sian	if (bas->rclk != 0 && baudrate != 0) {
166259319Sian		baud = bas->rclk * 4 / baudrate;
167259319Sian		__uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 6)) & IBRD_BDIVINT);
168259319Sian		__uart_setreg(bas, UART_FBRD, (uint32_t)(baud & 0x3F) & FBRD_BDIVFRAC);
169259319Sian	}
170239919Sgonzo
171239919Sgonzo	/* Add config. to line before reenabling UART */
172239919Sgonzo	__uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
173239919Sgonzo	    ~0xff) | line);
174239919Sgonzo
175239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
176239919Sgonzo}
177239919Sgonzo
178239919Sgonzostatic void
179242333Sgonzouart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
180242333Sgonzo    int parity)
181242333Sgonzo{
182242333Sgonzo	/* Mask all interrupts */
183242333Sgonzo	__uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
184242333Sgonzo	    ~IMSC_MASK_ALL);
185242333Sgonzo
186242333Sgonzo	uart_pl011_param(bas, baudrate, databits, stopbits, parity);
187242333Sgonzo}
188242333Sgonzo
189242333Sgonzostatic void
190239919Sgonzouart_pl011_term(struct uart_bas *bas)
191239919Sgonzo{
192239919Sgonzo}
193239919Sgonzo
194239919Sgonzostatic void
195239919Sgonzouart_pl011_putc(struct uart_bas *bas, int c)
196239919Sgonzo{
197239919Sgonzo
198283321Sian	/* Wait when TX FIFO full. Push character otherwise. */
199283321Sian	while (__uart_getreg(bas, UART_FR) & FR_TXFF)
200239919Sgonzo		;
201239919Sgonzo	__uart_setreg(bas, UART_DR, c & 0xff);
202239919Sgonzo}
203239919Sgonzo
204239919Sgonzostatic int
205239919Sgonzouart_pl011_rxready(struct uart_bas *bas)
206239919Sgonzo{
207239919Sgonzo
208239919Sgonzo	return (__uart_getreg(bas, UART_FR) & FR_RXFF);
209239919Sgonzo}
210239919Sgonzo
211239919Sgonzostatic int
212239919Sgonzouart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
213239919Sgonzo{
214239919Sgonzo	int c;
215239919Sgonzo
216239919Sgonzo	while (!uart_pl011_rxready(bas))
217239919Sgonzo		;
218239919Sgonzo	c = __uart_getreg(bas, UART_DR) & 0xff;
219239919Sgonzo
220239919Sgonzo	return (c);
221239919Sgonzo}
222239919Sgonzo
223239919Sgonzo/*
224239919Sgonzo * High-level UART interface.
225239919Sgonzo */
226239919Sgonzostruct uart_pl011_softc {
227239919Sgonzo	struct uart_softc base;
228239919Sgonzo	uint8_t		fcr;
229239919Sgonzo	uint8_t		ier;
230239919Sgonzo	uint8_t		mcr;
231239919Sgonzo
232239919Sgonzo	uint8_t		ier_mask;
233239919Sgonzo	uint8_t		ier_rxbits;
234239919Sgonzo};
235239919Sgonzo
236239919Sgonzostatic int uart_pl011_bus_attach(struct uart_softc *);
237239919Sgonzostatic int uart_pl011_bus_detach(struct uart_softc *);
238239919Sgonzostatic int uart_pl011_bus_flush(struct uart_softc *, int);
239239919Sgonzostatic int uart_pl011_bus_getsig(struct uart_softc *);
240239919Sgonzostatic int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
241239919Sgonzostatic int uart_pl011_bus_ipend(struct uart_softc *);
242239919Sgonzostatic int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
243239919Sgonzostatic int uart_pl011_bus_probe(struct uart_softc *);
244239919Sgonzostatic int uart_pl011_bus_receive(struct uart_softc *);
245239919Sgonzostatic int uart_pl011_bus_setsig(struct uart_softc *, int);
246239919Sgonzostatic int uart_pl011_bus_transmit(struct uart_softc *);
247262649Simpstatic void uart_pl011_bus_grab(struct uart_softc *);
248262649Simpstatic void uart_pl011_bus_ungrab(struct uart_softc *);
249239919Sgonzo
250239919Sgonzostatic kobj_method_t uart_pl011_methods[] = {
251239919Sgonzo	KOBJMETHOD(uart_attach,		uart_pl011_bus_attach),
252239919Sgonzo	KOBJMETHOD(uart_detach,		uart_pl011_bus_detach),
253239919Sgonzo	KOBJMETHOD(uart_flush,		uart_pl011_bus_flush),
254239919Sgonzo	KOBJMETHOD(uart_getsig,		uart_pl011_bus_getsig),
255239919Sgonzo	KOBJMETHOD(uart_ioctl,		uart_pl011_bus_ioctl),
256239919Sgonzo	KOBJMETHOD(uart_ipend,		uart_pl011_bus_ipend),
257239919Sgonzo	KOBJMETHOD(uart_param,		uart_pl011_bus_param),
258239919Sgonzo	KOBJMETHOD(uart_probe,		uart_pl011_bus_probe),
259239919Sgonzo	KOBJMETHOD(uart_receive,	uart_pl011_bus_receive),
260239919Sgonzo	KOBJMETHOD(uart_setsig,		uart_pl011_bus_setsig),
261239919Sgonzo	KOBJMETHOD(uart_transmit,	uart_pl011_bus_transmit),
262262649Simp	KOBJMETHOD(uart_grab,		uart_pl011_bus_grab),
263262649Simp	KOBJMETHOD(uart_ungrab,		uart_pl011_bus_ungrab),
264262649Simp
265239919Sgonzo	{ 0, 0 }
266239919Sgonzo};
267239919Sgonzo
268239919Sgonzostruct uart_class uart_pl011_class = {
269239919Sgonzo	"uart_pl011",
270239919Sgonzo	uart_pl011_methods,
271239919Sgonzo	sizeof(struct uart_pl011_softc),
272239919Sgonzo	.uc_ops = &uart_pl011_ops,
273239919Sgonzo	.uc_range = 0x48,
274239919Sgonzo	.uc_rclk = 0
275239919Sgonzo};
276239919Sgonzo
277239919Sgonzostatic int
278239919Sgonzouart_pl011_bus_attach(struct uart_softc *sc)
279239919Sgonzo{
280239919Sgonzo	struct uart_bas *bas;
281239919Sgonzo
282239919Sgonzo	bas = &sc->sc_bas;
283239919Sgonzo	/* Enable RX & TX interrupts */
284239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
285239919Sgonzo	/* Clear RX & TX interrupts */
286239919Sgonzo	__uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
287239919Sgonzo
288239919Sgonzo	return (0);
289239919Sgonzo}
290239919Sgonzo
291239919Sgonzostatic int
292239919Sgonzouart_pl011_bus_detach(struct uart_softc *sc)
293239919Sgonzo{
294239919Sgonzo
295239919Sgonzo	return (0);
296239919Sgonzo}
297239919Sgonzo
298239919Sgonzostatic int
299239919Sgonzouart_pl011_bus_flush(struct uart_softc *sc, int what)
300239919Sgonzo{
301239919Sgonzo
302239919Sgonzo	return (0);
303239919Sgonzo}
304239919Sgonzo
305239919Sgonzostatic int
306239919Sgonzouart_pl011_bus_getsig(struct uart_softc *sc)
307239919Sgonzo{
308239919Sgonzo
309239919Sgonzo	return (0);
310239919Sgonzo}
311239919Sgonzo
312239919Sgonzostatic int
313239919Sgonzouart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
314239919Sgonzo{
315239919Sgonzo	struct uart_bas *bas;
316239919Sgonzo	int error;
317239919Sgonzo
318239919Sgonzo	bas = &sc->sc_bas;
319239919Sgonzo	error = 0;
320239919Sgonzo	uart_lock(sc->sc_hwmtx);
321239919Sgonzo	switch (request) {
322239919Sgonzo	case UART_IOCTL_BREAK:
323239919Sgonzo		break;
324239919Sgonzo	case UART_IOCTL_BAUD:
325239919Sgonzo		*(int*)data = 115200;
326239919Sgonzo		break;
327239919Sgonzo	default:
328239919Sgonzo		error = EINVAL;
329239919Sgonzo		break;
330239919Sgonzo	}
331239919Sgonzo	uart_unlock(sc->sc_hwmtx);
332239919Sgonzo
333239919Sgonzo	return (error);
334239919Sgonzo}
335239919Sgonzo
336239919Sgonzostatic int
337239919Sgonzouart_pl011_bus_ipend(struct uart_softc *sc)
338239919Sgonzo{
339239919Sgonzo	struct uart_bas *bas;
340239919Sgonzo	int ipend;
341239919Sgonzo	uint32_t ints;
342239919Sgonzo
343239919Sgonzo	bas = &sc->sc_bas;
344239919Sgonzo	uart_lock(sc->sc_hwmtx);
345239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
346239919Sgonzo	ipend = 0;
347239919Sgonzo
348239919Sgonzo	if (ints & UART_RXREADY)
349239919Sgonzo		ipend |= SER_INT_RXREADY;
350239919Sgonzo	if (ints & RIS_BE)
351239919Sgonzo		ipend |= SER_INT_BREAK;
352239919Sgonzo	if (ints & RIS_OE)
353239919Sgonzo		ipend |= SER_INT_OVERRUN;
354239919Sgonzo	if (ints & UART_TXEMPTY) {
355239919Sgonzo		if (sc->sc_txbusy)
356239919Sgonzo			ipend |= SER_INT_TXIDLE;
357239919Sgonzo
358239919Sgonzo		__uart_setreg(bas, UART_IMSC, UART_RXREADY);
359239919Sgonzo	}
360239919Sgonzo
361239919Sgonzo	uart_unlock(sc->sc_hwmtx);
362239919Sgonzo
363239919Sgonzo	return (ipend);
364239919Sgonzo}
365239919Sgonzo
366239919Sgonzostatic int
367239919Sgonzouart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
368239919Sgonzo    int stopbits, int parity)
369239919Sgonzo{
370239919Sgonzo
371239919Sgonzo	uart_lock(sc->sc_hwmtx);
372242333Sgonzo	uart_pl011_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
373239919Sgonzo	uart_unlock(sc->sc_hwmtx);
374239919Sgonzo
375239919Sgonzo	return (0);
376239919Sgonzo}
377239919Sgonzo
378239919Sgonzostatic int
379239919Sgonzouart_pl011_bus_probe(struct uart_softc *sc)
380239919Sgonzo{
381239919Sgonzo
382239919Sgonzo	device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
383239919Sgonzo
384248965Sian	sc->sc_rxfifosz = 1;
385248965Sian	sc->sc_txfifosz = 1;
386248965Sian
387239919Sgonzo	return (0);
388239919Sgonzo}
389239919Sgonzo
390239919Sgonzostatic int
391239919Sgonzouart_pl011_bus_receive(struct uart_softc *sc)
392239919Sgonzo{
393239919Sgonzo	struct uart_bas *bas;
394239919Sgonzo	int rx;
395239919Sgonzo	uint32_t ints, xc;
396239919Sgonzo
397239919Sgonzo	bas = &sc->sc_bas;
398239919Sgonzo	uart_lock(sc->sc_hwmtx);
399239919Sgonzo
400239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
401239919Sgonzo	while (ints & UART_RXREADY) {
402239919Sgonzo		if (uart_rx_full(sc)) {
403239919Sgonzo			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
404239919Sgonzo			break;
405239919Sgonzo		}
406239919Sgonzo		xc = __uart_getreg(bas, UART_DR);
407239919Sgonzo		rx = xc & 0xff;
408239919Sgonzo
409239919Sgonzo		if (xc & DR_FE)
410239919Sgonzo			rx |= UART_STAT_FRAMERR;
411239919Sgonzo		if (xc & DR_PE)
412239919Sgonzo			rx |= UART_STAT_PARERR;
413239919Sgonzo
414239919Sgonzo		__uart_setreg(bas, UART_ICR, UART_RXREADY);
415239919Sgonzo
416239919Sgonzo		uart_rx_put(sc, rx);
417239919Sgonzo		ints = __uart_getreg(bas, UART_MIS);
418239919Sgonzo	}
419239919Sgonzo
420239919Sgonzo	uart_unlock(sc->sc_hwmtx);
421239919Sgonzo
422239919Sgonzo	return (0);
423239919Sgonzo}
424239919Sgonzo
425239919Sgonzostatic int
426239919Sgonzouart_pl011_bus_setsig(struct uart_softc *sc, int sig)
427239919Sgonzo{
428239919Sgonzo
429239919Sgonzo	return (0);
430239919Sgonzo}
431239919Sgonzo
432239919Sgonzostatic int
433239919Sgonzouart_pl011_bus_transmit(struct uart_softc *sc)
434239919Sgonzo{
435239919Sgonzo	struct uart_bas *bas;
436239919Sgonzo	int i;
437239919Sgonzo
438239919Sgonzo	bas = &sc->sc_bas;
439239919Sgonzo	uart_lock(sc->sc_hwmtx);
440239919Sgonzo
441239919Sgonzo	for (i = 0; i < sc->sc_txdatasz; i++) {
442239919Sgonzo		__uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
443239919Sgonzo		uart_barrier(bas);
444239919Sgonzo	}
445239919Sgonzo	sc->sc_txbusy = 1;
446239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
447239919Sgonzo	uart_unlock(sc->sc_hwmtx);
448239919Sgonzo
449239919Sgonzo	return (0);
450239919Sgonzo}
451262649Simp
452262649Simpstatic void
453262649Simpuart_pl011_bus_grab(struct uart_softc *sc)
454262649Simp{
455262649Simp	struct uart_bas *bas;
456262649Simp
457262649Simp	bas = &sc->sc_bas;
458262649Simp	uart_lock(sc->sc_hwmtx);
459262649Simp	__uart_setreg(bas, UART_IMSC, 	/* Switch to RX polling while grabbed */
460262649Simp	    ~UART_RXREADY & __uart_getreg(bas, UART_IMSC));
461262649Simp	uart_unlock(sc->sc_hwmtx);
462262649Simp}
463262649Simp
464262649Simpstatic void
465262649Simpuart_pl011_bus_ungrab(struct uart_softc *sc)
466262649Simp{
467262649Simp	struct uart_bas *bas;
468262649Simp
469262649Simp	bas = &sc->sc_bas;
470262649Simp	uart_lock(sc->sc_hwmtx);
471262649Simp	__uart_setreg(bas, UART_IMSC,	/* Switch to RX interrupts while not grabbed */
472262649Simp	    UART_RXREADY | __uart_getreg(bas, UART_IMSC));
473262649Simp	uart_unlock(sc->sc_hwmtx);
474262649Simp}
475