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