xref: /qemu/hw/char/ibex_uart.c (revision a7d2d98c5944cec9ac8ed12215c2ea9d4545779b)
1*a7d2d98cSAlistair Francis /*
2*a7d2d98cSAlistair Francis  * QEMU lowRISC Ibex UART device
3*a7d2d98cSAlistair Francis  *
4*a7d2d98cSAlistair Francis  * Copyright (c) 2020 Western Digital
5*a7d2d98cSAlistair Francis  *
6*a7d2d98cSAlistair Francis  * For details check the documentation here:
7*a7d2d98cSAlistair Francis  *    https://docs.opentitan.org/hw/ip/uart/doc/
8*a7d2d98cSAlistair Francis  *
9*a7d2d98cSAlistair Francis  * Permission is hereby granted, free of charge, to any person obtaining a copy
10*a7d2d98cSAlistair Francis  * of this software and associated documentation files (the "Software"), to deal
11*a7d2d98cSAlistair Francis  * in the Software without restriction, including without limitation the rights
12*a7d2d98cSAlistair Francis  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13*a7d2d98cSAlistair Francis  * copies of the Software, and to permit persons to whom the Software is
14*a7d2d98cSAlistair Francis  * furnished to do so, subject to the following conditions:
15*a7d2d98cSAlistair Francis  *
16*a7d2d98cSAlistair Francis  * The above copyright notice and this permission notice shall be included in
17*a7d2d98cSAlistair Francis  * all copies or substantial portions of the Software.
18*a7d2d98cSAlistair Francis  *
19*a7d2d98cSAlistair Francis  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*a7d2d98cSAlistair Francis  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*a7d2d98cSAlistair Francis  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22*a7d2d98cSAlistair Francis  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23*a7d2d98cSAlistair Francis  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24*a7d2d98cSAlistair Francis  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25*a7d2d98cSAlistair Francis  * THE SOFTWARE.
26*a7d2d98cSAlistair Francis  */
27*a7d2d98cSAlistair Francis 
28*a7d2d98cSAlistair Francis #include "qemu/osdep.h"
29*a7d2d98cSAlistair Francis #include "hw/char/ibex_uart.h"
30*a7d2d98cSAlistair Francis #include "hw/irq.h"
31*a7d2d98cSAlistair Francis #include "hw/qdev-properties.h"
32*a7d2d98cSAlistair Francis #include "migration/vmstate.h"
33*a7d2d98cSAlistair Francis #include "qemu/log.h"
34*a7d2d98cSAlistair Francis #include "qemu/module.h"
35*a7d2d98cSAlistair Francis 
36*a7d2d98cSAlistair Francis static void ibex_uart_update_irqs(IbexUartState *s)
37*a7d2d98cSAlistair Francis {
38*a7d2d98cSAlistair Francis     if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
39*a7d2d98cSAlistair Francis         qemu_set_irq(s->tx_watermark, 1);
40*a7d2d98cSAlistair Francis     } else {
41*a7d2d98cSAlistair Francis         qemu_set_irq(s->tx_watermark, 0);
42*a7d2d98cSAlistair Francis     }
43*a7d2d98cSAlistair Francis 
44*a7d2d98cSAlistair Francis     if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
45*a7d2d98cSAlistair Francis         qemu_set_irq(s->rx_watermark, 1);
46*a7d2d98cSAlistair Francis     } else {
47*a7d2d98cSAlistair Francis         qemu_set_irq(s->rx_watermark, 0);
48*a7d2d98cSAlistair Francis     }
49*a7d2d98cSAlistair Francis 
50*a7d2d98cSAlistair Francis     if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
51*a7d2d98cSAlistair Francis         qemu_set_irq(s->tx_empty, 1);
52*a7d2d98cSAlistair Francis     } else {
53*a7d2d98cSAlistair Francis         qemu_set_irq(s->tx_empty, 0);
54*a7d2d98cSAlistair Francis     }
55*a7d2d98cSAlistair Francis 
56*a7d2d98cSAlistair Francis     if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
57*a7d2d98cSAlistair Francis         qemu_set_irq(s->rx_overflow, 1);
58*a7d2d98cSAlistair Francis     } else {
59*a7d2d98cSAlistair Francis         qemu_set_irq(s->rx_overflow, 0);
60*a7d2d98cSAlistair Francis     }
61*a7d2d98cSAlistair Francis }
62*a7d2d98cSAlistair Francis 
63*a7d2d98cSAlistair Francis static int ibex_uart_can_receive(void *opaque)
64*a7d2d98cSAlistair Francis {
65*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
66*a7d2d98cSAlistair Francis 
67*a7d2d98cSAlistair Francis     if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
68*a7d2d98cSAlistair Francis         return 1;
69*a7d2d98cSAlistair Francis     }
70*a7d2d98cSAlistair Francis 
71*a7d2d98cSAlistair Francis     return 0;
72*a7d2d98cSAlistair Francis }
73*a7d2d98cSAlistair Francis 
74*a7d2d98cSAlistair Francis static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
75*a7d2d98cSAlistair Francis {
76*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
77*a7d2d98cSAlistair Francis     uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
78*a7d2d98cSAlistair Francis                             >> FIFO_CTRL_RXILVL_SHIFT;
79*a7d2d98cSAlistair Francis 
80*a7d2d98cSAlistair Francis     s->uart_rdata = *buf;
81*a7d2d98cSAlistair Francis 
82*a7d2d98cSAlistair Francis     s->uart_status &= ~UART_STATUS_RXIDLE;
83*a7d2d98cSAlistair Francis     s->uart_status &= ~UART_STATUS_RXEMPTY;
84*a7d2d98cSAlistair Francis 
85*a7d2d98cSAlistair Francis     if (size > rx_fifo_level) {
86*a7d2d98cSAlistair Francis         s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
87*a7d2d98cSAlistair Francis     }
88*a7d2d98cSAlistair Francis 
89*a7d2d98cSAlistair Francis     ibex_uart_update_irqs(s);
90*a7d2d98cSAlistair Francis }
91*a7d2d98cSAlistair Francis 
92*a7d2d98cSAlistair Francis static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
93*a7d2d98cSAlistair Francis                                void *opaque)
94*a7d2d98cSAlistair Francis {
95*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
96*a7d2d98cSAlistair Francis     uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
97*a7d2d98cSAlistair Francis                             >> FIFO_CTRL_TXILVL_SHIFT;
98*a7d2d98cSAlistair Francis     int ret;
99*a7d2d98cSAlistair Francis 
100*a7d2d98cSAlistair Francis     /* instant drain the fifo when there's no back-end */
101*a7d2d98cSAlistair Francis     if (!qemu_chr_fe_backend_connected(&s->chr)) {
102*a7d2d98cSAlistair Francis         s->tx_level = 0;
103*a7d2d98cSAlistair Francis         return FALSE;
104*a7d2d98cSAlistair Francis     }
105*a7d2d98cSAlistair Francis 
106*a7d2d98cSAlistair Francis     if (!s->tx_level) {
107*a7d2d98cSAlistair Francis         s->uart_status &= ~UART_STATUS_TXFULL;
108*a7d2d98cSAlistair Francis         s->uart_status |= UART_STATUS_TXEMPTY;
109*a7d2d98cSAlistair Francis         s->uart_intr_state |= INTR_STATE_TX_EMPTY;
110*a7d2d98cSAlistair Francis         s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
111*a7d2d98cSAlistair Francis         ibex_uart_update_irqs(s);
112*a7d2d98cSAlistair Francis         return FALSE;
113*a7d2d98cSAlistair Francis     }
114*a7d2d98cSAlistair Francis 
115*a7d2d98cSAlistair Francis     ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
116*a7d2d98cSAlistair Francis 
117*a7d2d98cSAlistair Francis     if (ret >= 0) {
118*a7d2d98cSAlistair Francis         s->tx_level -= ret;
119*a7d2d98cSAlistair Francis         memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
120*a7d2d98cSAlistair Francis     }
121*a7d2d98cSAlistair Francis 
122*a7d2d98cSAlistair Francis     if (s->tx_level) {
123*a7d2d98cSAlistair Francis         guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
124*a7d2d98cSAlistair Francis                                         ibex_uart_xmit, s);
125*a7d2d98cSAlistair Francis         if (!r) {
126*a7d2d98cSAlistair Francis             s->tx_level = 0;
127*a7d2d98cSAlistair Francis             return FALSE;
128*a7d2d98cSAlistair Francis         }
129*a7d2d98cSAlistair Francis     }
130*a7d2d98cSAlistair Francis 
131*a7d2d98cSAlistair Francis     /* Clear the TX Full bit */
132*a7d2d98cSAlistair Francis     if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
133*a7d2d98cSAlistair Francis         s->uart_status &= ~UART_STATUS_TXFULL;
134*a7d2d98cSAlistair Francis     }
135*a7d2d98cSAlistair Francis 
136*a7d2d98cSAlistair Francis     /* Disable the TX_WATERMARK IRQ */
137*a7d2d98cSAlistair Francis     if (s->tx_level < tx_fifo_level) {
138*a7d2d98cSAlistair Francis         s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
139*a7d2d98cSAlistair Francis     }
140*a7d2d98cSAlistair Francis 
141*a7d2d98cSAlistair Francis     /* Set TX empty */
142*a7d2d98cSAlistair Francis     if (s->tx_level == 0) {
143*a7d2d98cSAlistair Francis         s->uart_status |= UART_STATUS_TXEMPTY;
144*a7d2d98cSAlistair Francis         s->uart_intr_state |= INTR_STATE_TX_EMPTY;
145*a7d2d98cSAlistair Francis     }
146*a7d2d98cSAlistair Francis 
147*a7d2d98cSAlistair Francis     ibex_uart_update_irqs(s);
148*a7d2d98cSAlistair Francis     return FALSE;
149*a7d2d98cSAlistair Francis }
150*a7d2d98cSAlistair Francis 
151*a7d2d98cSAlistair Francis static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
152*a7d2d98cSAlistair Francis                                int size)
153*a7d2d98cSAlistair Francis {
154*a7d2d98cSAlistair Francis     uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
155*a7d2d98cSAlistair Francis     uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
156*a7d2d98cSAlistair Francis                             >> FIFO_CTRL_TXILVL_SHIFT;
157*a7d2d98cSAlistair Francis 
158*a7d2d98cSAlistair Francis     if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
159*a7d2d98cSAlistair Francis         size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
160*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
161*a7d2d98cSAlistair Francis     }
162*a7d2d98cSAlistair Francis 
163*a7d2d98cSAlistair Francis     memcpy(s->tx_fifo + s->tx_level, buf, size);
164*a7d2d98cSAlistair Francis     s->tx_level += size;
165*a7d2d98cSAlistair Francis 
166*a7d2d98cSAlistair Francis     if (s->tx_level > 0) {
167*a7d2d98cSAlistair Francis         s->uart_status &= ~UART_STATUS_TXEMPTY;
168*a7d2d98cSAlistair Francis     }
169*a7d2d98cSAlistair Francis 
170*a7d2d98cSAlistair Francis     if (s->tx_level >= tx_fifo_level) {
171*a7d2d98cSAlistair Francis         s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
172*a7d2d98cSAlistair Francis         ibex_uart_update_irqs(s);
173*a7d2d98cSAlistair Francis     }
174*a7d2d98cSAlistair Francis 
175*a7d2d98cSAlistair Francis     if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
176*a7d2d98cSAlistair Francis         s->uart_status |= UART_STATUS_TXFULL;
177*a7d2d98cSAlistair Francis     }
178*a7d2d98cSAlistair Francis 
179*a7d2d98cSAlistair Francis     timer_mod(s->fifo_trigger_handle, current_time +
180*a7d2d98cSAlistair Francis               (s->char_tx_time * 4));
181*a7d2d98cSAlistair Francis }
182*a7d2d98cSAlistair Francis 
183*a7d2d98cSAlistair Francis static void ibex_uart_reset(DeviceState *dev)
184*a7d2d98cSAlistair Francis {
185*a7d2d98cSAlistair Francis     IbexUartState *s = IBEX_UART(dev);
186*a7d2d98cSAlistair Francis 
187*a7d2d98cSAlistair Francis     s->uart_intr_state = 0x00000000;
188*a7d2d98cSAlistair Francis     s->uart_intr_state = 0x00000000;
189*a7d2d98cSAlistair Francis     s->uart_intr_enable = 0x00000000;
190*a7d2d98cSAlistair Francis     s->uart_ctrl = 0x00000000;
191*a7d2d98cSAlistair Francis     s->uart_status = 0x0000003c;
192*a7d2d98cSAlistair Francis     s->uart_rdata = 0x00000000;
193*a7d2d98cSAlistair Francis     s->uart_fifo_ctrl = 0x00000000;
194*a7d2d98cSAlistair Francis     s->uart_fifo_status = 0x00000000;
195*a7d2d98cSAlistair Francis     s->uart_ovrd = 0x00000000;
196*a7d2d98cSAlistair Francis     s->uart_val = 0x00000000;
197*a7d2d98cSAlistair Francis     s->uart_timeout_ctrl = 0x00000000;
198*a7d2d98cSAlistair Francis 
199*a7d2d98cSAlistair Francis     s->tx_level = 0;
200*a7d2d98cSAlistair Francis 
201*a7d2d98cSAlistair Francis     s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
202*a7d2d98cSAlistair Francis 
203*a7d2d98cSAlistair Francis     ibex_uart_update_irqs(s);
204*a7d2d98cSAlistair Francis }
205*a7d2d98cSAlistair Francis 
206*a7d2d98cSAlistair Francis static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
207*a7d2d98cSAlistair Francis                                        unsigned int size)
208*a7d2d98cSAlistair Francis {
209*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
210*a7d2d98cSAlistair Francis     uint64_t retvalue = 0;
211*a7d2d98cSAlistair Francis 
212*a7d2d98cSAlistair Francis     switch (addr) {
213*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_STATE:
214*a7d2d98cSAlistair Francis         retvalue = s->uart_intr_state;
215*a7d2d98cSAlistair Francis         break;
216*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_ENABLE:
217*a7d2d98cSAlistair Francis         retvalue = s->uart_intr_enable;
218*a7d2d98cSAlistair Francis         break;
219*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_TEST:
220*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
221*a7d2d98cSAlistair Francis                       "%s: wdata is write only\n", __func__);
222*a7d2d98cSAlistair Francis         break;
223*a7d2d98cSAlistair Francis 
224*a7d2d98cSAlistair Francis     case IBEX_UART_CTRL:
225*a7d2d98cSAlistair Francis         retvalue = s->uart_ctrl;
226*a7d2d98cSAlistair Francis         break;
227*a7d2d98cSAlistair Francis     case IBEX_UART_STATUS:
228*a7d2d98cSAlistair Francis         retvalue = s->uart_status;
229*a7d2d98cSAlistair Francis         break;
230*a7d2d98cSAlistair Francis 
231*a7d2d98cSAlistair Francis     case IBEX_UART_RDATA:
232*a7d2d98cSAlistair Francis         retvalue = s->uart_rdata;
233*a7d2d98cSAlistair Francis         if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
234*a7d2d98cSAlistair Francis             qemu_chr_fe_accept_input(&s->chr);
235*a7d2d98cSAlistair Francis 
236*a7d2d98cSAlistair Francis             s->uart_status |= UART_STATUS_RXIDLE;
237*a7d2d98cSAlistair Francis             s->uart_status |= UART_STATUS_RXEMPTY;
238*a7d2d98cSAlistair Francis         }
239*a7d2d98cSAlistair Francis         break;
240*a7d2d98cSAlistair Francis     case IBEX_UART_WDATA:
241*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
242*a7d2d98cSAlistair Francis                       "%s: wdata is write only\n", __func__);
243*a7d2d98cSAlistair Francis         break;
244*a7d2d98cSAlistair Francis 
245*a7d2d98cSAlistair Francis     case IBEX_UART_FIFO_CTRL:
246*a7d2d98cSAlistair Francis         retvalue = s->uart_fifo_ctrl;
247*a7d2d98cSAlistair Francis         break;
248*a7d2d98cSAlistair Francis     case IBEX_UART_FIFO_STATUS:
249*a7d2d98cSAlistair Francis         retvalue = s->uart_fifo_status;
250*a7d2d98cSAlistair Francis 
251*a7d2d98cSAlistair Francis         retvalue |= s->tx_level & 0x1F;
252*a7d2d98cSAlistair Francis 
253*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
254*a7d2d98cSAlistair Francis                       "%s: RX fifos are not supported\n", __func__);
255*a7d2d98cSAlistair Francis         break;
256*a7d2d98cSAlistair Francis 
257*a7d2d98cSAlistair Francis     case IBEX_UART_OVRD:
258*a7d2d98cSAlistair Francis         retvalue = s->uart_ovrd;
259*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
260*a7d2d98cSAlistair Francis                       "%s: ovrd is not supported\n", __func__);
261*a7d2d98cSAlistair Francis         break;
262*a7d2d98cSAlistair Francis     case IBEX_UART_VAL:
263*a7d2d98cSAlistair Francis         retvalue = s->uart_val;
264*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
265*a7d2d98cSAlistair Francis                       "%s: val is not supported\n", __func__);
266*a7d2d98cSAlistair Francis         break;
267*a7d2d98cSAlistair Francis     case IBEX_UART_TIMEOUT_CTRL:
268*a7d2d98cSAlistair Francis         retvalue = s->uart_timeout_ctrl;
269*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
270*a7d2d98cSAlistair Francis                       "%s: timeout_ctrl is not supported\n", __func__);
271*a7d2d98cSAlistair Francis         break;
272*a7d2d98cSAlistair Francis     default:
273*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
274*a7d2d98cSAlistair Francis                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
275*a7d2d98cSAlistair Francis         return 0;
276*a7d2d98cSAlistair Francis     }
277*a7d2d98cSAlistair Francis 
278*a7d2d98cSAlistair Francis     return retvalue;
279*a7d2d98cSAlistair Francis }
280*a7d2d98cSAlistair Francis 
281*a7d2d98cSAlistair Francis static void ibex_uart_write(void *opaque, hwaddr addr,
282*a7d2d98cSAlistair Francis                                   uint64_t val64, unsigned int size)
283*a7d2d98cSAlistair Francis {
284*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
285*a7d2d98cSAlistair Francis     uint32_t value = val64;
286*a7d2d98cSAlistair Francis 
287*a7d2d98cSAlistair Francis     switch (addr) {
288*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_STATE:
289*a7d2d98cSAlistair Francis         /* Write 1 clear */
290*a7d2d98cSAlistair Francis         s->uart_intr_state &= ~value;
291*a7d2d98cSAlistair Francis         ibex_uart_update_irqs(s);
292*a7d2d98cSAlistair Francis         break;
293*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_ENABLE:
294*a7d2d98cSAlistair Francis         s->uart_intr_enable = value;
295*a7d2d98cSAlistair Francis         ibex_uart_update_irqs(s);
296*a7d2d98cSAlistair Francis         break;
297*a7d2d98cSAlistair Francis     case IBEX_UART_INTR_TEST:
298*a7d2d98cSAlistair Francis         s->uart_intr_state |= value;
299*a7d2d98cSAlistair Francis         ibex_uart_update_irqs(s);
300*a7d2d98cSAlistair Francis         break;
301*a7d2d98cSAlistair Francis 
302*a7d2d98cSAlistair Francis     case IBEX_UART_CTRL:
303*a7d2d98cSAlistair Francis         s->uart_ctrl = value;
304*a7d2d98cSAlistair Francis 
305*a7d2d98cSAlistair Francis         if (value & UART_CTRL_NF) {
306*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
307*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_NF is not supported\n", __func__);
308*a7d2d98cSAlistair Francis         }
309*a7d2d98cSAlistair Francis         if (value & UART_CTRL_SLPBK) {
310*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
311*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_SLPBK is not supported\n", __func__);
312*a7d2d98cSAlistair Francis         }
313*a7d2d98cSAlistair Francis         if (value & UART_CTRL_LLPBK) {
314*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
315*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_LLPBK is not supported\n", __func__);
316*a7d2d98cSAlistair Francis         }
317*a7d2d98cSAlistair Francis         if (value & UART_CTRL_PARITY_EN) {
318*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
319*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_PARITY_EN is not supported\n",
320*a7d2d98cSAlistair Francis                           __func__);
321*a7d2d98cSAlistair Francis         }
322*a7d2d98cSAlistair Francis         if (value & UART_CTRL_PARITY_ODD) {
323*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
324*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_PARITY_ODD is not supported\n",
325*a7d2d98cSAlistair Francis                           __func__);
326*a7d2d98cSAlistair Francis         }
327*a7d2d98cSAlistair Francis         if (value & UART_CTRL_RXBLVL) {
328*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
329*a7d2d98cSAlistair Francis                           "%s: UART_CTRL_RXBLVL is not supported\n", __func__);
330*a7d2d98cSAlistair Francis         }
331*a7d2d98cSAlistair Francis         if (value & UART_CTRL_NCO) {
332*a7d2d98cSAlistair Francis             uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
333*a7d2d98cSAlistair Francis             baud *= 1000;
334*a7d2d98cSAlistair Francis             baud /= 2 ^ 20;
335*a7d2d98cSAlistair Francis 
336*a7d2d98cSAlistair Francis             s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
337*a7d2d98cSAlistair Francis         }
338*a7d2d98cSAlistair Francis         break;
339*a7d2d98cSAlistair Francis     case IBEX_UART_STATUS:
340*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
341*a7d2d98cSAlistair Francis                       "%s: status is read only\n", __func__);
342*a7d2d98cSAlistair Francis         break;
343*a7d2d98cSAlistair Francis 
344*a7d2d98cSAlistair Francis     case IBEX_UART_RDATA:
345*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
346*a7d2d98cSAlistair Francis                       "%s: rdata is read only\n", __func__);
347*a7d2d98cSAlistair Francis         break;
348*a7d2d98cSAlistair Francis     case IBEX_UART_WDATA:
349*a7d2d98cSAlistair Francis         uart_write_tx_fifo(s, (uint8_t *) &value, 1);
350*a7d2d98cSAlistair Francis         break;
351*a7d2d98cSAlistair Francis 
352*a7d2d98cSAlistair Francis     case IBEX_UART_FIFO_CTRL:
353*a7d2d98cSAlistair Francis         s->uart_fifo_ctrl = value;
354*a7d2d98cSAlistair Francis 
355*a7d2d98cSAlistair Francis         if (value & FIFO_CTRL_RXRST) {
356*a7d2d98cSAlistair Francis             qemu_log_mask(LOG_UNIMP,
357*a7d2d98cSAlistair Francis                           "%s: RX fifos are not supported\n", __func__);
358*a7d2d98cSAlistair Francis         }
359*a7d2d98cSAlistair Francis         if (value & FIFO_CTRL_TXRST) {
360*a7d2d98cSAlistair Francis             s->tx_level = 0;
361*a7d2d98cSAlistair Francis         }
362*a7d2d98cSAlistair Francis         break;
363*a7d2d98cSAlistair Francis     case IBEX_UART_FIFO_STATUS:
364*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
365*a7d2d98cSAlistair Francis                       "%s: fifo_status is read only\n", __func__);
366*a7d2d98cSAlistair Francis         break;
367*a7d2d98cSAlistair Francis 
368*a7d2d98cSAlistair Francis     case IBEX_UART_OVRD:
369*a7d2d98cSAlistair Francis         s->uart_ovrd = value;
370*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
371*a7d2d98cSAlistair Francis                       "%s: ovrd is not supported\n", __func__);
372*a7d2d98cSAlistair Francis         break;
373*a7d2d98cSAlistair Francis     case IBEX_UART_VAL:
374*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
375*a7d2d98cSAlistair Francis                       "%s: val is read only\n", __func__);
376*a7d2d98cSAlistair Francis         break;
377*a7d2d98cSAlistair Francis     case IBEX_UART_TIMEOUT_CTRL:
378*a7d2d98cSAlistair Francis         s->uart_timeout_ctrl = value;
379*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_UNIMP,
380*a7d2d98cSAlistair Francis                       "%s: timeout_ctrl is not supported\n", __func__);
381*a7d2d98cSAlistair Francis         break;
382*a7d2d98cSAlistair Francis     default:
383*a7d2d98cSAlistair Francis         qemu_log_mask(LOG_GUEST_ERROR,
384*a7d2d98cSAlistair Francis                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
385*a7d2d98cSAlistair Francis     }
386*a7d2d98cSAlistair Francis }
387*a7d2d98cSAlistair Francis 
388*a7d2d98cSAlistair Francis static void fifo_trigger_update(void *opaque)
389*a7d2d98cSAlistair Francis {
390*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
391*a7d2d98cSAlistair Francis 
392*a7d2d98cSAlistair Francis     if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
393*a7d2d98cSAlistair Francis         ibex_uart_xmit(NULL, G_IO_OUT, s);
394*a7d2d98cSAlistair Francis     }
395*a7d2d98cSAlistair Francis }
396*a7d2d98cSAlistair Francis 
397*a7d2d98cSAlistair Francis static const MemoryRegionOps ibex_uart_ops = {
398*a7d2d98cSAlistair Francis     .read = ibex_uart_read,
399*a7d2d98cSAlistair Francis     .write = ibex_uart_write,
400*a7d2d98cSAlistair Francis     .endianness = DEVICE_NATIVE_ENDIAN,
401*a7d2d98cSAlistair Francis     .impl.min_access_size = 4,
402*a7d2d98cSAlistair Francis     .impl.max_access_size = 4,
403*a7d2d98cSAlistair Francis };
404*a7d2d98cSAlistair Francis 
405*a7d2d98cSAlistair Francis static int ibex_uart_post_load(void *opaque, int version_id)
406*a7d2d98cSAlistair Francis {
407*a7d2d98cSAlistair Francis     IbexUartState *s = opaque;
408*a7d2d98cSAlistair Francis 
409*a7d2d98cSAlistair Francis     ibex_uart_update_irqs(s);
410*a7d2d98cSAlistair Francis     return 0;
411*a7d2d98cSAlistair Francis }
412*a7d2d98cSAlistair Francis 
413*a7d2d98cSAlistair Francis static const VMStateDescription vmstate_ibex_uart = {
414*a7d2d98cSAlistair Francis     .name = TYPE_IBEX_UART,
415*a7d2d98cSAlistair Francis     .version_id = 1,
416*a7d2d98cSAlistair Francis     .minimum_version_id = 1,
417*a7d2d98cSAlistair Francis     .post_load = ibex_uart_post_load,
418*a7d2d98cSAlistair Francis     .fields = (VMStateField[]) {
419*a7d2d98cSAlistair Francis         VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
420*a7d2d98cSAlistair Francis                             IBEX_UART_TX_FIFO_SIZE),
421*a7d2d98cSAlistair Francis         VMSTATE_UINT32(tx_level, IbexUartState),
422*a7d2d98cSAlistair Francis         VMSTATE_UINT64(char_tx_time, IbexUartState),
423*a7d2d98cSAlistair Francis         VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
424*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_intr_state, IbexUartState),
425*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_intr_enable, IbexUartState),
426*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_ctrl, IbexUartState),
427*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_status, IbexUartState),
428*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_rdata, IbexUartState),
429*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
430*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_fifo_status, IbexUartState),
431*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_ovrd, IbexUartState),
432*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_val, IbexUartState),
433*a7d2d98cSAlistair Francis         VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
434*a7d2d98cSAlistair Francis         VMSTATE_END_OF_LIST()
435*a7d2d98cSAlistair Francis     }
436*a7d2d98cSAlistair Francis };
437*a7d2d98cSAlistair Francis 
438*a7d2d98cSAlistair Francis static Property ibex_uart_properties[] = {
439*a7d2d98cSAlistair Francis     DEFINE_PROP_CHR("chardev", IbexUartState, chr),
440*a7d2d98cSAlistair Francis     DEFINE_PROP_END_OF_LIST(),
441*a7d2d98cSAlistair Francis };
442*a7d2d98cSAlistair Francis 
443*a7d2d98cSAlistair Francis static void ibex_uart_init(Object *obj)
444*a7d2d98cSAlistair Francis {
445*a7d2d98cSAlistair Francis     IbexUartState *s = IBEX_UART(obj);
446*a7d2d98cSAlistair Francis 
447*a7d2d98cSAlistair Francis     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
448*a7d2d98cSAlistair Francis     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
449*a7d2d98cSAlistair Francis     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);
450*a7d2d98cSAlistair Francis     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
451*a7d2d98cSAlistair Francis 
452*a7d2d98cSAlistair Francis     memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
453*a7d2d98cSAlistair Francis                           TYPE_IBEX_UART, 0x400);
454*a7d2d98cSAlistair Francis     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
455*a7d2d98cSAlistair Francis }
456*a7d2d98cSAlistair Francis 
457*a7d2d98cSAlistair Francis static void ibex_uart_realize(DeviceState *dev, Error **errp)
458*a7d2d98cSAlistair Francis {
459*a7d2d98cSAlistair Francis     IbexUartState *s = IBEX_UART(dev);
460*a7d2d98cSAlistair Francis 
461*a7d2d98cSAlistair Francis     s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
462*a7d2d98cSAlistair Francis                                           fifo_trigger_update, s);
463*a7d2d98cSAlistair Francis 
464*a7d2d98cSAlistair Francis     qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
465*a7d2d98cSAlistair Francis                              ibex_uart_receive, NULL, NULL,
466*a7d2d98cSAlistair Francis                              s, NULL, true);
467*a7d2d98cSAlistair Francis }
468*a7d2d98cSAlistair Francis 
469*a7d2d98cSAlistair Francis static void ibex_uart_class_init(ObjectClass *klass, void *data)
470*a7d2d98cSAlistair Francis {
471*a7d2d98cSAlistair Francis     DeviceClass *dc = DEVICE_CLASS(klass);
472*a7d2d98cSAlistair Francis 
473*a7d2d98cSAlistair Francis     dc->reset = ibex_uart_reset;
474*a7d2d98cSAlistair Francis     dc->realize = ibex_uart_realize;
475*a7d2d98cSAlistair Francis     dc->vmsd = &vmstate_ibex_uart;
476*a7d2d98cSAlistair Francis     device_class_set_props(dc, ibex_uart_properties);
477*a7d2d98cSAlistair Francis }
478*a7d2d98cSAlistair Francis 
479*a7d2d98cSAlistair Francis static const TypeInfo ibex_uart_info = {
480*a7d2d98cSAlistair Francis     .name          = TYPE_IBEX_UART,
481*a7d2d98cSAlistair Francis     .parent        = TYPE_SYS_BUS_DEVICE,
482*a7d2d98cSAlistair Francis     .instance_size = sizeof(IbexUartState),
483*a7d2d98cSAlistair Francis     .instance_init = ibex_uart_init,
484*a7d2d98cSAlistair Francis     .class_init    = ibex_uart_class_init,
485*a7d2d98cSAlistair Francis };
486*a7d2d98cSAlistair Francis 
487*a7d2d98cSAlistair Francis static void ibex_uart_register_types(void)
488*a7d2d98cSAlistair Francis {
489*a7d2d98cSAlistair Francis     type_register_static(&ibex_uart_info);
490*a7d2d98cSAlistair Francis }
491*a7d2d98cSAlistair Francis 
492*a7d2d98cSAlistair Francis type_init(ibex_uart_register_types)
493