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