18
#include "qemu/osdep.h"
20
#include "qemu/module.h"
21
#include "qapi/error.h"
24
#include "migration/vmstate.h"
25
#include "hw/registerfields.h"
26
#include "chardev/char-fe.h"
27
#include "chardev/char-serial.h"
28
#include "hw/char/cmsdk-apb-uart.h"
30
#include "hw/qdev-properties-system.h"
34
FIELD(STATE, TXFULL, 0, 1)
35
FIELD(STATE, RXFULL, 1, 1)
36
FIELD(STATE, TXOVERRUN, 2, 1)
37
FIELD(STATE, RXOVERRUN, 3, 1)
39
FIELD(CTRL, TX_EN, 0, 1)
40
FIELD(CTRL, RX_EN, 1, 1)
41
FIELD(CTRL, TX_INTEN, 2, 1)
42
FIELD(CTRL, RX_INTEN, 3, 1)
43
FIELD(CTRL, TXO_INTEN, 4, 1)
44
FIELD(CTRL, RXO_INTEN, 5, 1)
45
FIELD(CTRL, HSTEST, 6, 1)
47
FIELD(INTSTATUS, TX, 0, 1)
48
FIELD(INTSTATUS, RX, 1, 1)
49
FIELD(INTSTATUS, TXO, 2, 1)
50
FIELD(INTSTATUS, RXO, 3, 1)
66
static const int uart_id[] = {
67
0x04, 0x00, 0x00, 0x00,
68
0x21, 0xb8, 0x1b, 0x00,
69
0x0d, 0xf0, 0x05, 0xb1,
72
static bool uart_baudrate_ok(CMSDKAPBUART *s)
78
return s->bauddiv >= 16 && s->bauddiv <= s->pclk_frq;
81
static void uart_update_parameters(CMSDKAPBUART *s)
83
QEMUSerialSetParams ssp;
86
if (!uart_baudrate_ok(s)) {
93
ssp.speed = s->pclk_frq / s->bauddiv;
94
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
95
trace_cmsdk_apb_uart_set_params(ssp.speed);
98
static void cmsdk_apb_uart_update(CMSDKAPBUART *s)
104
uint32_t omask = (R_INTSTATUS_RXO_MASK | R_INTSTATUS_TXO_MASK);
105
s->intstatus &= ~omask;
106
s->intstatus |= (s->state & (s->ctrl >> 2) & omask);
108
qemu_set_irq(s->txint, !!(s->intstatus & R_INTSTATUS_TX_MASK));
109
qemu_set_irq(s->rxint, !!(s->intstatus & R_INTSTATUS_RX_MASK));
110
qemu_set_irq(s->txovrint, !!(s->intstatus & R_INTSTATUS_TXO_MASK));
111
qemu_set_irq(s->rxovrint, !!(s->intstatus & R_INTSTATUS_RXO_MASK));
112
qemu_set_irq(s->uartint, !!(s->intstatus));
115
static int uart_can_receive(void *opaque)
117
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
120
if (s->ctrl & R_CTRL_RX_EN_MASK && !(s->state & R_STATE_RXFULL_MASK)) {
126
static void uart_receive(void *opaque, const uint8_t *buf, int size)
128
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
130
trace_cmsdk_apb_uart_receive(*buf);
137
if (!(s->ctrl & R_CTRL_RX_EN_MASK)) {
142
if (s->state & R_STATE_RXFULL_MASK) {
143
s->state |= R_STATE_RXOVERRUN_MASK;
147
s->state |= R_STATE_RXFULL_MASK;
148
if (s->ctrl & R_CTRL_RX_INTEN_MASK) {
149
s->intstatus |= R_INTSTATUS_RX_MASK;
151
cmsdk_apb_uart_update(s);
154
static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size)
156
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
162
s->state &= ~R_STATE_RXFULL_MASK;
163
cmsdk_apb_uart_update(s);
164
qemu_chr_fe_accept_input(&s->chr);
178
case A_PID4 ... A_CID3:
179
r = uart_id[(offset - A_PID4) / 4];
182
qemu_log_mask(LOG_GUEST_ERROR,
183
"CMSDK APB UART read: bad offset %x\n", (int) offset);
187
trace_cmsdk_apb_uart_read(offset, r, size);
194
static gboolean uart_transmit(void *do_not_use, GIOCondition cond, void *opaque)
196
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
201
if (!(s->ctrl & R_CTRL_TX_EN_MASK) || !(s->state & R_STATE_TXFULL_MASK)) {
202
return G_SOURCE_REMOVE;
205
ret = qemu_chr_fe_write(&s->chr, &s->txbuf, 1);
207
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
217
trace_cmsdk_apb_uart_tx_pending();
218
return G_SOURCE_REMOVE;
223
trace_cmsdk_apb_uart_tx(s->txbuf);
224
s->state &= ~R_STATE_TXFULL_MASK;
226
if (s->ctrl & R_CTRL_TX_INTEN_MASK) {
227
s->intstatus |= R_INTSTATUS_TX_MASK;
229
cmsdk_apb_uart_update(s);
230
return G_SOURCE_REMOVE;
233
static void uart_cancel_transmit(CMSDKAPBUART *s)
236
g_source_remove(s->watch_tag);
241
static void uart_write(void *opaque, hwaddr offset, uint64_t value,
244
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
246
trace_cmsdk_apb_uart_write(offset, value, size);
251
if (s->state & R_STATE_TXFULL_MASK) {
255
s->state |= R_STATE_TXOVERRUN_MASK;
256
cmsdk_apb_uart_update(s);
258
s->state |= R_STATE_TXFULL_MASK;
259
uart_transmit(NULL, G_IO_OUT, s);
264
s->state &= ~(value &
265
(R_STATE_TXOVERRUN_MASK | R_STATE_RXOVERRUN_MASK));
266
cmsdk_apb_uart_update(s);
269
s->ctrl = value & 0x7f;
270
if ((s->ctrl & R_CTRL_TX_EN_MASK) && !uart_baudrate_ok(s)) {
271
qemu_log_mask(LOG_GUEST_ERROR,
272
"CMSDK APB UART: Tx enabled with invalid baudrate\n");
274
cmsdk_apb_uart_update(s);
281
s->state &= ~(value & (R_INTSTATUS_TXO_MASK | R_INTSTATUS_RXO_MASK));
282
s->intstatus &= ~value;
283
cmsdk_apb_uart_update(s);
286
s->bauddiv = value & 0xFFFFF;
287
uart_update_parameters(s);
289
case A_PID4 ... A_CID3:
290
qemu_log_mask(LOG_GUEST_ERROR,
291
"CMSDK APB UART write: write to RO offset 0x%x\n",
295
qemu_log_mask(LOG_GUEST_ERROR,
296
"CMSDK APB UART write: bad offset 0x%x\n", (int) offset);
301
static const MemoryRegionOps uart_ops = {
304
.endianness = DEVICE_LITTLE_ENDIAN,
307
static void cmsdk_apb_uart_reset(DeviceState *dev)
309
CMSDKAPBUART *s = CMSDK_APB_UART(dev);
311
trace_cmsdk_apb_uart_reset();
312
uart_cancel_transmit(s);
321
static void cmsdk_apb_uart_init(Object *obj)
323
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
324
CMSDKAPBUART *s = CMSDK_APB_UART(obj);
326
memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000);
327
sysbus_init_mmio(sbd, &s->iomem);
328
sysbus_init_irq(sbd, &s->txint);
329
sysbus_init_irq(sbd, &s->rxint);
330
sysbus_init_irq(sbd, &s->txovrint);
331
sysbus_init_irq(sbd, &s->rxovrint);
332
sysbus_init_irq(sbd, &s->uartint);
335
static void cmsdk_apb_uart_realize(DeviceState *dev, Error **errp)
337
CMSDKAPBUART *s = CMSDK_APB_UART(dev);
339
if (s->pclk_frq == 0) {
340
error_setg(errp, "CMSDK APB UART: pclk-frq property must be set");
347
qemu_chr_fe_set_handlers(&s->chr, uart_can_receive, uart_receive,
348
NULL, NULL, s, NULL, true);
351
static int cmsdk_apb_uart_post_load(void *opaque, int version_id)
353
CMSDKAPBUART *s = CMSDK_APB_UART(opaque);
356
if (s->state & R_STATE_TXFULL_MASK) {
357
s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
360
uart_update_parameters(s);
364
static const VMStateDescription cmsdk_apb_uart_vmstate = {
365
.name = "cmsdk-apb-uart",
367
.minimum_version_id = 1,
368
.post_load = cmsdk_apb_uart_post_load,
369
.fields = (const VMStateField[]) {
370
VMSTATE_UINT32(state, CMSDKAPBUART),
371
VMSTATE_UINT32(ctrl, CMSDKAPBUART),
372
VMSTATE_UINT32(intstatus, CMSDKAPBUART),
373
VMSTATE_UINT32(bauddiv, CMSDKAPBUART),
374
VMSTATE_UINT8(txbuf, CMSDKAPBUART),
375
VMSTATE_UINT8(rxbuf, CMSDKAPBUART),
376
VMSTATE_END_OF_LIST()
380
static Property cmsdk_apb_uart_properties[] = {
381
DEFINE_PROP_CHR("chardev", CMSDKAPBUART, chr),
382
DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0),
383
DEFINE_PROP_END_OF_LIST(),
386
static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
388
DeviceClass *dc = DEVICE_CLASS(klass);
390
dc->realize = cmsdk_apb_uart_realize;
391
dc->vmsd = &cmsdk_apb_uart_vmstate;
392
dc->reset = cmsdk_apb_uart_reset;
393
device_class_set_props(dc, cmsdk_apb_uart_properties);
396
static const TypeInfo cmsdk_apb_uart_info = {
397
.name = TYPE_CMSDK_APB_UART,
398
.parent = TYPE_SYS_BUS_DEVICE,
399
.instance_size = sizeof(CMSDKAPBUART),
400
.instance_init = cmsdk_apb_uart_init,
401
.class_init = cmsdk_apb_uart_class_init,
404
static void cmsdk_apb_uart_register_types(void)
406
type_register_static(&cmsdk_apb_uart_info);
409
type_init(cmsdk_apb_uart_register_types);