xref: /openbmc/qemu/hw/char/cmsdk-apb-uart.c (revision 64552b6be4758d3a774f7787b294543ccebd5358)
1775df84eSPeter Maydell /*
2775df84eSPeter Maydell  * ARM CMSDK APB UART emulation
3775df84eSPeter Maydell  *
4775df84eSPeter Maydell  * Copyright (c) 2017 Linaro Limited
5775df84eSPeter Maydell  * Written by Peter Maydell
6775df84eSPeter Maydell  *
7775df84eSPeter Maydell  *  This program is free software; you can redistribute it and/or modify
8775df84eSPeter Maydell  *  it under the terms of the GNU General Public License version 2 or
9775df84eSPeter Maydell  *  (at your option) any later version.
10775df84eSPeter Maydell  */
11775df84eSPeter Maydell 
12775df84eSPeter Maydell /* This is a model of the "APB UART" which is part of the Cortex-M
13775df84eSPeter Maydell  * System Design Kit (CMSDK) and documented in the Cortex-M System
14775df84eSPeter Maydell  * Design Kit Technical Reference Manual (ARM DDI0479C):
15775df84eSPeter Maydell  * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
16775df84eSPeter Maydell  */
17775df84eSPeter Maydell 
18775df84eSPeter Maydell #include "qemu/osdep.h"
19775df84eSPeter Maydell #include "qemu/log.h"
200b8fa32fSMarkus Armbruster #include "qemu/module.h"
21775df84eSPeter Maydell #include "qapi/error.h"
22775df84eSPeter Maydell #include "trace.h"
23775df84eSPeter Maydell #include "hw/sysbus.h"
24775df84eSPeter Maydell #include "hw/registerfields.h"
25775df84eSPeter Maydell #include "chardev/char-fe.h"
26775df84eSPeter Maydell #include "chardev/char-serial.h"
27775df84eSPeter Maydell #include "hw/char/cmsdk-apb-uart.h"
28*64552b6bSMarkus Armbruster #include "hw/irq.h"
29775df84eSPeter Maydell 
30775df84eSPeter Maydell REG32(DATA, 0)
31775df84eSPeter Maydell REG32(STATE, 4)
32775df84eSPeter Maydell     FIELD(STATE, TXFULL, 0, 1)
33775df84eSPeter Maydell     FIELD(STATE, RXFULL, 1, 1)
34775df84eSPeter Maydell     FIELD(STATE, TXOVERRUN, 2, 1)
35775df84eSPeter Maydell     FIELD(STATE, RXOVERRUN, 3, 1)
36775df84eSPeter Maydell REG32(CTRL, 8)
37775df84eSPeter Maydell     FIELD(CTRL, TX_EN, 0, 1)
38775df84eSPeter Maydell     FIELD(CTRL, RX_EN, 1, 1)
39775df84eSPeter Maydell     FIELD(CTRL, TX_INTEN, 2, 1)
40775df84eSPeter Maydell     FIELD(CTRL, RX_INTEN, 3, 1)
41775df84eSPeter Maydell     FIELD(CTRL, TXO_INTEN, 4, 1)
42775df84eSPeter Maydell     FIELD(CTRL, RXO_INTEN, 5, 1)
43775df84eSPeter Maydell     FIELD(CTRL, HSTEST, 6, 1)
44775df84eSPeter Maydell REG32(INTSTATUS, 0xc)
45775df84eSPeter Maydell     FIELD(INTSTATUS, TX, 0, 1)
46775df84eSPeter Maydell     FIELD(INTSTATUS, RX, 1, 1)
47775df84eSPeter Maydell     FIELD(INTSTATUS, TXO, 2, 1)
48775df84eSPeter Maydell     FIELD(INTSTATUS, RXO, 3, 1)
49775df84eSPeter Maydell REG32(BAUDDIV, 0x10)
50775df84eSPeter Maydell REG32(PID4, 0xFD0)
51775df84eSPeter Maydell REG32(PID5, 0xFD4)
52775df84eSPeter Maydell REG32(PID6, 0xFD8)
53775df84eSPeter Maydell REG32(PID7, 0xFDC)
54775df84eSPeter Maydell REG32(PID0, 0xFE0)
55775df84eSPeter Maydell REG32(PID1, 0xFE4)
56775df84eSPeter Maydell REG32(PID2, 0xFE8)
57775df84eSPeter Maydell REG32(PID3, 0xFEC)
58775df84eSPeter Maydell REG32(CID0, 0xFF0)
59775df84eSPeter Maydell REG32(CID1, 0xFF4)
60775df84eSPeter Maydell REG32(CID2, 0xFF8)
61775df84eSPeter Maydell REG32(CID3, 0xFFC)
62775df84eSPeter Maydell 
63775df84eSPeter Maydell /* PID/CID values */
64775df84eSPeter Maydell static const int uart_id[] = {
65775df84eSPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
66775df84eSPeter Maydell     0x21, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
67775df84eSPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
68775df84eSPeter Maydell };
69775df84eSPeter Maydell 
70775df84eSPeter Maydell static bool uart_baudrate_ok(CMSDKAPBUART *s)
71775df84eSPeter Maydell {
72775df84eSPeter Maydell     /* The minimum permitted bauddiv setting is 16, so we just ignore
73775df84eSPeter Maydell      * settings below that (usually this means the device has just
74775df84eSPeter Maydell      * been reset and not yet programmed).
75775df84eSPeter Maydell      */
76775df84eSPeter Maydell     return s->bauddiv >= 16 && s->bauddiv <= s->pclk_frq;
77775df84eSPeter Maydell }
78775df84eSPeter Maydell 
79775df84eSPeter Maydell static void uart_update_parameters(CMSDKAPBUART *s)
80775df84eSPeter Maydell {
81775df84eSPeter Maydell     QEMUSerialSetParams ssp;
82775df84eSPeter Maydell 
83775df84eSPeter Maydell     /* This UART is always 8N1 but the baud rate is programmable. */
84775df84eSPeter Maydell     if (!uart_baudrate_ok(s)) {
85775df84eSPeter Maydell         return;
86775df84eSPeter Maydell     }
87775df84eSPeter Maydell 
88775df84eSPeter Maydell     ssp.data_bits = 8;
89775df84eSPeter Maydell     ssp.parity = 'N';
90775df84eSPeter Maydell     ssp.stop_bits = 1;
91775df84eSPeter Maydell     ssp.speed = s->pclk_frq / s->bauddiv;
92775df84eSPeter Maydell     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
93775df84eSPeter Maydell     trace_cmsdk_apb_uart_set_params(ssp.speed);
94775df84eSPeter Maydell }
95775df84eSPeter Maydell 
96775df84eSPeter Maydell static void cmsdk_apb_uart_update(CMSDKAPBUART *s)
97775df84eSPeter Maydell {
98775df84eSPeter Maydell     /* update outbound irqs, including handling the way the rxo and txo
99775df84eSPeter Maydell      * interrupt status bits are just logical AND of the overrun bit in
100775df84eSPeter Maydell      * STATE and the overrun interrupt enable bit in CTRL.
101775df84eSPeter Maydell      */
102775df84eSPeter Maydell     uint32_t omask = (R_INTSTATUS_RXO_MASK | R_INTSTATUS_TXO_MASK);
103775df84eSPeter Maydell     s->intstatus &= ~omask;
104775df84eSPeter Maydell     s->intstatus |= (s->state & (s->ctrl >> 2) & omask);
105775df84eSPeter Maydell 
106775df84eSPeter Maydell     qemu_set_irq(s->txint, !!(s->intstatus & R_INTSTATUS_TX_MASK));
107775df84eSPeter Maydell     qemu_set_irq(s->rxint, !!(s->intstatus & R_INTSTATUS_RX_MASK));
108775df84eSPeter Maydell     qemu_set_irq(s->txovrint, !!(s->intstatus & R_INTSTATUS_TXO_MASK));
109775df84eSPeter Maydell     qemu_set_irq(s->rxovrint, !!(s->intstatus & R_INTSTATUS_RXO_MASK));
110775df84eSPeter Maydell     qemu_set_irq(s->uartint, !!(s->intstatus));
111775df84eSPeter Maydell }
112775df84eSPeter Maydell 
113775df84eSPeter Maydell static int uart_can_receive(void *opaque)
114775df84eSPeter Maydell {
115775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
116775df84eSPeter Maydell 
117775df84eSPeter Maydell     /* We can take a char if RX is enabled and the buffer is empty */
118775df84eSPeter Maydell     if (s->ctrl & R_CTRL_RX_EN_MASK && !(s->state & R_STATE_RXFULL_MASK)) {
119775df84eSPeter Maydell         return 1;
120775df84eSPeter Maydell     }
121775df84eSPeter Maydell     return 0;
122775df84eSPeter Maydell }
123775df84eSPeter Maydell 
124775df84eSPeter Maydell static void uart_receive(void *opaque, const uint8_t *buf, int size)
125775df84eSPeter Maydell {
126775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
127775df84eSPeter Maydell 
128775df84eSPeter Maydell     trace_cmsdk_apb_uart_receive(*buf);
129775df84eSPeter Maydell 
130775df84eSPeter Maydell     /* In fact uart_can_receive() ensures that we can't be
131775df84eSPeter Maydell      * called unless RX is enabled and the buffer is empty,
132775df84eSPeter Maydell      * but we include this logic as documentation of what the
133775df84eSPeter Maydell      * hardware does if a character arrives in these circumstances.
134775df84eSPeter Maydell      */
135775df84eSPeter Maydell     if (!(s->ctrl & R_CTRL_RX_EN_MASK)) {
136775df84eSPeter Maydell         /* Just drop the character on the floor */
137775df84eSPeter Maydell         return;
138775df84eSPeter Maydell     }
139775df84eSPeter Maydell 
140775df84eSPeter Maydell     if (s->state & R_STATE_RXFULL_MASK) {
141775df84eSPeter Maydell         s->state |= R_STATE_RXOVERRUN_MASK;
142775df84eSPeter Maydell     }
143775df84eSPeter Maydell 
144775df84eSPeter Maydell     s->rxbuf = *buf;
145775df84eSPeter Maydell     s->state |= R_STATE_RXFULL_MASK;
146775df84eSPeter Maydell     if (s->ctrl & R_CTRL_RX_INTEN_MASK) {
147775df84eSPeter Maydell         s->intstatus |= R_INTSTATUS_RX_MASK;
148775df84eSPeter Maydell     }
149775df84eSPeter Maydell     cmsdk_apb_uart_update(s);
150775df84eSPeter Maydell }
151775df84eSPeter Maydell 
152775df84eSPeter Maydell static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size)
153775df84eSPeter Maydell {
154775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
155775df84eSPeter Maydell     uint64_t r;
156775df84eSPeter Maydell 
157775df84eSPeter Maydell     switch (offset) {
158775df84eSPeter Maydell     case A_DATA:
159775df84eSPeter Maydell         r = s->rxbuf;
160775df84eSPeter Maydell         s->state &= ~R_STATE_RXFULL_MASK;
161775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
1620c6a108eSPatrick Oppenlander         qemu_chr_fe_accept_input(&s->chr);
163775df84eSPeter Maydell         break;
164775df84eSPeter Maydell     case A_STATE:
165775df84eSPeter Maydell         r = s->state;
166775df84eSPeter Maydell         break;
167775df84eSPeter Maydell     case A_CTRL:
168775df84eSPeter Maydell         r = s->ctrl;
169775df84eSPeter Maydell         break;
170775df84eSPeter Maydell     case A_INTSTATUS:
171775df84eSPeter Maydell         r = s->intstatus;
172775df84eSPeter Maydell         break;
173775df84eSPeter Maydell     case A_BAUDDIV:
174775df84eSPeter Maydell         r = s->bauddiv;
175775df84eSPeter Maydell         break;
176775df84eSPeter Maydell     case A_PID4 ... A_CID3:
177775df84eSPeter Maydell         r = uart_id[(offset - A_PID4) / 4];
178775df84eSPeter Maydell         break;
179775df84eSPeter Maydell     default:
180775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
181775df84eSPeter Maydell                       "CMSDK APB UART read: bad offset %x\n", (int) offset);
182775df84eSPeter Maydell         r = 0;
183775df84eSPeter Maydell         break;
184775df84eSPeter Maydell     }
185775df84eSPeter Maydell     trace_cmsdk_apb_uart_read(offset, r, size);
186775df84eSPeter Maydell     return r;
187775df84eSPeter Maydell }
188775df84eSPeter Maydell 
189775df84eSPeter Maydell /* Try to send tx data, and arrange to be called back later if
190775df84eSPeter Maydell  * we can't (ie the char backend is busy/blocking).
191775df84eSPeter Maydell  */
192775df84eSPeter Maydell static gboolean uart_transmit(GIOChannel *chan, GIOCondition cond, void *opaque)
193775df84eSPeter Maydell {
194775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
195775df84eSPeter Maydell     int ret;
196775df84eSPeter Maydell 
197775df84eSPeter Maydell     s->watch_tag = 0;
198775df84eSPeter Maydell 
199775df84eSPeter Maydell     if (!(s->ctrl & R_CTRL_TX_EN_MASK) || !(s->state & R_STATE_TXFULL_MASK)) {
200775df84eSPeter Maydell         return FALSE;
201775df84eSPeter Maydell     }
202775df84eSPeter Maydell 
203775df84eSPeter Maydell     ret = qemu_chr_fe_write(&s->chr, &s->txbuf, 1);
204775df84eSPeter Maydell     if (ret <= 0) {
205775df84eSPeter Maydell         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
206775df84eSPeter Maydell                                              uart_transmit, s);
207775df84eSPeter Maydell         if (!s->watch_tag) {
208775df84eSPeter Maydell             /* Most common reason to be here is "no chardev backend":
209775df84eSPeter Maydell              * just insta-drain the buffer, so the serial output
210775df84eSPeter Maydell              * goes into a void, rather than blocking the guest.
211775df84eSPeter Maydell              */
212775df84eSPeter Maydell             goto buffer_drained;
213775df84eSPeter Maydell         }
214775df84eSPeter Maydell         /* Transmit pending */
215775df84eSPeter Maydell         trace_cmsdk_apb_uart_tx_pending();
216775df84eSPeter Maydell         return FALSE;
217775df84eSPeter Maydell     }
218775df84eSPeter Maydell 
219775df84eSPeter Maydell buffer_drained:
220775df84eSPeter Maydell     /* Character successfully sent */
221775df84eSPeter Maydell     trace_cmsdk_apb_uart_tx(s->txbuf);
222775df84eSPeter Maydell     s->state &= ~R_STATE_TXFULL_MASK;
223775df84eSPeter Maydell     /* Going from TXFULL set to clear triggers the tx interrupt */
224775df84eSPeter Maydell     if (s->ctrl & R_CTRL_TX_INTEN_MASK) {
225775df84eSPeter Maydell         s->intstatus |= R_INTSTATUS_TX_MASK;
226775df84eSPeter Maydell     }
227775df84eSPeter Maydell     cmsdk_apb_uart_update(s);
228775df84eSPeter Maydell     return FALSE;
229775df84eSPeter Maydell }
230775df84eSPeter Maydell 
231775df84eSPeter Maydell static void uart_cancel_transmit(CMSDKAPBUART *s)
232775df84eSPeter Maydell {
233775df84eSPeter Maydell     if (s->watch_tag) {
234775df84eSPeter Maydell         g_source_remove(s->watch_tag);
235775df84eSPeter Maydell         s->watch_tag = 0;
236775df84eSPeter Maydell     }
237775df84eSPeter Maydell }
238775df84eSPeter Maydell 
239775df84eSPeter Maydell static void uart_write(void *opaque, hwaddr offset, uint64_t value,
240775df84eSPeter Maydell                        unsigned size)
241775df84eSPeter Maydell {
242775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
243775df84eSPeter Maydell 
244775df84eSPeter Maydell     trace_cmsdk_apb_uart_write(offset, value, size);
245775df84eSPeter Maydell 
246775df84eSPeter Maydell     switch (offset) {
247775df84eSPeter Maydell     case A_DATA:
248775df84eSPeter Maydell         s->txbuf = value;
249775df84eSPeter Maydell         if (s->state & R_STATE_TXFULL_MASK) {
250775df84eSPeter Maydell             /* Buffer already full -- note the overrun and let the
251775df84eSPeter Maydell              * existing pending transmit callback handle the new char.
252775df84eSPeter Maydell              */
253775df84eSPeter Maydell             s->state |= R_STATE_TXOVERRUN_MASK;
254775df84eSPeter Maydell             cmsdk_apb_uart_update(s);
255775df84eSPeter Maydell         } else {
256775df84eSPeter Maydell             s->state |= R_STATE_TXFULL_MASK;
257775df84eSPeter Maydell             uart_transmit(NULL, G_IO_OUT, s);
258775df84eSPeter Maydell         }
259775df84eSPeter Maydell         break;
260775df84eSPeter Maydell     case A_STATE:
261775df84eSPeter Maydell         /* Bits 0 and 1 are read only; bits 2 and 3 are W1C */
262775df84eSPeter Maydell         s->state &= ~(value &
263775df84eSPeter Maydell                       (R_STATE_TXOVERRUN_MASK | R_STATE_RXOVERRUN_MASK));
264775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
265775df84eSPeter Maydell         break;
266775df84eSPeter Maydell     case A_CTRL:
267775df84eSPeter Maydell         s->ctrl = value & 0x7f;
268775df84eSPeter Maydell         if ((s->ctrl & R_CTRL_TX_EN_MASK) && !uart_baudrate_ok(s)) {
269775df84eSPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
270775df84eSPeter Maydell                           "CMSDK APB UART: Tx enabled with invalid baudrate\n");
271775df84eSPeter Maydell         }
272775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
273775df84eSPeter Maydell         break;
274775df84eSPeter Maydell     case A_INTSTATUS:
275775df84eSPeter Maydell         /* All bits are W1C. Clearing the overrun interrupt bits really
276775df84eSPeter Maydell          * clears the overrun status bits in the STATE register (which
277775df84eSPeter Maydell          * is then reflected into the intstatus value by the update function).
278775df84eSPeter Maydell          */
279775df84eSPeter Maydell         s->state &= ~(value & (R_INTSTATUS_TXO_MASK | R_INTSTATUS_RXO_MASK));
2806670b494SPeter Maydell         s->intstatus &= ~value;
281775df84eSPeter Maydell         cmsdk_apb_uart_update(s);
282775df84eSPeter Maydell         break;
283775df84eSPeter Maydell     case A_BAUDDIV:
284775df84eSPeter Maydell         s->bauddiv = value & 0xFFFFF;
285775df84eSPeter Maydell         uart_update_parameters(s);
286775df84eSPeter Maydell         break;
287775df84eSPeter Maydell     case A_PID4 ... A_CID3:
288775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
289775df84eSPeter Maydell                       "CMSDK APB UART write: write to RO offset 0x%x\n",
290775df84eSPeter Maydell                       (int)offset);
291775df84eSPeter Maydell         break;
292775df84eSPeter Maydell     default:
293775df84eSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
294775df84eSPeter Maydell                       "CMSDK APB UART write: bad offset 0x%x\n", (int) offset);
295775df84eSPeter Maydell         break;
296775df84eSPeter Maydell     }
297775df84eSPeter Maydell }
298775df84eSPeter Maydell 
299775df84eSPeter Maydell static const MemoryRegionOps uart_ops = {
300775df84eSPeter Maydell     .read = uart_read,
301775df84eSPeter Maydell     .write = uart_write,
302775df84eSPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
303775df84eSPeter Maydell };
304775df84eSPeter Maydell 
305775df84eSPeter Maydell static void cmsdk_apb_uart_reset(DeviceState *dev)
306775df84eSPeter Maydell {
307775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(dev);
308775df84eSPeter Maydell 
309775df84eSPeter Maydell     trace_cmsdk_apb_uart_reset();
310775df84eSPeter Maydell     uart_cancel_transmit(s);
311775df84eSPeter Maydell     s->state = 0;
312775df84eSPeter Maydell     s->ctrl = 0;
313775df84eSPeter Maydell     s->intstatus = 0;
314775df84eSPeter Maydell     s->bauddiv = 0;
315775df84eSPeter Maydell     s->txbuf = 0;
316775df84eSPeter Maydell     s->rxbuf = 0;
317775df84eSPeter Maydell }
318775df84eSPeter Maydell 
319775df84eSPeter Maydell static void cmsdk_apb_uart_init(Object *obj)
320775df84eSPeter Maydell {
321775df84eSPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
322775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(obj);
323775df84eSPeter Maydell 
324775df84eSPeter Maydell     memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
325775df84eSPeter Maydell     sysbus_init_mmio(sbd, &s->iomem);
326775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->txint);
327775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->rxint);
328775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->txovrint);
329775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->rxovrint);
330775df84eSPeter Maydell     sysbus_init_irq(sbd, &s->uartint);
331775df84eSPeter Maydell }
332775df84eSPeter Maydell 
333775df84eSPeter Maydell static void cmsdk_apb_uart_realize(DeviceState *dev, Error **errp)
334775df84eSPeter Maydell {
335775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(dev);
336775df84eSPeter Maydell 
337775df84eSPeter Maydell     if (s->pclk_frq == 0) {
338775df84eSPeter Maydell         error_setg(errp, "CMSDK APB UART: pclk-frq property must be set");
339775df84eSPeter Maydell         return;
340775df84eSPeter Maydell     }
341775df84eSPeter Maydell 
342775df84eSPeter Maydell     /* This UART has no flow control, so we do not need to register
343775df84eSPeter Maydell      * an event handler to deal with CHR_EVENT_BREAK.
344775df84eSPeter Maydell      */
345775df84eSPeter Maydell     qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
346977a15f4SPeter Maydell                              NULL, NULL, s, NULL, true);
347775df84eSPeter Maydell }
348775df84eSPeter Maydell 
349775df84eSPeter Maydell static int cmsdk_apb_uart_post_load(void *opaque, int version_id)
350775df84eSPeter Maydell {
351775df84eSPeter Maydell     CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
352775df84eSPeter Maydell 
353775df84eSPeter Maydell     /* If we have a pending character, arrange to resend it. */
354775df84eSPeter Maydell     if (s->state & R_STATE_TXFULL_MASK) {
355775df84eSPeter Maydell         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
356775df84eSPeter Maydell                                              uart_transmit, s);
357775df84eSPeter Maydell     }
358775df84eSPeter Maydell     uart_update_parameters(s);
359775df84eSPeter Maydell     return 0;
360775df84eSPeter Maydell }
361775df84eSPeter Maydell 
362775df84eSPeter Maydell static const VMStateDescription cmsdk_apb_uart_vmstate = {
363775df84eSPeter Maydell     .name = "cmsdk-apb-uart",
364775df84eSPeter Maydell     .version_id = 1,
365775df84eSPeter Maydell     .minimum_version_id = 1,
366775df84eSPeter Maydell     .post_load = cmsdk_apb_uart_post_load,
367775df84eSPeter Maydell     .fields = (VMStateField[]) {
368775df84eSPeter Maydell         VMSTATE_UINT32(state, CMSDKAPBUART),
369775df84eSPeter Maydell         VMSTATE_UINT32(ctrl, CMSDKAPBUART),
370775df84eSPeter Maydell         VMSTATE_UINT32(intstatus, CMSDKAPBUART),
371775df84eSPeter Maydell         VMSTATE_UINT32(bauddiv, CMSDKAPBUART),
372775df84eSPeter Maydell         VMSTATE_UINT8(txbuf, CMSDKAPBUART),
373775df84eSPeter Maydell         VMSTATE_UINT8(rxbuf, CMSDKAPBUART),
374775df84eSPeter Maydell         VMSTATE_END_OF_LIST()
375775df84eSPeter Maydell     }
376775df84eSPeter Maydell };
377775df84eSPeter Maydell 
378775df84eSPeter Maydell static Property cmsdk_apb_uart_properties[] = {
379775df84eSPeter Maydell     DEFINE_PROP_CHR("chardev", CMSDKAPBUART, chr),
380775df84eSPeter Maydell     DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0),
381775df84eSPeter Maydell     DEFINE_PROP_END_OF_LIST(),
382775df84eSPeter Maydell };
383775df84eSPeter Maydell 
384775df84eSPeter Maydell static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
385775df84eSPeter Maydell {
386775df84eSPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
387775df84eSPeter Maydell 
388775df84eSPeter Maydell     dc->realize = cmsdk_apb_uart_realize;
389775df84eSPeter Maydell     dc->vmsd = &cmsdk_apb_uart_vmstate;
390775df84eSPeter Maydell     dc->reset = cmsdk_apb_uart_reset;
391775df84eSPeter Maydell     dc->props = cmsdk_apb_uart_properties;
392775df84eSPeter Maydell }
393775df84eSPeter Maydell 
394775df84eSPeter Maydell static const TypeInfo cmsdk_apb_uart_info = {
395775df84eSPeter Maydell     .name = TYPE_CMSDK_APB_UART,
396775df84eSPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
397775df84eSPeter Maydell     .instance_size = sizeof(CMSDKAPBUART),
398775df84eSPeter Maydell     .instance_init = cmsdk_apb_uart_init,
399775df84eSPeter Maydell     .class_init = cmsdk_apb_uart_class_init,
400775df84eSPeter Maydell };
401775df84eSPeter Maydell 
402775df84eSPeter Maydell static void cmsdk_apb_uart_register_types(void)
403775df84eSPeter Maydell {
404775df84eSPeter Maydell     type_register_static(&cmsdk_apb_uart_info);
405775df84eSPeter Maydell }
406775df84eSPeter Maydell 
407775df84eSPeter Maydell type_init(cmsdk_apb_uart_register_types);
408