xref: /openbmc/qemu/hw/char/cmsdk-apb-uart.c (revision 775df84e48bffba8cb188eecdf7872923d6e15d7)
1*775df84eSPeter Maydell /*
2*775df84eSPeter Maydell  * ARM CMSDK APB UART emulation
3*775df84eSPeter Maydell  *
4*775df84eSPeter Maydell  * Copyright (c) 2017 Linaro Limited
5*775df84eSPeter Maydell  * Written by Peter Maydell
6*775df84eSPeter Maydell  *
7*775df84eSPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8*775df84eSPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9*775df84eSPeter Maydell  *  (at your option) any later version.
10*775df84eSPeter Maydell  */
11*775df84eSPeter Maydell 
12*775df84eSPeter Maydell /* This is a model of the "APB UART" which is part of the Cortex-M
13*775df84eSPeter Maydell  * System Design Kit (CMSDK) and documented in the Cortex-M System
14*775df84eSPeter Maydell  * Design Kit Technical Reference Manual (ARM DDI0479C):
15*775df84eSPeter Maydell  * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
16*775df84eSPeter Maydell  */
17*775df84eSPeter Maydell 
18*775df84eSPeter Maydell #include "qemu/osdep.h"
19*775df84eSPeter Maydell #include "qemu/log.h"
20*775df84eSPeter Maydell #include "qapi/error.h"
21*775df84eSPeter Maydell #include "trace.h"
22*775df84eSPeter Maydell #include "hw/sysbus.h"
23*775df84eSPeter Maydell #include "hw/registerfields.h"
24*775df84eSPeter Maydell #include "chardev/char-fe.h"
25*775df84eSPeter Maydell #include "chardev/char-serial.h"
26*775df84eSPeter Maydell #include "hw/char/cmsdk-apb-uart.h"
27*775df84eSPeter Maydell 
28*775df84eSPeter Maydell REG32(DATA, 0)
29*775df84eSPeter Maydell REG32(STATE, 4)
30*775df84eSPeter Maydell     FIELD(STATE, TXFULL, 0, 1)
31*775df84eSPeter Maydell     FIELD(STATE, RXFULL, 1, 1)
32*775df84eSPeter Maydell     FIELD(STATE, TXOVERRUN, 2, 1)
33*775df84eSPeter Maydell     FIELD(STATE, RXOVERRUN, 3, 1)
34*775df84eSPeter Maydell REG32(CTRL, 8)
35*775df84eSPeter Maydell     FIELD(CTRL, TX_EN, 0, 1)
36*775df84eSPeter Maydell     FIELD(CTRL, RX_EN, 1, 1)
37*775df84eSPeter Maydell     FIELD(CTRL, TX_INTEN, 2, 1)
38*775df84eSPeter Maydell     FIELD(CTRL, RX_INTEN, 3, 1)
39*775df84eSPeter Maydell     FIELD(CTRL, TXO_INTEN, 4, 1)
40*775df84eSPeter Maydell     FIELD(CTRL, RXO_INTEN, 5, 1)
41*775df84eSPeter Maydell     FIELD(CTRL, HSTEST, 6, 1)
42*775df84eSPeter Maydell REG32(INTSTATUS, 0xc)
43*775df84eSPeter Maydell     FIELD(INTSTATUS, TX, 0, 1)
44*775df84eSPeter Maydell     FIELD(INTSTATUS, RX, 1, 1)
45*775df84eSPeter Maydell     FIELD(INTSTATUS, TXO, 2, 1)
46*775df84eSPeter Maydell     FIELD(INTSTATUS, RXO, 3, 1)
47*775df84eSPeter Maydell REG32(BAUDDIV, 0x10)
48*775df84eSPeter Maydell REG32(PID4, 0xFD0)
49*775df84eSPeter Maydell REG32(PID5, 0xFD4)
50*775df84eSPeter Maydell REG32(PID6, 0xFD8)
51*775df84eSPeter Maydell REG32(PID7, 0xFDC)
52*775df84eSPeter Maydell REG32(PID0, 0xFE0)
53*775df84eSPeter Maydell REG32(PID1, 0xFE4)
54*775df84eSPeter Maydell REG32(PID2, 0xFE8)
55*775df84eSPeter Maydell REG32(PID3, 0xFEC)
56*775df84eSPeter Maydell REG32(CID0, 0xFF0)
57*775df84eSPeter Maydell REG32(CID1, 0xFF4)
58*775df84eSPeter Maydell REG32(CID2, 0xFF8)
59*775df84eSPeter Maydell REG32(CID3, 0xFFC)
60*775df84eSPeter Maydell 
61*775df84eSPeter Maydell /* PID/CID values */
62*775df84eSPeter Maydell static const int uart_id[] = {
63*775df84eSPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
64*775df84eSPeter Maydell     0x21, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
65*775df84eSPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
66*775df84eSPeter Maydell };
67*775df84eSPeter Maydell 
68*775df84eSPeter Maydell static bool uart_baudrate_ok(CMSDKAPBUART *s)
69*775df84eSPeter Maydell {
70*775df84eSPeter Maydell     /* The minimum permitted bauddiv setting is 16, so we just ignore
71*775df84eSPeter Maydell      * settings below that (usually this means the device has just
72*775df84eSPeter Maydell      * been reset and not yet programmed).
73*775df84eSPeter Maydell      */
74*775df84eSPeter Maydell     return s->bauddiv >= 16 && s->bauddiv <= s->pclk_frq;
75*775df84eSPeter Maydell }
76*775df84eSPeter Maydell 
77*775df84eSPeter Maydell static void uart_update_parameters(CMSDKAPBUART *s)
78*775df84eSPeter Maydell {
79*775df84eSPeter Maydell     QEMUSerialSetParams ssp;
80*775df84eSPeter Maydell 
81*775df84eSPeter Maydell     /* This UART is always 8N1 but the baud rate is programmable. */
82*775df84eSPeter Maydell     if (!uart_baudrate_ok(s)) {
83*775df84eSPeter Maydell         return;
84*775df84eSPeter Maydell     }
85*775df84eSPeter Maydell 
86*775df84eSPeter Maydell     ssp.data_bits = 8;
87*775df84eSPeter Maydell     ssp.parity = 'N';
88*775df84eSPeter Maydell     ssp.stop_bits = 1;
89*775df84eSPeter Maydell     ssp.speed = s->pclk_frq / s->bauddiv;
90*775df84eSPeter Maydell     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
91*775df84eSPeter Maydell     trace_cmsdk_apb_uart_set_params(ssp.speed);
92*775df84eSPeter Maydell }
93*775df84eSPeter Maydell 
94*775df84eSPeter Maydell static void cmsdk_apb_uart_update(CMSDKAPBUART *s)
95*775df84eSPeter Maydell {
96*775df84eSPeter Maydell     /* update outbound irqs, including handling the way the rxo and txo
97*775df84eSPeter Maydell      * interrupt status bits are just logical AND of the overrun bit in
98*775df84eSPeter Maydell      * STATE and the overrun interrupt enable bit in CTRL.
99*775df84eSPeter Maydell      */
100*775df84eSPeter Maydell     uint32_t omask = (R_INTSTATUS_RXO_MASK | R_INTSTATUS_TXO_MASK);
101*775df84eSPeter Maydell     s->intstatus &= ~omask;
102*775df84eSPeter Maydell     s->intstatus |= (s->state & (s->ctrl >> 2) & omask);
103*775df84eSPeter Maydell 
104*775df84eSPeter Maydell     qemu_set_irq(s->txint, !!(s->intstatus & R_INTSTATUS_TX_MASK));
105*775df84eSPeter Maydell     qemu_set_irq(s->rxint, !!(s->intstatus & R_INTSTATUS_RX_MASK));
106*775df84eSPeter Maydell     qemu_set_irq(s->txovrint, !!(s->intstatus & R_INTSTATUS_TXO_MASK));
107*775df84eSPeter Maydell     qemu_set_irq(s->rxovrint, !!(s->intstatus & R_INTSTATUS_RXO_MASK));
108*775df84eSPeter Maydell     qemu_set_irq(s->uartint, !!(s->intstatus));
109*775df84eSPeter Maydell }
110*775df84eSPeter Maydell 
111*775df84eSPeter Maydell static int uart_can_receive(void *opaque)
112*775df84eSPeter Maydell {
113*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
114*775df84eSPeter Maydell 
115*775df84eSPeter Maydell     /* We can take a char if RX is enabled and the buffer is empty */
116*775df84eSPeter Maydell     if (s->ctrl & R_CTRL_RX_EN_MASK && !(s->state & R_STATE_RXFULL_MASK)) {
117*775df84eSPeter Maydell         return 1;
118*775df84eSPeter Maydell     }
119*775df84eSPeter Maydell     return 0;
120*775df84eSPeter Maydell }
121*775df84eSPeter Maydell 
122*775df84eSPeter Maydell static void uart_receive(void *opaque, const uint8_t *buf, int size)
123*775df84eSPeter Maydell {
124*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
125*775df84eSPeter Maydell 
126*775df84eSPeter Maydell     trace_cmsdk_apb_uart_receive(*buf);
127*775df84eSPeter Maydell 
128*775df84eSPeter Maydell     /* In fact uart_can_receive() ensures that we can't be
129*775df84eSPeter Maydell      * called unless RX is enabled and the buffer is empty,
130*775df84eSPeter Maydell      * but we include this logic as documentation of what the
131*775df84eSPeter Maydell      * hardware does if a character arrives in these circumstances.
132*775df84eSPeter Maydell      */
133*775df84eSPeter Maydell     if (!(s->ctrl & R_CTRL_RX_EN_MASK)) {
134*775df84eSPeter Maydell         /* Just drop the character on the floor */
135*775df84eSPeter Maydell         return;
136*775df84eSPeter Maydell     }
137*775df84eSPeter Maydell 
138*775df84eSPeter Maydell     if (s->state & R_STATE_RXFULL_MASK) {
139*775df84eSPeter Maydell         s->state |= R_STATE_RXOVERRUN_MASK;
140*775df84eSPeter Maydell     }
141*775df84eSPeter Maydell 
142*775df84eSPeter Maydell     s->rxbuf = *buf;
143*775df84eSPeter Maydell     s->state |= R_STATE_RXFULL_MASK;
144*775df84eSPeter Maydell     if (s->ctrl & R_CTRL_RX_INTEN_MASK) {
145*775df84eSPeter Maydell         s->intstatus |= R_INTSTATUS_RX_MASK;
146*775df84eSPeter Maydell     }
147*775df84eSPeter Maydell     cmsdk_apb_uart_update(s);
148*775df84eSPeter Maydell }
149*775df84eSPeter Maydell 
150*775df84eSPeter Maydell static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size)
151*775df84eSPeter Maydell {
152*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
153*775df84eSPeter Maydell     uint64_t r;
154*775df84eSPeter Maydell 
155*775df84eSPeter Maydell     switch (offset) {
156*775df84eSPeter Maydell     case A_DATA:
157*775df84eSPeter Maydell         r = s->rxbuf;
158*775df84eSPeter Maydell         s->state &= ~R_STATE_RXFULL_MASK;
159*775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
160*775df84eSPeter Maydell         break;
161*775df84eSPeter Maydell     case A_STATE:
162*775df84eSPeter Maydell         r = s->state;
163*775df84eSPeter Maydell         break;
164*775df84eSPeter Maydell     case A_CTRL:
165*775df84eSPeter Maydell         r = s->ctrl;
166*775df84eSPeter Maydell         break;
167*775df84eSPeter Maydell     case A_INTSTATUS:
168*775df84eSPeter Maydell         r = s->intstatus;
169*775df84eSPeter Maydell         break;
170*775df84eSPeter Maydell     case A_BAUDDIV:
171*775df84eSPeter Maydell         r = s->bauddiv;
172*775df84eSPeter Maydell         break;
173*775df84eSPeter Maydell     case A_PID4 ... A_CID3:
174*775df84eSPeter Maydell         r = uart_id[(offset - A_PID4) / 4];
175*775df84eSPeter Maydell         break;
176*775df84eSPeter Maydell     default:
177*775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
178*775df84eSPeter Maydell                       "CMSDK APB UART read: bad offset %x\n", (int) offset);
179*775df84eSPeter Maydell         r = 0;
180*775df84eSPeter Maydell         break;
181*775df84eSPeter Maydell     }
182*775df84eSPeter Maydell     trace_cmsdk_apb_uart_read(offset, r, size);
183*775df84eSPeter Maydell     return r;
184*775df84eSPeter Maydell }
185*775df84eSPeter Maydell 
186*775df84eSPeter Maydell /* Try to send tx data, and arrange to be called back later if
187*775df84eSPeter Maydell  * we can't (ie the char backend is busy/blocking).
188*775df84eSPeter Maydell  */
189*775df84eSPeter Maydell static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque)
190*775df84eSPeter Maydell {
191*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
192*775df84eSPeter Maydell     int ret;
193*775df84eSPeter Maydell 
194*775df84eSPeter Maydell     s->watch_tag = 0;
195*775df84eSPeter Maydell 
196*775df84eSPeter Maydell     if (!(s->ctrl & R_CTRL_TX_EN_MASK) || !(s->state & R_STATE_TXFULL_MASK)) {
197*775df84eSPeter Maydell         return FALSE;
198*775df84eSPeter Maydell     }
199*775df84eSPeter Maydell 
200*775df84eSPeter Maydell     ret = qemu_chr_fe_write(&s->chr, &s->txbuf, 1);
201*775df84eSPeter Maydell     if (ret <= 0) {
202*775df84eSPeter Maydell         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
203*775df84eSPeter Maydell                                              uart_transmit, s);
204*775df84eSPeter Maydell         if (!s->watch_tag) {
205*775df84eSPeter Maydell             /* Most common reason to be here is "no chardev backend":
206*775df84eSPeter Maydell              * just insta-drain the buffer, so the serial output
207*775df84eSPeter Maydell              * goes into a void, rather than blocking the guest.
208*775df84eSPeter Maydell              */
209*775df84eSPeter Maydell             goto buffer_drained;
210*775df84eSPeter Maydell         }
211*775df84eSPeter Maydell         /* Transmit pending */
212*775df84eSPeter Maydell         trace_cmsdk_apb_uart_tx_pending();
213*775df84eSPeter Maydell         return FALSE;
214*775df84eSPeter Maydell     }
215*775df84eSPeter Maydell 
216*775df84eSPeter Maydell buffer_drained:
217*775df84eSPeter Maydell     /* Character successfully sent */
218*775df84eSPeter Maydell     trace_cmsdk_apb_uart_tx(s->txbuf);
219*775df84eSPeter Maydell     s->state &= ~R_STATE_TXFULL_MASK;
220*775df84eSPeter Maydell     /* Going from TXFULL set to clear triggers the tx interrupt */
221*775df84eSPeter Maydell     if (s->ctrl & R_CTRL_TX_INTEN_MASK) {
222*775df84eSPeter Maydell         s->intstatus |= R_INTSTATUS_TX_MASK;
223*775df84eSPeter Maydell     }
224*775df84eSPeter Maydell     cmsdk_apb_uart_update(s);
225*775df84eSPeter Maydell     return FALSE;
226*775df84eSPeter Maydell }
227*775df84eSPeter Maydell 
228*775df84eSPeter Maydell static void uart_cancel_transmit(CMSDKAPBUART *s)
229*775df84eSPeter Maydell {
230*775df84eSPeter Maydell     if (s->watch_tag) {
231*775df84eSPeter Maydell         g_source_remove(s->watch_tag);
232*775df84eSPeter Maydell         s->watch_tag = 0;
233*775df84eSPeter Maydell     }
234*775df84eSPeter Maydell }
235*775df84eSPeter Maydell 
236*775df84eSPeter Maydell static void uart_write(void *opaque, hwaddr offset, uint64_t value,
237*775df84eSPeter Maydell                        unsigned size)
238*775df84eSPeter Maydell {
239*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
240*775df84eSPeter Maydell 
241*775df84eSPeter Maydell     trace_cmsdk_apb_uart_write(offset, value, size);
242*775df84eSPeter Maydell 
243*775df84eSPeter Maydell     switch (offset) {
244*775df84eSPeter Maydell     case A_DATA:
245*775df84eSPeter Maydell         s->txbuf = value;
246*775df84eSPeter Maydell         if (s->state & R_STATE_TXFULL_MASK) {
247*775df84eSPeter Maydell             /* Buffer already full -- note the overrun and let the
248*775df84eSPeter Maydell              * existing pending transmit callback handle the new char.
249*775df84eSPeter Maydell              */
250*775df84eSPeter Maydell             s->state |= R_STATE_TXOVERRUN_MASK;
251*775df84eSPeter Maydell             cmsdk_apb_uart_update(s);
252*775df84eSPeter Maydell         } else {
253*775df84eSPeter Maydell             s->state |= R_STATE_TXFULL_MASK;
254*775df84eSPeter Maydell             uart_transmit(NULL, G_IO_OUT, s);
255*775df84eSPeter Maydell         }
256*775df84eSPeter Maydell         break;
257*775df84eSPeter Maydell     case A_STATE:
258*775df84eSPeter Maydell         /* Bits 0 and 1 are read only; bits 2 and 3 are W1C */
259*775df84eSPeter Maydell         s->state &= ~(value &
260*775df84eSPeter Maydell                       (R_STATE_TXOVERRUN_MASK | R_STATE_RXOVERRUN_MASK));
261*775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
262*775df84eSPeter Maydell         break;
263*775df84eSPeter Maydell     case A_CTRL:
264*775df84eSPeter Maydell         s->ctrl = value & 0x7f;
265*775df84eSPeter Maydell         if ((s->ctrl & R_CTRL_TX_EN_MASK) && !uart_baudrate_ok(s)) {
266*775df84eSPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
267*775df84eSPeter Maydell                           "CMSDK APB UART: Tx enabled with invalid baudrate\n");
268*775df84eSPeter Maydell         }
269*775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
270*775df84eSPeter Maydell         break;
271*775df84eSPeter Maydell     case A_INTSTATUS:
272*775df84eSPeter Maydell         /* All bits are W1C. Clearing the overrun interrupt bits really
273*775df84eSPeter Maydell          * clears the overrun status bits in the STATE register (which
274*775df84eSPeter Maydell          * is then reflected into the intstatus value by the update function).
275*775df84eSPeter Maydell          */
276*775df84eSPeter Maydell         s->state &= ~(value & (R_INTSTATUS_TXO_MASK | R_INTSTATUS_RXO_MASK));
277*775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
278*775df84eSPeter Maydell         break;
279*775df84eSPeter Maydell     case A_BAUDDIV:
280*775df84eSPeter Maydell         s->bauddiv = value & 0xFFFFF;
281*775df84eSPeter Maydell         uart_update_parameters(s);
282*775df84eSPeter Maydell         break;
283*775df84eSPeter Maydell     case A_PID4 ... A_CID3:
284*775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
285*775df84eSPeter Maydell                       "CMSDK APB UART write: write to RO offset 0x%x\n",
286*775df84eSPeter Maydell                       (int)offset);
287*775df84eSPeter Maydell         break;
288*775df84eSPeter Maydell     default:
289*775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
290*775df84eSPeter Maydell                       "CMSDK APB UART write: bad offset 0x%x\n", (int) offset);
291*775df84eSPeter Maydell         break;
292*775df84eSPeter Maydell     }
293*775df84eSPeter Maydell }
294*775df84eSPeter Maydell 
295*775df84eSPeter Maydell static const MemoryRegionOps uart_ops = {
296*775df84eSPeter Maydell     .read = uart_read,
297*775df84eSPeter Maydell     .write = uart_write,
298*775df84eSPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
299*775df84eSPeter Maydell };
300*775df84eSPeter Maydell 
301*775df84eSPeter Maydell static void cmsdk_apb_uart_reset(DeviceState *dev)
302*775df84eSPeter Maydell {
303*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(dev);
304*775df84eSPeter Maydell 
305*775df84eSPeter Maydell     trace_cmsdk_apb_uart_reset();
306*775df84eSPeter Maydell     uart_cancel_transmit(s);
307*775df84eSPeter Maydell     s->state = 0;
308*775df84eSPeter Maydell     s->ctrl = 0;
309*775df84eSPeter Maydell     s->intstatus = 0;
310*775df84eSPeter Maydell     s->bauddiv = 0;
311*775df84eSPeter Maydell     s->txbuf = 0;
312*775df84eSPeter Maydell     s->rxbuf = 0;
313*775df84eSPeter Maydell }
314*775df84eSPeter Maydell 
315*775df84eSPeter Maydell static void cmsdk_apb_uart_init(Object *obj)
316*775df84eSPeter Maydell {
317*775df84eSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
318*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(obj);
319*775df84eSPeter Maydell 
320*775df84eSPeter Maydell     memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
321*775df84eSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
322*775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->txint);
323*775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->rxint);
324*775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->txovrint);
325*775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->rxovrint);
326*775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->uartint);
327*775df84eSPeter Maydell }
328*775df84eSPeter Maydell 
329*775df84eSPeter Maydell static void cmsdk_apb_uart_realize(DeviceState *dev, Error **errp)
330*775df84eSPeter Maydell {
331*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(dev);
332*775df84eSPeter Maydell 
333*775df84eSPeter Maydell     if (s->pclk_frq == 0) {
334*775df84eSPeter Maydell         error_setg(errp, "CMSDK APB UART: pclk-frq property must be set");
335*775df84eSPeter Maydell         return;
336*775df84eSPeter Maydell     }
337*775df84eSPeter Maydell 
338*775df84eSPeter Maydell     /* This UART has no flow control, so we do not need to register
339*775df84eSPeter Maydell      * an event handler to deal with CHR_EVENT_BREAK.
340*775df84eSPeter Maydell      */
341*775df84eSPeter Maydell     qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
342*775df84eSPeter Maydell                              NULL, s, NULL, true);
343*775df84eSPeter Maydell }
344*775df84eSPeter Maydell 
345*775df84eSPeter Maydell static int cmsdk_apb_uart_post_load(void *opaque, int version_id)
346*775df84eSPeter Maydell {
347*775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
348*775df84eSPeter Maydell 
349*775df84eSPeter Maydell     /* If we have a pending character, arrange to resend it. */
350*775df84eSPeter Maydell     if (s->state & R_STATE_TXFULL_MASK) {
351*775df84eSPeter Maydell         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
352*775df84eSPeter Maydell                                              uart_transmit, s);
353*775df84eSPeter Maydell     }
354*775df84eSPeter Maydell     uart_update_parameters(s);
355*775df84eSPeter Maydell     return 0;
356*775df84eSPeter Maydell }
357*775df84eSPeter Maydell 
358*775df84eSPeter Maydell static const VMStateDescription cmsdk_apb_uart_vmstate = {
359*775df84eSPeter Maydell     .name = "cmsdk-apb-uart",
360*775df84eSPeter Maydell     .version_id = 1,
361*775df84eSPeter Maydell     .minimum_version_id = 1,
362*775df84eSPeter Maydell     .post_load = cmsdk_apb_uart_post_load,
363*775df84eSPeter Maydell     .fields = (VMStateField[]) {
364*775df84eSPeter Maydell         VMSTATE_UINT32(state, CMSDKAPBUART),
365*775df84eSPeter Maydell         VMSTATE_UINT32(ctrl, CMSDKAPBUART),
366*775df84eSPeter Maydell         VMSTATE_UINT32(intstatus, CMSDKAPBUART),
367*775df84eSPeter Maydell         VMSTATE_UINT32(bauddiv, CMSDKAPBUART),
368*775df84eSPeter Maydell         VMSTATE_UINT8(txbuf, CMSDKAPBUART),
369*775df84eSPeter Maydell         VMSTATE_UINT8(rxbuf, CMSDKAPBUART),
370*775df84eSPeter Maydell         VMSTATE_END_OF_LIST()
371*775df84eSPeter Maydell     }
372*775df84eSPeter Maydell };
373*775df84eSPeter Maydell 
374*775df84eSPeter Maydell static Property cmsdk_apb_uart_properties[] = {
375*775df84eSPeter Maydell     DEFINE_PROP_CHR("chardev", CMSDKAPBUART, chr),
376*775df84eSPeter Maydell     DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0),
377*775df84eSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
378*775df84eSPeter Maydell };
379*775df84eSPeter Maydell 
380*775df84eSPeter Maydell static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
381*775df84eSPeter Maydell {
382*775df84eSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
383*775df84eSPeter Maydell 
384*775df84eSPeter Maydell     dc->realize = cmsdk_apb_uart_realize;
385*775df84eSPeter Maydell     dc->vmsd = &cmsdk_apb_uart_vmstate;
386*775df84eSPeter Maydell     dc->reset = cmsdk_apb_uart_reset;
387*775df84eSPeter Maydell     dc->props = cmsdk_apb_uart_properties;
388*775df84eSPeter Maydell }
389*775df84eSPeter Maydell 
390*775df84eSPeter Maydell static const TypeInfo cmsdk_apb_uart_info = {
391*775df84eSPeter Maydell     .name = TYPE_CMSDK_APB_UART,
392*775df84eSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
393*775df84eSPeter Maydell     .instance_size = sizeof(CMSDKAPBUART),
394*775df84eSPeter Maydell     .instance_init = cmsdk_apb_uart_init,
395*775df84eSPeter Maydell     .class_init = cmsdk_apb_uart_class_init,
396*775df84eSPeter Maydell };
397*775df84eSPeter Maydell 
398*775df84eSPeter Maydell static void cmsdk_apb_uart_register_types(void)
399*775df84eSPeter Maydell {
400*775df84eSPeter Maydell     type_register_static(&cmsdk_apb_uart_info);
401*775df84eSPeter Maydell }
402*775df84eSPeter Maydell 
403*775df84eSPeter Maydell type_init(cmsdk_apb_uart_register_types);
404