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