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
uart_reset(struct uart_pl011_softc * sc)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
uart_rx_trigger_level(struct uart_pl011_softc * sc)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
uart_toggle_intr(struct uart_pl011_softc * sc)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
uart_drain(int fd __unused,enum ev_type ev,void * arg)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
uart_pl011_write(struct uart_pl011_softc * sc,int offset,uint32_t value)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
uart_pl011_read(struct uart_pl011_softc * sc,int offset)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 *
uart_pl011_init(uart_intr_func_t intr_assert,uart_intr_func_t intr_deassert,void * arg)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
uart_pl011_tty_open(struct uart_pl011_softc * sc,const char * device)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