qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cmsdk-apb-uart.c (12139B)


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