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: releng/10.2/sys/dev/uart/uart_dev_pl011.c 283327 2015-05-23 20:54:25Z 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>
38283327Sian#include <dev/uart/uart_cpu_fdt.h>
39239919Sgonzo#include <dev/uart/uart_bus.h>
40239919Sgonzo#include "uart_if.h"
41239919Sgonzo
42239919Sgonzo#include <sys/kdb.h>
43239919Sgonzo
44239919Sgonzo/* PL011 UART registers and masks*/
45239919Sgonzo#define	UART_DR		0x00		/* Data register */
46239919Sgonzo#define	DR_FE		(1 << 8)	/* Framing error */
47239919Sgonzo#define	DR_PE		(1 << 9)	/* Parity error */
48239919Sgonzo#define	DR_BE		(1 << 10)	/* Break error */
49239919Sgonzo#define	DR_OE		(1 << 11)	/* Overrun error */
50239919Sgonzo
51239919Sgonzo#define	UART_FR		0x06		/* Flag register */
52283321Sian#define	FR_TXFF		(1 << 5)	/* Transmit FIFO/reg full */
53239919Sgonzo#define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
54239919Sgonzo#define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
55239919Sgonzo
56239919Sgonzo#define	UART_IBRD	0x09		/* Integer baud rate register */
57239919Sgonzo#define	IBRD_BDIVINT	0xffff	/* Significant part of int. divisor value */
58239919Sgonzo
59239919Sgonzo#define	UART_FBRD	0x0a		/* Fractional baud rate register */
60239919Sgonzo#define	FBRD_BDIVFRAC	0x3f	/* Significant part of frac. divisor value */
61239919Sgonzo
62239919Sgonzo#define	UART_LCR_H	0x0b		/* Line control register */
63239919Sgonzo#define	LCR_H_WLEN8	(0x3 << 5)
64239919Sgonzo#define	LCR_H_WLEN7	(0x2 << 5)
65239919Sgonzo#define	LCR_H_WLEN6	(0x1 << 5)
66239919Sgonzo#define	LCR_H_FEN	(1 << 4)	/* FIFO mode enable */
67239919Sgonzo#define	LCR_H_STP2	(1 << 3)	/* 2 stop frames at the end */
68239919Sgonzo#define	LCR_H_EPS	(1 << 2)	/* Even parity select */
69239919Sgonzo#define	LCR_H_PEN	(1 << 1)	/* Parity enable */
70239919Sgonzo
71239919Sgonzo#define	UART_CR		0x0c		/* Control register */
72239919Sgonzo#define	CR_RXE		(1 << 9)	/* Receive enable */
73239919Sgonzo#define	CR_TXE		(1 << 8)	/* Transmit enable */
74239919Sgonzo#define	CR_UARTEN	(1 << 0)	/* UART enable */
75239919Sgonzo
76239919Sgonzo#define	UART_IMSC	0x0e		/* Interrupt mask set/clear register */
77239919Sgonzo#define	IMSC_MASK_ALL	0x7ff		/* Mask all interrupts */
78239919Sgonzo
79239919Sgonzo#define	UART_RIS	0x0f		/* Raw interrupt status register */
80239919Sgonzo#define	UART_RXREADY	(1 << 4)	/* RX buffer full */
81239919Sgonzo#define	UART_TXEMPTY	(1 << 5)	/* TX buffer empty */
82283324Sian#define	RIS_RTIM	(1 << 6)	/* Receive timeout */
83239919Sgonzo#define	RIS_FE		(1 << 7)	/* Framing error interrupt status */
84239919Sgonzo#define	RIS_PE		(1 << 8)	/* Parity error interrupt status */
85239919Sgonzo#define	RIS_BE		(1 << 9)	/* Break error interrupt status */
86239919Sgonzo#define	RIS_OE		(1 << 10)	/* Overrun interrupt status */
87239919Sgonzo
88239919Sgonzo#define	UART_MIS	0x10		/* Masked interrupt status register */
89239919Sgonzo#define	UART_ICR	0x11		/* Interrupt clear register */
90239919Sgonzo
91239919Sgonzo/*
92239919Sgonzo * FIXME: actual register size is SoC-dependent, we need to handle it
93239919Sgonzo */
94239919Sgonzo#define	__uart_getreg(bas, reg)		\
95239919Sgonzo	bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
96239919Sgonzo#define	__uart_setreg(bas, reg, value)	\
97239919Sgonzo	bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
98239919Sgonzo
99239919Sgonzo/*
100239919Sgonzo * Low-level UART interface.
101239919Sgonzo */
102239919Sgonzostatic int uart_pl011_probe(struct uart_bas *bas);
103239919Sgonzostatic void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
104239919Sgonzostatic void uart_pl011_term(struct uart_bas *bas);
105239919Sgonzostatic void uart_pl011_putc(struct uart_bas *bas, int);
106239919Sgonzostatic int uart_pl011_rxready(struct uart_bas *bas);
107239919Sgonzostatic int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
108239919Sgonzo
109239919Sgonzostatic struct uart_ops uart_pl011_ops = {
110239919Sgonzo	.probe = uart_pl011_probe,
111239919Sgonzo	.init = uart_pl011_init,
112239919Sgonzo	.term = uart_pl011_term,
113239919Sgonzo	.putc = uart_pl011_putc,
114239919Sgonzo	.rxready = uart_pl011_rxready,
115239919Sgonzo	.getc = uart_pl011_getc,
116239919Sgonzo};
117239919Sgonzo
118239919Sgonzostatic int
119239919Sgonzouart_pl011_probe(struct uart_bas *bas)
120239919Sgonzo{
121239919Sgonzo
122239919Sgonzo	return (0);
123239919Sgonzo}
124239919Sgonzo
125239919Sgonzostatic void
126242333Sgonzouart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
127239919Sgonzo    int parity)
128239919Sgonzo{
129239919Sgonzo	uint32_t ctrl, line;
130239919Sgonzo	uint32_t baud;
131239919Sgonzo
132239919Sgonzo	/*
133239919Sgonzo	 * Zero all settings to make sure
134239919Sgonzo	 * UART is disabled and not configured
135239919Sgonzo	 */
136239919Sgonzo	ctrl = line = 0x0;
137239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
138239919Sgonzo
139239919Sgonzo	/* As we know UART is disabled we may setup the line */
140239919Sgonzo	switch (databits) {
141239919Sgonzo	case 7:
142239919Sgonzo		line |= LCR_H_WLEN7;
143239919Sgonzo		break;
144239919Sgonzo	case 6:
145239919Sgonzo		line |= LCR_H_WLEN6;
146239919Sgonzo		break;
147239919Sgonzo	case 8:
148239919Sgonzo	default:
149239919Sgonzo		line |= LCR_H_WLEN8;
150239919Sgonzo		break;
151239919Sgonzo	}
152239919Sgonzo
153239919Sgonzo	if (stopbits == 2)
154239919Sgonzo		line |= LCR_H_STP2;
155239919Sgonzo	else
156239919Sgonzo		line &= ~LCR_H_STP2;
157239919Sgonzo
158239919Sgonzo	if (parity)
159239919Sgonzo		line |= LCR_H_PEN;
160239919Sgonzo	else
161239919Sgonzo		line &= ~LCR_H_PEN;
162239919Sgonzo
163239919Sgonzo	/* Configure the rest */
164239919Sgonzo	line &=  ~LCR_H_FEN;
165239919Sgonzo	ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
166239919Sgonzo
167259319Sian	if (bas->rclk != 0 && baudrate != 0) {
168259319Sian		baud = bas->rclk * 4 / baudrate;
169259319Sian		__uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 6)) & IBRD_BDIVINT);
170259319Sian		__uart_setreg(bas, UART_FBRD, (uint32_t)(baud & 0x3F) & FBRD_BDIVFRAC);
171259319Sian	}
172239919Sgonzo
173239919Sgonzo	/* Add config. to line before reenabling UART */
174239919Sgonzo	__uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
175239919Sgonzo	    ~0xff) | line);
176239919Sgonzo
177239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
178239919Sgonzo}
179239919Sgonzo
180239919Sgonzostatic void
181242333Sgonzouart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
182242333Sgonzo    int parity)
183242333Sgonzo{
184242333Sgonzo	/* Mask all interrupts */
185242333Sgonzo	__uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
186242333Sgonzo	    ~IMSC_MASK_ALL);
187242333Sgonzo
188242333Sgonzo	uart_pl011_param(bas, baudrate, databits, stopbits, parity);
189242333Sgonzo}
190242333Sgonzo
191242333Sgonzostatic void
192239919Sgonzouart_pl011_term(struct uart_bas *bas)
193239919Sgonzo{
194239919Sgonzo}
195239919Sgonzo
196239919Sgonzostatic void
197239919Sgonzouart_pl011_putc(struct uart_bas *bas, int c)
198239919Sgonzo{
199239919Sgonzo
200283321Sian	/* Wait when TX FIFO full. Push character otherwise. */
201283321Sian	while (__uart_getreg(bas, UART_FR) & FR_TXFF)
202239919Sgonzo		;
203239919Sgonzo	__uart_setreg(bas, UART_DR, c & 0xff);
204239919Sgonzo}
205239919Sgonzo
206239919Sgonzostatic int
207239919Sgonzouart_pl011_rxready(struct uart_bas *bas)
208239919Sgonzo{
209239919Sgonzo
210239919Sgonzo	return (__uart_getreg(bas, UART_FR) & FR_RXFF);
211239919Sgonzo}
212239919Sgonzo
213239919Sgonzostatic int
214239919Sgonzouart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
215239919Sgonzo{
216239919Sgonzo	int c;
217239919Sgonzo
218239919Sgonzo	while (!uart_pl011_rxready(bas))
219239919Sgonzo		;
220239919Sgonzo	c = __uart_getreg(bas, UART_DR) & 0xff;
221239919Sgonzo
222239919Sgonzo	return (c);
223239919Sgonzo}
224239919Sgonzo
225239919Sgonzo/*
226239919Sgonzo * High-level UART interface.
227239919Sgonzo */
228239919Sgonzostruct uart_pl011_softc {
229239919Sgonzo	struct uart_softc base;
230239919Sgonzo	uint8_t		fcr;
231239919Sgonzo	uint8_t		ier;
232239919Sgonzo	uint8_t		mcr;
233239919Sgonzo
234239919Sgonzo	uint8_t		ier_mask;
235239919Sgonzo	uint8_t		ier_rxbits;
236239919Sgonzo};
237239919Sgonzo
238239919Sgonzostatic int uart_pl011_bus_attach(struct uart_softc *);
239239919Sgonzostatic int uart_pl011_bus_detach(struct uart_softc *);
240239919Sgonzostatic int uart_pl011_bus_flush(struct uart_softc *, int);
241239919Sgonzostatic int uart_pl011_bus_getsig(struct uart_softc *);
242239919Sgonzostatic int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
243239919Sgonzostatic int uart_pl011_bus_ipend(struct uart_softc *);
244239919Sgonzostatic int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
245239919Sgonzostatic int uart_pl011_bus_probe(struct uart_softc *);
246239919Sgonzostatic int uart_pl011_bus_receive(struct uart_softc *);
247239919Sgonzostatic int uart_pl011_bus_setsig(struct uart_softc *, int);
248239919Sgonzostatic int uart_pl011_bus_transmit(struct uart_softc *);
249262649Simpstatic void uart_pl011_bus_grab(struct uart_softc *);
250262649Simpstatic void uart_pl011_bus_ungrab(struct uart_softc *);
251239919Sgonzo
252239919Sgonzostatic kobj_method_t uart_pl011_methods[] = {
253239919Sgonzo	KOBJMETHOD(uart_attach,		uart_pl011_bus_attach),
254239919Sgonzo	KOBJMETHOD(uart_detach,		uart_pl011_bus_detach),
255239919Sgonzo	KOBJMETHOD(uart_flush,		uart_pl011_bus_flush),
256239919Sgonzo	KOBJMETHOD(uart_getsig,		uart_pl011_bus_getsig),
257239919Sgonzo	KOBJMETHOD(uart_ioctl,		uart_pl011_bus_ioctl),
258239919Sgonzo	KOBJMETHOD(uart_ipend,		uart_pl011_bus_ipend),
259239919Sgonzo	KOBJMETHOD(uart_param,		uart_pl011_bus_param),
260239919Sgonzo	KOBJMETHOD(uart_probe,		uart_pl011_bus_probe),
261239919Sgonzo	KOBJMETHOD(uart_receive,	uart_pl011_bus_receive),
262239919Sgonzo	KOBJMETHOD(uart_setsig,		uart_pl011_bus_setsig),
263239919Sgonzo	KOBJMETHOD(uart_transmit,	uart_pl011_bus_transmit),
264262649Simp	KOBJMETHOD(uart_grab,		uart_pl011_bus_grab),
265262649Simp	KOBJMETHOD(uart_ungrab,		uart_pl011_bus_ungrab),
266262649Simp
267239919Sgonzo	{ 0, 0 }
268239919Sgonzo};
269239919Sgonzo
270283327Sianstatic struct uart_class uart_pl011_class = {
271239919Sgonzo	"uart_pl011",
272239919Sgonzo	uart_pl011_methods,
273239919Sgonzo	sizeof(struct uart_pl011_softc),
274239919Sgonzo	.uc_ops = &uart_pl011_ops,
275239919Sgonzo	.uc_range = 0x48,
276239919Sgonzo	.uc_rclk = 0
277239919Sgonzo};
278239919Sgonzo
279283327Sianstatic struct ofw_compat_data compat_data[] = {
280283327Sian	{"arm,pl011",		(uintptr_t)&uart_pl011_class},
281283327Sian	{NULL,			(uintptr_t)NULL},
282283327Sian};
283283327SianUART_FDT_CLASS_AND_DEVICE(compat_data);
284283327Sian
285239919Sgonzostatic int
286239919Sgonzouart_pl011_bus_attach(struct uart_softc *sc)
287239919Sgonzo{
288239919Sgonzo	struct uart_bas *bas;
289283324Sian	int reg;
290239919Sgonzo
291239919Sgonzo	bas = &sc->sc_bas;
292283324Sian
293283324Sian	/* Enable interrupts */
294283324Sian	reg = (UART_RXREADY | RIS_RTIM | UART_TXEMPTY);
295283324Sian	__uart_setreg(bas, UART_IMSC, reg);
296283324Sian
297283324Sian	/* Clear interrupts */
298239919Sgonzo	__uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
299239919Sgonzo
300239919Sgonzo	return (0);
301239919Sgonzo}
302239919Sgonzo
303239919Sgonzostatic int
304239919Sgonzouart_pl011_bus_detach(struct uart_softc *sc)
305239919Sgonzo{
306239919Sgonzo
307239919Sgonzo	return (0);
308239919Sgonzo}
309239919Sgonzo
310239919Sgonzostatic int
311239919Sgonzouart_pl011_bus_flush(struct uart_softc *sc, int what)
312239919Sgonzo{
313239919Sgonzo
314239919Sgonzo	return (0);
315239919Sgonzo}
316239919Sgonzo
317239919Sgonzostatic int
318239919Sgonzouart_pl011_bus_getsig(struct uart_softc *sc)
319239919Sgonzo{
320239919Sgonzo
321239919Sgonzo	return (0);
322239919Sgonzo}
323239919Sgonzo
324239919Sgonzostatic int
325239919Sgonzouart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
326239919Sgonzo{
327239919Sgonzo	struct uart_bas *bas;
328239919Sgonzo	int error;
329239919Sgonzo
330239919Sgonzo	bas = &sc->sc_bas;
331239919Sgonzo	error = 0;
332239919Sgonzo	uart_lock(sc->sc_hwmtx);
333239919Sgonzo	switch (request) {
334239919Sgonzo	case UART_IOCTL_BREAK:
335239919Sgonzo		break;
336239919Sgonzo	case UART_IOCTL_BAUD:
337239919Sgonzo		*(int*)data = 115200;
338239919Sgonzo		break;
339239919Sgonzo	default:
340239919Sgonzo		error = EINVAL;
341239919Sgonzo		break;
342239919Sgonzo	}
343239919Sgonzo	uart_unlock(sc->sc_hwmtx);
344239919Sgonzo
345239919Sgonzo	return (error);
346239919Sgonzo}
347239919Sgonzo
348239919Sgonzostatic int
349239919Sgonzouart_pl011_bus_ipend(struct uart_softc *sc)
350239919Sgonzo{
351239919Sgonzo	struct uart_bas *bas;
352283324Sian	uint32_t ints;
353239919Sgonzo	int ipend;
354283324Sian	int reg;
355239919Sgonzo
356239919Sgonzo	bas = &sc->sc_bas;
357239919Sgonzo	uart_lock(sc->sc_hwmtx);
358239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
359239919Sgonzo	ipend = 0;
360239919Sgonzo
361283324Sian	if (ints & (UART_RXREADY | RIS_RTIM))
362239919Sgonzo		ipend |= SER_INT_RXREADY;
363239919Sgonzo	if (ints & RIS_BE)
364239919Sgonzo		ipend |= SER_INT_BREAK;
365239919Sgonzo	if (ints & RIS_OE)
366239919Sgonzo		ipend |= SER_INT_OVERRUN;
367239919Sgonzo	if (ints & UART_TXEMPTY) {
368239919Sgonzo		if (sc->sc_txbusy)
369239919Sgonzo			ipend |= SER_INT_TXIDLE;
370239919Sgonzo
371283324Sian		/* Disable TX interrupt */
372283324Sian		reg = __uart_getreg(bas, UART_IMSC);
373283324Sian		reg &= ~(UART_TXEMPTY);
374283324Sian		__uart_setreg(bas, UART_IMSC, reg);
375239919Sgonzo	}
376239919Sgonzo
377239919Sgonzo	uart_unlock(sc->sc_hwmtx);
378239919Sgonzo
379239919Sgonzo	return (ipend);
380239919Sgonzo}
381239919Sgonzo
382239919Sgonzostatic int
383239919Sgonzouart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
384239919Sgonzo    int stopbits, int parity)
385239919Sgonzo{
386239919Sgonzo
387239919Sgonzo	uart_lock(sc->sc_hwmtx);
388242333Sgonzo	uart_pl011_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
389239919Sgonzo	uart_unlock(sc->sc_hwmtx);
390239919Sgonzo
391239919Sgonzo	return (0);
392239919Sgonzo}
393239919Sgonzo
394239919Sgonzostatic int
395239919Sgonzouart_pl011_bus_probe(struct uart_softc *sc)
396239919Sgonzo{
397239919Sgonzo
398239919Sgonzo	device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
399239919Sgonzo
400248965Sian	sc->sc_rxfifosz = 1;
401248965Sian	sc->sc_txfifosz = 1;
402248965Sian
403239919Sgonzo	return (0);
404239919Sgonzo}
405239919Sgonzo
406239919Sgonzostatic int
407239919Sgonzouart_pl011_bus_receive(struct uart_softc *sc)
408239919Sgonzo{
409239919Sgonzo	struct uart_bas *bas;
410283324Sian	uint32_t ints, xc;
411239919Sgonzo	int rx;
412239919Sgonzo
413239919Sgonzo	bas = &sc->sc_bas;
414239919Sgonzo	uart_lock(sc->sc_hwmtx);
415239919Sgonzo
416239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
417283324Sian	while (ints & (UART_RXREADY | RIS_RTIM)) {
418239919Sgonzo		if (uart_rx_full(sc)) {
419239919Sgonzo			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
420239919Sgonzo			break;
421239919Sgonzo		}
422239919Sgonzo		xc = __uart_getreg(bas, UART_DR);
423239919Sgonzo		rx = xc & 0xff;
424239919Sgonzo
425239919Sgonzo		if (xc & DR_FE)
426239919Sgonzo			rx |= UART_STAT_FRAMERR;
427239919Sgonzo		if (xc & DR_PE)
428239919Sgonzo			rx |= UART_STAT_PARERR;
429239919Sgonzo
430283324Sian		__uart_setreg(bas, UART_ICR, (UART_RXREADY | RIS_RTIM));
431239919Sgonzo
432239919Sgonzo		uart_rx_put(sc, rx);
433239919Sgonzo		ints = __uart_getreg(bas, UART_MIS);
434239919Sgonzo	}
435239919Sgonzo
436239919Sgonzo	uart_unlock(sc->sc_hwmtx);
437239919Sgonzo
438239919Sgonzo	return (0);
439239919Sgonzo}
440239919Sgonzo
441239919Sgonzostatic int
442239919Sgonzouart_pl011_bus_setsig(struct uart_softc *sc, int sig)
443239919Sgonzo{
444239919Sgonzo
445239919Sgonzo	return (0);
446239919Sgonzo}
447239919Sgonzo
448239919Sgonzostatic int
449239919Sgonzouart_pl011_bus_transmit(struct uart_softc *sc)
450239919Sgonzo{
451239919Sgonzo	struct uart_bas *bas;
452283324Sian	int reg;
453239919Sgonzo	int i;
454239919Sgonzo
455239919Sgonzo	bas = &sc->sc_bas;
456239919Sgonzo	uart_lock(sc->sc_hwmtx);
457239919Sgonzo
458239919Sgonzo	for (i = 0; i < sc->sc_txdatasz; i++) {
459239919Sgonzo		__uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
460239919Sgonzo		uart_barrier(bas);
461239919Sgonzo	}
462239919Sgonzo	sc->sc_txbusy = 1;
463283324Sian
464283324Sian	/* Enable TX interrupt */
465283324Sian	reg = __uart_getreg(bas, UART_IMSC);
466283324Sian	reg |= (UART_TXEMPTY);
467283324Sian	__uart_setreg(bas, UART_IMSC, reg);
468283324Sian
469239919Sgonzo	uart_unlock(sc->sc_hwmtx);
470239919Sgonzo
471239919Sgonzo	return (0);
472239919Sgonzo}
473262649Simp
474262649Simpstatic void
475262649Simpuart_pl011_bus_grab(struct uart_softc *sc)
476262649Simp{
477262649Simp	struct uart_bas *bas;
478262649Simp
479262649Simp	bas = &sc->sc_bas;
480262649Simp	uart_lock(sc->sc_hwmtx);
481262649Simp	__uart_setreg(bas, UART_IMSC, 	/* Switch to RX polling while grabbed */
482262649Simp	    ~UART_RXREADY & __uart_getreg(bas, UART_IMSC));
483262649Simp	uart_unlock(sc->sc_hwmtx);
484262649Simp}
485262649Simp
486262649Simpstatic void
487262649Simpuart_pl011_bus_ungrab(struct uart_softc *sc)
488262649Simp{
489262649Simp	struct uart_bas *bas;
490262649Simp
491262649Simp	bas = &sc->sc_bas;
492262649Simp	uart_lock(sc->sc_hwmtx);
493262649Simp	__uart_setreg(bas, UART_IMSC,	/* Switch to RX interrupts while not grabbed */
494262649Simp	    UART_RXREADY | __uart_getreg(bas, UART_IMSC));
495262649Simp	uart_unlock(sc->sc_hwmtx);
496262649Simp}
497