xref: /freebsd/usr.sbin/bhyve/uart_pl011.c (revision f3003a0dfb91ce887587ff73ce758f31a921e5a3)
1*f3003a0dSAndrew Turner /*-
2*f3003a0dSAndrew Turner  * SPDX-License-Identifier: BSD-2-Clause
3*f3003a0dSAndrew Turner  *
4*f3003a0dSAndrew Turner  * Copyright (c) 2020 Andrew Turner
5*f3003a0dSAndrew Turner  *
6*f3003a0dSAndrew Turner  * This work was supported by Innovate UK project 105694, "Digital Security
7*f3003a0dSAndrew Turner  * by Design (DSbD) Technology Platform Prototype".
8*f3003a0dSAndrew Turner  *
9*f3003a0dSAndrew Turner  * Redistribution and use in source and binary forms, with or without
10*f3003a0dSAndrew Turner  * modification, are permitted provided that the following conditions
11*f3003a0dSAndrew Turner  * are met:
12*f3003a0dSAndrew Turner  * 1. Redistributions of source code must retain the above copyright
13*f3003a0dSAndrew Turner  *    notice, this list of conditions and the following disclaimer.
14*f3003a0dSAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
15*f3003a0dSAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
16*f3003a0dSAndrew Turner  *    documentation and/or other materials provided with the distribution.
17*f3003a0dSAndrew Turner  *
18*f3003a0dSAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*f3003a0dSAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*f3003a0dSAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*f3003a0dSAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*f3003a0dSAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*f3003a0dSAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*f3003a0dSAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*f3003a0dSAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*f3003a0dSAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*f3003a0dSAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*f3003a0dSAndrew Turner  * SUCH DAMAGE.
29*f3003a0dSAndrew Turner  */
30*f3003a0dSAndrew Turner 
31*f3003a0dSAndrew Turner #include <sys/param.h>
32*f3003a0dSAndrew Turner 
33*f3003a0dSAndrew Turner #include <assert.h>
34*f3003a0dSAndrew Turner #include <pthread.h>
35*f3003a0dSAndrew Turner #include <stdbool.h>
36*f3003a0dSAndrew Turner #include <stdio.h>
37*f3003a0dSAndrew Turner #include <stdlib.h>
38*f3003a0dSAndrew Turner 
39*f3003a0dSAndrew Turner #include "uart_backend.h"
40*f3003a0dSAndrew Turner #include "uart_emul.h"
41*f3003a0dSAndrew Turner 
42*f3003a0dSAndrew Turner #define	UART_FIFO_SIZE		16
43*f3003a0dSAndrew Turner 
44*f3003a0dSAndrew Turner #define	UARTDR			0x00
45*f3003a0dSAndrew Turner #define	UARTDR_RSR_SHIFT	8
46*f3003a0dSAndrew Turner 
47*f3003a0dSAndrew Turner #define	UARTRSR			0x01
48*f3003a0dSAndrew Turner #define	UARTRSR_OE		(1 << 3)
49*f3003a0dSAndrew Turner 
50*f3003a0dSAndrew Turner #define	UARTFR			0x06
51*f3003a0dSAndrew Turner #define	UARTFR_TXFE		(1 << 7)
52*f3003a0dSAndrew Turner #define	UARTFR_RXFF		(1 << 6)
53*f3003a0dSAndrew Turner #define	UARTFR_TXFF		(1 << 5)
54*f3003a0dSAndrew Turner #define	UARTFR_RXFE		(1 << 4)
55*f3003a0dSAndrew Turner 
56*f3003a0dSAndrew Turner #define	UARTRTINTR		(1 << 6)
57*f3003a0dSAndrew Turner #define	UARTTXINTR		(1 << 5)
58*f3003a0dSAndrew Turner #define	UARTRXINTR		(1 << 4)
59*f3003a0dSAndrew Turner 
60*f3003a0dSAndrew Turner #define	UARTIBRD		0x09
61*f3003a0dSAndrew Turner 
62*f3003a0dSAndrew Turner #define	UARTFBRD		0x0a
63*f3003a0dSAndrew Turner #define	UARTFBRD_MASK		0x003f
64*f3003a0dSAndrew Turner 
65*f3003a0dSAndrew Turner #define	UARTLCR_H		0x0b
66*f3003a0dSAndrew Turner #define	UARTLCR_H_MASK		0x00ff
67*f3003a0dSAndrew Turner #define	UARTLCR_H_FEN		(1 << 4)
68*f3003a0dSAndrew Turner 
69*f3003a0dSAndrew Turner #define	UARTCR			0x0c
70*f3003a0dSAndrew Turner /* TODO: Check the flags in the UARTCR register */
71*f3003a0dSAndrew Turner #define	UARTCR_MASK		0xffc7
72*f3003a0dSAndrew Turner #define	UARTCR_LBE		(1 << 7)
73*f3003a0dSAndrew Turner 
74*f3003a0dSAndrew Turner #define	UARTIFLS		0x0d
75*f3003a0dSAndrew Turner #define	UARTIFLS_MASK		0x003f
76*f3003a0dSAndrew Turner #define	UARTIFLS_RXIFLSEL(x)	(((x) >> 3) & 0x7)
77*f3003a0dSAndrew Turner #define	UARTIFLS_TXIFLSEL(x)	(((x) >> 0) & 0x7)
78*f3003a0dSAndrew Turner 
79*f3003a0dSAndrew Turner #define	UARTIMSC		0x0e
80*f3003a0dSAndrew Turner #define	UARTIMSC_MASK		0x07ff
81*f3003a0dSAndrew Turner 
82*f3003a0dSAndrew Turner #define	UARTRIS			0x0f
83*f3003a0dSAndrew Turner #define	UARTMIS			0x10
84*f3003a0dSAndrew Turner 
85*f3003a0dSAndrew Turner #define	UARTICR			0x11
86*f3003a0dSAndrew Turner 
87*f3003a0dSAndrew Turner #define	UARTPeriphID		0x00241011
88*f3003a0dSAndrew Turner #define	UARTPeriphID0		0x3f8
89*f3003a0dSAndrew Turner #define	UARTPeriphID0_VAL	(((UARTPeriphID) >>  0) & 0xff)
90*f3003a0dSAndrew Turner #define	UARTPeriphID1		0x3f9
91*f3003a0dSAndrew Turner #define	UARTPeriphID1_VAL	(((UARTPeriphID) >>  8) & 0xff)
92*f3003a0dSAndrew Turner #define	UARTPeriphID2		0x3fa
93*f3003a0dSAndrew Turner #define	UARTPeriphID2_VAL	(((UARTPeriphID) >> 16) & 0xff)
94*f3003a0dSAndrew Turner #define	UARTPeriphID3		0x3fb
95*f3003a0dSAndrew Turner #define	UARTPeriphID3_VAL	(((UARTPeriphID) >> 24) & 0xff)
96*f3003a0dSAndrew Turner 
97*f3003a0dSAndrew Turner #define	UARTPCellID		0xb105f00d
98*f3003a0dSAndrew Turner #define	UARTPCellID0		0x3fc
99*f3003a0dSAndrew Turner #define	UARTPCellID0_VAL	(((UARTPCellID) >>  0) & 0xff)
100*f3003a0dSAndrew Turner #define	UARTPCellID1		0x3fd
101*f3003a0dSAndrew Turner #define	UARTPCellID1_VAL	(((UARTPCellID) >>  8) & 0xff)
102*f3003a0dSAndrew Turner #define	UARTPCellID2		0x3fe
103*f3003a0dSAndrew Turner #define	UARTPCellID2_VAL	(((UARTPCellID) >> 16) & 0xff)
104*f3003a0dSAndrew Turner #define	UARTPCellID3		0x3ff
105*f3003a0dSAndrew Turner #define	UARTPCellID3_VAL	(((UARTPCellID) >> 24) & 0xff)
106*f3003a0dSAndrew Turner 
107*f3003a0dSAndrew Turner struct uart_pl011_softc {
108*f3003a0dSAndrew Turner 	struct uart_softc *backend;
109*f3003a0dSAndrew Turner 	pthread_mutex_t mtx;	/* protects all softc elements */
110*f3003a0dSAndrew Turner 
111*f3003a0dSAndrew Turner 	uint16_t	irq_state;
112*f3003a0dSAndrew Turner 
113*f3003a0dSAndrew Turner 	uint16_t	rsr;
114*f3003a0dSAndrew Turner 
115*f3003a0dSAndrew Turner 	uint16_t	cr;
116*f3003a0dSAndrew Turner 	uint16_t	ifls;
117*f3003a0dSAndrew Turner 	uint16_t	imsc;
118*f3003a0dSAndrew Turner 	uint16_t	lcr_h;
119*f3003a0dSAndrew Turner 
120*f3003a0dSAndrew Turner 	uint16_t	ibrd;
121*f3003a0dSAndrew Turner 	uint16_t	fbrd;
122*f3003a0dSAndrew Turner 
123*f3003a0dSAndrew Turner 	void	*arg;
124*f3003a0dSAndrew Turner 	uart_intr_func_t intr_assert;
125*f3003a0dSAndrew Turner 	uart_intr_func_t intr_deassert;
126*f3003a0dSAndrew Turner };
127*f3003a0dSAndrew Turner 
128*f3003a0dSAndrew Turner static void
129*f3003a0dSAndrew Turner uart_reset(struct uart_pl011_softc *sc)
130*f3003a0dSAndrew Turner {
131*f3003a0dSAndrew Turner 	sc->ifls = 0x12;
132*f3003a0dSAndrew Turner 
133*f3003a0dSAndrew Turner 	/* no fifo until enabled by software */
134*f3003a0dSAndrew Turner 	uart_rxfifo_reset(sc->backend, 1);
135*f3003a0dSAndrew Turner }
136*f3003a0dSAndrew Turner 
137*f3003a0dSAndrew Turner static int
138*f3003a0dSAndrew Turner uart_rx_trigger_level(struct uart_pl011_softc *sc)
139*f3003a0dSAndrew Turner {
140*f3003a0dSAndrew Turner 	/* If the FIFO is disabled trigger when we have any data */
141*f3003a0dSAndrew Turner 	if ((sc->lcr_h & UARTLCR_H_FEN) != 0)
142*f3003a0dSAndrew Turner 		return (1);
143*f3003a0dSAndrew Turner 
144*f3003a0dSAndrew Turner 	/* Trigger base on how full the fifo is */
145*f3003a0dSAndrew Turner 	switch (UARTIFLS_RXIFLSEL(sc->ifls)) {
146*f3003a0dSAndrew Turner 	case 0:
147*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE / 8);
148*f3003a0dSAndrew Turner 	case 1:
149*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE / 4);
150*f3003a0dSAndrew Turner 	case 2:
151*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE / 2);
152*f3003a0dSAndrew Turner 	case 3:
153*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE * 3 / 4);
154*f3003a0dSAndrew Turner 	case 4:
155*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE * 7 / 8);
156*f3003a0dSAndrew Turner 	default:
157*f3003a0dSAndrew Turner 		/* TODO: Find out what happens in this case */
158*f3003a0dSAndrew Turner 		return (UART_FIFO_SIZE);
159*f3003a0dSAndrew Turner 	}
160*f3003a0dSAndrew Turner }
161*f3003a0dSAndrew Turner 
162*f3003a0dSAndrew Turner static void
163*f3003a0dSAndrew Turner uart_toggle_intr(struct uart_pl011_softc *sc)
164*f3003a0dSAndrew Turner {
165*f3003a0dSAndrew Turner 	if ((sc->irq_state & sc->imsc) == 0)
166*f3003a0dSAndrew Turner 		(*sc->intr_deassert)(sc->arg);
167*f3003a0dSAndrew Turner 	else
168*f3003a0dSAndrew Turner 		(*sc->intr_assert)(sc->arg);
169*f3003a0dSAndrew Turner }
170*f3003a0dSAndrew Turner 
171*f3003a0dSAndrew Turner static void
172*f3003a0dSAndrew Turner uart_drain(int fd __unused, enum ev_type ev, void *arg)
173*f3003a0dSAndrew Turner {
174*f3003a0dSAndrew Turner 	struct uart_pl011_softc *sc;
175*f3003a0dSAndrew Turner 	int old_size, trig_lvl;
176*f3003a0dSAndrew Turner 	bool loopback;
177*f3003a0dSAndrew Turner 
178*f3003a0dSAndrew Turner 	sc = arg;
179*f3003a0dSAndrew Turner 
180*f3003a0dSAndrew Turner 	assert(ev == EVF_READ);
181*f3003a0dSAndrew Turner 
182*f3003a0dSAndrew Turner 	/*
183*f3003a0dSAndrew Turner 	 * This routine is called in the context of the mevent thread
184*f3003a0dSAndrew Turner 	 * to take out the softc lock to protect against concurrent
185*f3003a0dSAndrew Turner 	 * access from a vCPU i/o exit
186*f3003a0dSAndrew Turner 	 */
187*f3003a0dSAndrew Turner 	pthread_mutex_lock(&sc->mtx);
188*f3003a0dSAndrew Turner 
189*f3003a0dSAndrew Turner 	old_size = uart_rxfifo_numchars(sc->backend);
190*f3003a0dSAndrew Turner 
191*f3003a0dSAndrew Turner 	loopback = (sc->cr & UARTCR_LBE) != 0;
192*f3003a0dSAndrew Turner 	uart_rxfifo_drain(sc->backend, loopback);
193*f3003a0dSAndrew Turner 
194*f3003a0dSAndrew Turner 	/* If we cross the trigger level raise UARTRXINTR */
195*f3003a0dSAndrew Turner 	trig_lvl = uart_rx_trigger_level(sc);
196*f3003a0dSAndrew Turner 	if (old_size < trig_lvl &&
197*f3003a0dSAndrew Turner 	    uart_rxfifo_numchars(sc->backend) >= trig_lvl)
198*f3003a0dSAndrew Turner 		sc->irq_state |= UARTRXINTR;
199*f3003a0dSAndrew Turner 
200*f3003a0dSAndrew Turner 	if (uart_rxfifo_numchars(sc->backend) > 0)
201*f3003a0dSAndrew Turner 		sc->irq_state |= UARTRTINTR;
202*f3003a0dSAndrew Turner 	if (!loopback)
203*f3003a0dSAndrew Turner 		uart_toggle_intr(sc);
204*f3003a0dSAndrew Turner 
205*f3003a0dSAndrew Turner 	pthread_mutex_unlock(&sc->mtx);
206*f3003a0dSAndrew Turner }
207*f3003a0dSAndrew Turner 
208*f3003a0dSAndrew Turner void
209*f3003a0dSAndrew Turner uart_pl011_write(struct uart_pl011_softc *sc, int offset, uint32_t value)
210*f3003a0dSAndrew Turner {
211*f3003a0dSAndrew Turner 	bool loopback;
212*f3003a0dSAndrew Turner 
213*f3003a0dSAndrew Turner 	pthread_mutex_lock(&sc->mtx);
214*f3003a0dSAndrew Turner 	switch (offset) {
215*f3003a0dSAndrew Turner 	case UARTDR:
216*f3003a0dSAndrew Turner 		loopback = (sc->cr & UARTCR_LBE) != 0;
217*f3003a0dSAndrew Turner 		if (uart_rxfifo_putchar(sc->backend, value & 0xff, loopback))
218*f3003a0dSAndrew Turner 			sc->rsr |= UARTRSR_OE;
219*f3003a0dSAndrew Turner 
220*f3003a0dSAndrew Turner 		/* We don't have a TX fifo, so trigger when we have data */
221*f3003a0dSAndrew Turner 		sc->irq_state |= UARTTXINTR;
222*f3003a0dSAndrew Turner 		break;
223*f3003a0dSAndrew Turner 	case UARTRSR:
224*f3003a0dSAndrew Turner 		/* Any write clears this register */
225*f3003a0dSAndrew Turner 		sc->rsr = 0;
226*f3003a0dSAndrew Turner 		break;
227*f3003a0dSAndrew Turner 	case UARTFR:
228*f3003a0dSAndrew Turner 		/* UARTFR is a read-only register */
229*f3003a0dSAndrew Turner 		break;
230*f3003a0dSAndrew Turner 	/* TODO: UARTILPR */
231*f3003a0dSAndrew Turner 	case UARTIBRD:
232*f3003a0dSAndrew Turner 		sc->ibrd = value;
233*f3003a0dSAndrew Turner 		break;
234*f3003a0dSAndrew Turner 	case UARTFBRD:
235*f3003a0dSAndrew Turner 		sc->fbrd = value & UARTFBRD_MASK;
236*f3003a0dSAndrew Turner 		break;
237*f3003a0dSAndrew Turner 	case UARTLCR_H:
238*f3003a0dSAndrew Turner 		/* Check if the FIFO enable bit changed */
239*f3003a0dSAndrew Turner 		if (((sc->lcr_h ^ value) & UARTLCR_H_FEN) != 0) {
240*f3003a0dSAndrew Turner 			if ((value & UARTLCR_H_FEN) != 0) {
241*f3003a0dSAndrew Turner 				uart_rxfifo_reset(sc->backend, UART_FIFO_SIZE);
242*f3003a0dSAndrew Turner 			} else {
243*f3003a0dSAndrew Turner 				uart_rxfifo_reset(sc->backend, 1);
244*f3003a0dSAndrew Turner 			}
245*f3003a0dSAndrew Turner 		}
246*f3003a0dSAndrew Turner 		sc->lcr_h = value & UARTLCR_H_MASK;
247*f3003a0dSAndrew Turner 		break;
248*f3003a0dSAndrew Turner 	case UARTCR:
249*f3003a0dSAndrew Turner 		sc->cr = value & UARTCR_MASK;
250*f3003a0dSAndrew Turner 		break;
251*f3003a0dSAndrew Turner 	case UARTIFLS:
252*f3003a0dSAndrew Turner 		sc->ifls = value & UARTCR_MASK;
253*f3003a0dSAndrew Turner 		break;
254*f3003a0dSAndrew Turner 	case UARTIMSC:
255*f3003a0dSAndrew Turner 		sc->imsc = value & UARTIMSC_MASK;
256*f3003a0dSAndrew Turner 		break;
257*f3003a0dSAndrew Turner 	case UARTRIS:
258*f3003a0dSAndrew Turner 	case UARTMIS:
259*f3003a0dSAndrew Turner 		/* UARTRIS and UARTMIS are read-only registers */
260*f3003a0dSAndrew Turner 		break;
261*f3003a0dSAndrew Turner 	case UARTICR:
262*f3003a0dSAndrew Turner 		sc->irq_state &= ~value;
263*f3003a0dSAndrew Turner 		break;
264*f3003a0dSAndrew Turner 	default:
265*f3003a0dSAndrew Turner 		/* Ignore writes to unassigned/ID registers */
266*f3003a0dSAndrew Turner 		break;
267*f3003a0dSAndrew Turner 	}
268*f3003a0dSAndrew Turner 	uart_toggle_intr(sc);
269*f3003a0dSAndrew Turner 	pthread_mutex_unlock(&sc->mtx);
270*f3003a0dSAndrew Turner }
271*f3003a0dSAndrew Turner 
272*f3003a0dSAndrew Turner uint32_t
273*f3003a0dSAndrew Turner uart_pl011_read(struct uart_pl011_softc *sc, int offset)
274*f3003a0dSAndrew Turner {
275*f3003a0dSAndrew Turner 	uint32_t reg;
276*f3003a0dSAndrew Turner 	int fifo_sz;
277*f3003a0dSAndrew Turner 
278*f3003a0dSAndrew Turner 	reg = 0;
279*f3003a0dSAndrew Turner 	pthread_mutex_lock(&sc->mtx);
280*f3003a0dSAndrew Turner 	switch (offset) {
281*f3003a0dSAndrew Turner 	case UARTDR:
282*f3003a0dSAndrew Turner 		reg = uart_rxfifo_getchar(sc->backend);
283*f3003a0dSAndrew Turner 		/* Deassert the irq if below the trigger level */
284*f3003a0dSAndrew Turner 		fifo_sz = uart_rxfifo_numchars(sc->backend);
285*f3003a0dSAndrew Turner 		if (fifo_sz < uart_rx_trigger_level(sc))
286*f3003a0dSAndrew Turner 			sc->irq_state &= ~UARTRXINTR;
287*f3003a0dSAndrew Turner 		if (fifo_sz == 0)
288*f3003a0dSAndrew Turner 			sc->irq_state &= ~UARTRTINTR;
289*f3003a0dSAndrew Turner 
290*f3003a0dSAndrew Turner 		reg |= sc->rsr << UARTDR_RSR_SHIFT;
291*f3003a0dSAndrew Turner 
292*f3003a0dSAndrew Turner 		/* After reading from the fifo there is now space in it */
293*f3003a0dSAndrew Turner 		sc->rsr &= UARTRSR_OE;
294*f3003a0dSAndrew Turner 		break;
295*f3003a0dSAndrew Turner 	case UARTRSR:
296*f3003a0dSAndrew Turner 		/* Any write clears this register */
297*f3003a0dSAndrew Turner 		reg = sc->rsr;
298*f3003a0dSAndrew Turner 		break;
299*f3003a0dSAndrew Turner 	case UARTFR:
300*f3003a0dSAndrew Turner 		/* Transmit is intstant, so the fifo is always empty */
301*f3003a0dSAndrew Turner 		reg = UARTFR_TXFE;
302*f3003a0dSAndrew Turner 
303*f3003a0dSAndrew Turner 		/* Set the receive fifo full/empty flags */
304*f3003a0dSAndrew Turner 		fifo_sz = uart_rxfifo_numchars(sc->backend);
305*f3003a0dSAndrew Turner 		if (fifo_sz == UART_FIFO_SIZE)
306*f3003a0dSAndrew Turner 			reg |= UARTFR_RXFF;
307*f3003a0dSAndrew Turner 		else if (fifo_sz == 0)
308*f3003a0dSAndrew Turner 			reg |= UARTFR_RXFE;
309*f3003a0dSAndrew Turner 		break;
310*f3003a0dSAndrew Turner 	/* TODO: UARTILPR */
311*f3003a0dSAndrew Turner 	case UARTIBRD:
312*f3003a0dSAndrew Turner 		reg = sc->ibrd;
313*f3003a0dSAndrew Turner 		break;
314*f3003a0dSAndrew Turner 	case UARTFBRD:
315*f3003a0dSAndrew Turner 		reg = sc->fbrd;
316*f3003a0dSAndrew Turner 		break;
317*f3003a0dSAndrew Turner 	case UARTLCR_H:
318*f3003a0dSAndrew Turner 		reg = sc->lcr_h;
319*f3003a0dSAndrew Turner 		break;
320*f3003a0dSAndrew Turner 	case UARTCR:
321*f3003a0dSAndrew Turner 		reg = sc->cr;
322*f3003a0dSAndrew Turner 		break;
323*f3003a0dSAndrew Turner 	case UARTIMSC:
324*f3003a0dSAndrew Turner 		reg = sc->imsc;
325*f3003a0dSAndrew Turner 		break;
326*f3003a0dSAndrew Turner 	case UARTRIS:
327*f3003a0dSAndrew Turner 		reg = sc->irq_state;
328*f3003a0dSAndrew Turner 		break;
329*f3003a0dSAndrew Turner 	case UARTMIS:
330*f3003a0dSAndrew Turner 		reg = sc->irq_state & sc->imsc;
331*f3003a0dSAndrew Turner 		break;
332*f3003a0dSAndrew Turner 	case UARTICR:
333*f3003a0dSAndrew Turner 		reg = 0;
334*f3003a0dSAndrew Turner 		break;
335*f3003a0dSAndrew Turner 	case UARTPeriphID0:
336*f3003a0dSAndrew Turner 		reg = UARTPeriphID0_VAL;
337*f3003a0dSAndrew Turner 		break;
338*f3003a0dSAndrew Turner 	case UARTPeriphID1:
339*f3003a0dSAndrew Turner 		reg =UARTPeriphID1_VAL;
340*f3003a0dSAndrew Turner 		break;
341*f3003a0dSAndrew Turner 	case UARTPeriphID2:
342*f3003a0dSAndrew Turner 		reg = UARTPeriphID2_VAL;
343*f3003a0dSAndrew Turner 		break;
344*f3003a0dSAndrew Turner 	case UARTPeriphID3:
345*f3003a0dSAndrew Turner 		reg = UARTPeriphID3_VAL;
346*f3003a0dSAndrew Turner 		break;
347*f3003a0dSAndrew Turner 	case UARTPCellID0:
348*f3003a0dSAndrew Turner 		reg = UARTPCellID0_VAL;
349*f3003a0dSAndrew Turner 		break;
350*f3003a0dSAndrew Turner 	case UARTPCellID1:
351*f3003a0dSAndrew Turner 		reg = UARTPCellID1_VAL;
352*f3003a0dSAndrew Turner 		break;
353*f3003a0dSAndrew Turner 	case UARTPCellID2:
354*f3003a0dSAndrew Turner 		reg = UARTPCellID2_VAL;
355*f3003a0dSAndrew Turner 		break;
356*f3003a0dSAndrew Turner 	case UARTPCellID3:
357*f3003a0dSAndrew Turner 		reg = UARTPCellID3_VAL;
358*f3003a0dSAndrew Turner 		break;
359*f3003a0dSAndrew Turner 	default:
360*f3003a0dSAndrew Turner 		/* Return 0 in reads from unasigned registers */
361*f3003a0dSAndrew Turner 		reg = 0;
362*f3003a0dSAndrew Turner 		break;
363*f3003a0dSAndrew Turner 	}
364*f3003a0dSAndrew Turner 	uart_toggle_intr(sc);
365*f3003a0dSAndrew Turner 	pthread_mutex_unlock(&sc->mtx);
366*f3003a0dSAndrew Turner 
367*f3003a0dSAndrew Turner 	return (reg);
368*f3003a0dSAndrew Turner }
369*f3003a0dSAndrew Turner 
370*f3003a0dSAndrew Turner struct uart_pl011_softc *
371*f3003a0dSAndrew Turner uart_pl011_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
372*f3003a0dSAndrew Turner     void *arg)
373*f3003a0dSAndrew Turner {
374*f3003a0dSAndrew Turner 	struct uart_pl011_softc *sc;
375*f3003a0dSAndrew Turner 
376*f3003a0dSAndrew Turner 	sc = calloc(1, sizeof(struct uart_pl011_softc));
377*f3003a0dSAndrew Turner 
378*f3003a0dSAndrew Turner 	sc->arg = arg;
379*f3003a0dSAndrew Turner 	sc->intr_assert = intr_assert;
380*f3003a0dSAndrew Turner 	sc->intr_deassert = intr_deassert;
381*f3003a0dSAndrew Turner 	sc->backend = uart_init();
382*f3003a0dSAndrew Turner 
383*f3003a0dSAndrew Turner 	pthread_mutex_init(&sc->mtx, NULL);
384*f3003a0dSAndrew Turner 
385*f3003a0dSAndrew Turner 	uart_reset(sc);
386*f3003a0dSAndrew Turner 
387*f3003a0dSAndrew Turner 	return (sc);
388*f3003a0dSAndrew Turner }
389*f3003a0dSAndrew Turner 
390*f3003a0dSAndrew Turner int
391*f3003a0dSAndrew Turner uart_pl011_tty_open(struct uart_pl011_softc *sc, const char *device)
392*f3003a0dSAndrew Turner {
393*f3003a0dSAndrew Turner 	return (uart_tty_open(sc->backend, device, uart_drain, sc));
394*f3003a0dSAndrew Turner }
395