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