197398d90SAndrew Baumann /* 297398d90SAndrew Baumann * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI). 397398d90SAndrew Baumann * Copyright (c) 2015, Microsoft 497398d90SAndrew Baumann * Written by Andrew Baumann 597398d90SAndrew Baumann * Based on pl011.c, copyright terms below: 697398d90SAndrew Baumann * 797398d90SAndrew Baumann * Arm PrimeCell PL011 UART 897398d90SAndrew Baumann * 997398d90SAndrew Baumann * Copyright (c) 2006 CodeSourcery. 1097398d90SAndrew Baumann * Written by Paul Brook 1197398d90SAndrew Baumann * 1297398d90SAndrew Baumann * This code is licensed under the GPL. 1397398d90SAndrew Baumann * 1497398d90SAndrew Baumann * At present only the core UART functions (data path for tx/rx) are 1597398d90SAndrew Baumann * implemented. The following features/registers are unimplemented: 1697398d90SAndrew Baumann * - Line/modem control 1797398d90SAndrew Baumann * - Scratch register 1897398d90SAndrew Baumann * - Extra control 1997398d90SAndrew Baumann * - Baudrate 2097398d90SAndrew Baumann * - SPI interfaces 2197398d90SAndrew Baumann */ 2297398d90SAndrew Baumann 2397398d90SAndrew Baumann #include "qemu/osdep.h" 2497398d90SAndrew Baumann #include "hw/char/bcm2835_aux.h" 2564552b6bSMarkus Armbruster #include "hw/irq.h" 26a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 27d6454270SMarkus Armbruster #include "migration/vmstate.h" 2803dd024fSPaolo Bonzini #include "qemu/log.h" 290b8fa32fSMarkus Armbruster #include "qemu/module.h" 3097398d90SAndrew Baumann 3197398d90SAndrew Baumann #define AUX_IRQ 0x0 3297398d90SAndrew Baumann #define AUX_ENABLES 0x4 3397398d90SAndrew Baumann #define AUX_MU_IO_REG 0x40 3497398d90SAndrew Baumann #define AUX_MU_IER_REG 0x44 3597398d90SAndrew Baumann #define AUX_MU_IIR_REG 0x48 3697398d90SAndrew Baumann #define AUX_MU_LCR_REG 0x4c 3797398d90SAndrew Baumann #define AUX_MU_MCR_REG 0x50 3897398d90SAndrew Baumann #define AUX_MU_LSR_REG 0x54 3997398d90SAndrew Baumann #define AUX_MU_MSR_REG 0x58 4097398d90SAndrew Baumann #define AUX_MU_SCRATCH 0x5c 4197398d90SAndrew Baumann #define AUX_MU_CNTL_REG 0x60 4297398d90SAndrew Baumann #define AUX_MU_STAT_REG 0x64 4397398d90SAndrew Baumann #define AUX_MU_BAUD_REG 0x68 4497398d90SAndrew Baumann 4597398d90SAndrew Baumann /* bits in IER/IIR registers */ 4665e9f27fSGuenter Roeck #define RX_INT 0x1 4765e9f27fSGuenter Roeck #define TX_INT 0x2 4897398d90SAndrew Baumann 4997398d90SAndrew Baumann static void bcm2835_aux_update(BCM2835AuxState *s) 5097398d90SAndrew Baumann { 5197398d90SAndrew Baumann /* signal an interrupt if either: 5297398d90SAndrew Baumann * 1. rx interrupt is enabled and we have a non-empty rx fifo, or 5397398d90SAndrew Baumann * 2. the tx interrupt is enabled (since we instantly drain the tx fifo) 5497398d90SAndrew Baumann */ 5597398d90SAndrew Baumann s->iir = 0; 5697398d90SAndrew Baumann if ((s->ier & RX_INT) && s->read_count != 0) { 5797398d90SAndrew Baumann s->iir |= RX_INT; 5897398d90SAndrew Baumann } 5997398d90SAndrew Baumann if (s->ier & TX_INT) { 6097398d90SAndrew Baumann s->iir |= TX_INT; 6197398d90SAndrew Baumann } 6297398d90SAndrew Baumann qemu_set_irq(s->irq, s->iir != 0); 6397398d90SAndrew Baumann } 6497398d90SAndrew Baumann 6597398d90SAndrew Baumann static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size) 6697398d90SAndrew Baumann { 6797398d90SAndrew Baumann BCM2835AuxState *s = opaque; 6897398d90SAndrew Baumann uint32_t c, res; 6997398d90SAndrew Baumann 7097398d90SAndrew Baumann switch (offset) { 7197398d90SAndrew Baumann case AUX_IRQ: 7297398d90SAndrew Baumann return s->iir != 0; 7397398d90SAndrew Baumann 7497398d90SAndrew Baumann case AUX_ENABLES: 7597398d90SAndrew Baumann return 1; /* mini UART permanently enabled */ 7697398d90SAndrew Baumann 7797398d90SAndrew Baumann case AUX_MU_IO_REG: 7897398d90SAndrew Baumann /* "DLAB bit set means access baudrate register" is NYI */ 7997398d90SAndrew Baumann c = s->read_fifo[s->read_pos]; 8097398d90SAndrew Baumann if (s->read_count > 0) { 8197398d90SAndrew Baumann s->read_count--; 8297398d90SAndrew Baumann if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) { 8397398d90SAndrew Baumann s->read_pos = 0; 8497398d90SAndrew Baumann } 8597398d90SAndrew Baumann } 865345fdb4SMarc-André Lureau qemu_chr_fe_accept_input(&s->chr); 8797398d90SAndrew Baumann bcm2835_aux_update(s); 8897398d90SAndrew Baumann return c; 8997398d90SAndrew Baumann 9097398d90SAndrew Baumann case AUX_MU_IER_REG: 9197398d90SAndrew Baumann /* "DLAB bit set means access baudrate register" is NYI */ 9297398d90SAndrew Baumann return 0xc0 | s->ier; /* FIFO enables always read 1 */ 9397398d90SAndrew Baumann 9497398d90SAndrew Baumann case AUX_MU_IIR_REG: 9597398d90SAndrew Baumann res = 0xc0; /* FIFO enables */ 9697398d90SAndrew Baumann /* The spec is unclear on what happens when both tx and rx 9797398d90SAndrew Baumann * interrupts are active, besides that this cannot occur. At 9897398d90SAndrew Baumann * present, we choose to prioritise the rx interrupt, since 9997398d90SAndrew Baumann * the tx fifo is always empty. */ 10097398d90SAndrew Baumann if (s->read_count != 0) { 10197398d90SAndrew Baumann res |= 0x4; 10297398d90SAndrew Baumann } else { 10397398d90SAndrew Baumann res |= 0x2; 10497398d90SAndrew Baumann } 10597398d90SAndrew Baumann if (s->iir == 0) { 10697398d90SAndrew Baumann res |= 0x1; 10797398d90SAndrew Baumann } 10897398d90SAndrew Baumann return res; 10997398d90SAndrew Baumann 11097398d90SAndrew Baumann case AUX_MU_LCR_REG: 11197398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); 11297398d90SAndrew Baumann return 0; 11397398d90SAndrew Baumann 11497398d90SAndrew Baumann case AUX_MU_MCR_REG: 11597398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); 11697398d90SAndrew Baumann return 0; 11797398d90SAndrew Baumann 11897398d90SAndrew Baumann case AUX_MU_LSR_REG: 11997398d90SAndrew Baumann res = 0x60; /* tx idle, empty */ 12097398d90SAndrew Baumann if (s->read_count != 0) { 12197398d90SAndrew Baumann res |= 0x1; 12297398d90SAndrew Baumann } 12397398d90SAndrew Baumann return res; 12497398d90SAndrew Baumann 12597398d90SAndrew Baumann case AUX_MU_MSR_REG: 12697398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__); 12797398d90SAndrew Baumann return 0; 12897398d90SAndrew Baumann 12997398d90SAndrew Baumann case AUX_MU_SCRATCH: 13097398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); 13197398d90SAndrew Baumann return 0; 13297398d90SAndrew Baumann 13397398d90SAndrew Baumann case AUX_MU_CNTL_REG: 13497398d90SAndrew Baumann return 0x3; /* tx, rx enabled */ 13597398d90SAndrew Baumann 13697398d90SAndrew Baumann case AUX_MU_STAT_REG: 13797398d90SAndrew Baumann res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */ 13897398d90SAndrew Baumann if (s->read_count > 0) { 13997398d90SAndrew Baumann res |= 0x1; /* data in input buffer */ 14097398d90SAndrew Baumann assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN); 14197398d90SAndrew Baumann res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */ 14297398d90SAndrew Baumann } 14397398d90SAndrew Baumann return res; 14497398d90SAndrew Baumann 14597398d90SAndrew Baumann case AUX_MU_BAUD_REG: 14697398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); 14797398d90SAndrew Baumann return 0; 14897398d90SAndrew Baumann 14997398d90SAndrew Baumann default: 15097398d90SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 15197398d90SAndrew Baumann __func__, offset); 15297398d90SAndrew Baumann return 0; 15397398d90SAndrew Baumann } 15497398d90SAndrew Baumann } 15597398d90SAndrew Baumann 15697398d90SAndrew Baumann static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value, 15797398d90SAndrew Baumann unsigned size) 15897398d90SAndrew Baumann { 15997398d90SAndrew Baumann BCM2835AuxState *s = opaque; 16097398d90SAndrew Baumann unsigned char ch; 16197398d90SAndrew Baumann 16297398d90SAndrew Baumann switch (offset) { 16397398d90SAndrew Baumann case AUX_ENABLES: 16497398d90SAndrew Baumann if (value != 1) { 16597398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI" 166e1ecf8c8SPhilippe Mathieu-Daudé " or disable UART: 0x%"PRIx64"\n", 167e1ecf8c8SPhilippe Mathieu-Daudé __func__, value); 16897398d90SAndrew Baumann } 16997398d90SAndrew Baumann break; 17097398d90SAndrew Baumann 17197398d90SAndrew Baumann case AUX_MU_IO_REG: 17297398d90SAndrew Baumann /* "DLAB bit set means access baudrate register" is NYI */ 17397398d90SAndrew Baumann ch = value; 1746ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 1756ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 1765345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&s->chr, &ch, 1); 17797398d90SAndrew Baumann break; 17897398d90SAndrew Baumann 17997398d90SAndrew Baumann case AUX_MU_IER_REG: 18097398d90SAndrew Baumann /* "DLAB bit set means access baudrate register" is NYI */ 18197398d90SAndrew Baumann s->ier = value & (TX_INT | RX_INT); 18297398d90SAndrew Baumann bcm2835_aux_update(s); 18397398d90SAndrew Baumann break; 18497398d90SAndrew Baumann 18597398d90SAndrew Baumann case AUX_MU_IIR_REG: 18697398d90SAndrew Baumann if (value & 0x2) { 18797398d90SAndrew Baumann s->read_count = 0; 18897398d90SAndrew Baumann } 18997398d90SAndrew Baumann break; 19097398d90SAndrew Baumann 19197398d90SAndrew Baumann case AUX_MU_LCR_REG: 19297398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); 19397398d90SAndrew Baumann break; 19497398d90SAndrew Baumann 19597398d90SAndrew Baumann case AUX_MU_MCR_REG: 19697398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); 19797398d90SAndrew Baumann break; 19897398d90SAndrew Baumann 19997398d90SAndrew Baumann case AUX_MU_SCRATCH: 20097398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); 20197398d90SAndrew Baumann break; 20297398d90SAndrew Baumann 20397398d90SAndrew Baumann case AUX_MU_CNTL_REG: 20497398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__); 20597398d90SAndrew Baumann break; 20697398d90SAndrew Baumann 20797398d90SAndrew Baumann case AUX_MU_BAUD_REG: 20897398d90SAndrew Baumann qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); 20997398d90SAndrew Baumann break; 21097398d90SAndrew Baumann 21197398d90SAndrew Baumann default: 21297398d90SAndrew Baumann qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 21397398d90SAndrew Baumann __func__, offset); 21497398d90SAndrew Baumann } 21597398d90SAndrew Baumann 21697398d90SAndrew Baumann bcm2835_aux_update(s); 21797398d90SAndrew Baumann } 21897398d90SAndrew Baumann 21997398d90SAndrew Baumann static int bcm2835_aux_can_receive(void *opaque) 22097398d90SAndrew Baumann { 22197398d90SAndrew Baumann BCM2835AuxState *s = opaque; 22297398d90SAndrew Baumann 22397398d90SAndrew Baumann return s->read_count < BCM2835_AUX_RX_FIFO_LEN; 22497398d90SAndrew Baumann } 22597398d90SAndrew Baumann 22697398d90SAndrew Baumann static void bcm2835_aux_put_fifo(void *opaque, uint8_t value) 22797398d90SAndrew Baumann { 22897398d90SAndrew Baumann BCM2835AuxState *s = opaque; 22997398d90SAndrew Baumann int slot; 23097398d90SAndrew Baumann 23197398d90SAndrew Baumann slot = s->read_pos + s->read_count; 23297398d90SAndrew Baumann if (slot >= BCM2835_AUX_RX_FIFO_LEN) { 23397398d90SAndrew Baumann slot -= BCM2835_AUX_RX_FIFO_LEN; 23497398d90SAndrew Baumann } 23597398d90SAndrew Baumann s->read_fifo[slot] = value; 23697398d90SAndrew Baumann s->read_count++; 23797398d90SAndrew Baumann if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) { 23897398d90SAndrew Baumann /* buffer full */ 23997398d90SAndrew Baumann } 24097398d90SAndrew Baumann bcm2835_aux_update(s); 24197398d90SAndrew Baumann } 24297398d90SAndrew Baumann 24397398d90SAndrew Baumann static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size) 24497398d90SAndrew Baumann { 24597398d90SAndrew Baumann bcm2835_aux_put_fifo(opaque, *buf); 24697398d90SAndrew Baumann } 24797398d90SAndrew Baumann 24897398d90SAndrew Baumann static const MemoryRegionOps bcm2835_aux_ops = { 24997398d90SAndrew Baumann .read = bcm2835_aux_read, 25097398d90SAndrew Baumann .write = bcm2835_aux_write, 25197398d90SAndrew Baumann .endianness = DEVICE_NATIVE_ENDIAN, 25297398d90SAndrew Baumann .valid.min_access_size = 4, 25397398d90SAndrew Baumann .valid.max_access_size = 4, 25497398d90SAndrew Baumann }; 25597398d90SAndrew Baumann 25697398d90SAndrew Baumann static const VMStateDescription vmstate_bcm2835_aux = { 25797398d90SAndrew Baumann .name = TYPE_BCM2835_AUX, 25897398d90SAndrew Baumann .version_id = 1, 25997398d90SAndrew Baumann .minimum_version_id = 1, 26097398d90SAndrew Baumann .fields = (VMStateField[]) { 26197398d90SAndrew Baumann VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState, 26297398d90SAndrew Baumann BCM2835_AUX_RX_FIFO_LEN), 26397398d90SAndrew Baumann VMSTATE_UINT8(read_pos, BCM2835AuxState), 26497398d90SAndrew Baumann VMSTATE_UINT8(read_count, BCM2835AuxState), 26597398d90SAndrew Baumann VMSTATE_UINT8(ier, BCM2835AuxState), 26697398d90SAndrew Baumann VMSTATE_UINT8(iir, BCM2835AuxState), 26797398d90SAndrew Baumann VMSTATE_END_OF_LIST() 26897398d90SAndrew Baumann } 26997398d90SAndrew Baumann }; 27097398d90SAndrew Baumann 27197398d90SAndrew Baumann static void bcm2835_aux_init(Object *obj) 27297398d90SAndrew Baumann { 27397398d90SAndrew Baumann SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 27497398d90SAndrew Baumann BCM2835AuxState *s = BCM2835_AUX(obj); 27597398d90SAndrew Baumann 27697398d90SAndrew Baumann memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s, 27797398d90SAndrew Baumann TYPE_BCM2835_AUX, 0x100); 27897398d90SAndrew Baumann sysbus_init_mmio(sbd, &s->iomem); 27997398d90SAndrew Baumann sysbus_init_irq(sbd, &s->irq); 28097398d90SAndrew Baumann } 28197398d90SAndrew Baumann 28297398d90SAndrew Baumann static void bcm2835_aux_realize(DeviceState *dev, Error **errp) 28397398d90SAndrew Baumann { 28497398d90SAndrew Baumann BCM2835AuxState *s = BCM2835_AUX(dev); 28597398d90SAndrew Baumann 2865345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive, 28781517ba3SAnton Nefedov bcm2835_aux_receive, NULL, NULL, s, NULL, true); 28897398d90SAndrew Baumann } 28997398d90SAndrew Baumann 29097398d90SAndrew Baumann static Property bcm2835_aux_props[] = { 29197398d90SAndrew Baumann DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr), 29297398d90SAndrew Baumann DEFINE_PROP_END_OF_LIST(), 29397398d90SAndrew Baumann }; 29497398d90SAndrew Baumann 29597398d90SAndrew Baumann static void bcm2835_aux_class_init(ObjectClass *oc, void *data) 29697398d90SAndrew Baumann { 29797398d90SAndrew Baumann DeviceClass *dc = DEVICE_CLASS(oc); 29897398d90SAndrew Baumann 29997398d90SAndrew Baumann dc->realize = bcm2835_aux_realize; 30097398d90SAndrew Baumann dc->vmsd = &vmstate_bcm2835_aux; 30197398d90SAndrew Baumann set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 302*4f67d30bSMarc-André Lureau device_class_set_props(dc, bcm2835_aux_props); 30397398d90SAndrew Baumann } 30497398d90SAndrew Baumann 30597398d90SAndrew Baumann static const TypeInfo bcm2835_aux_info = { 30697398d90SAndrew Baumann .name = TYPE_BCM2835_AUX, 30797398d90SAndrew Baumann .parent = TYPE_SYS_BUS_DEVICE, 30897398d90SAndrew Baumann .instance_size = sizeof(BCM2835AuxState), 30997398d90SAndrew Baumann .instance_init = bcm2835_aux_init, 31097398d90SAndrew Baumann .class_init = bcm2835_aux_class_init, 31197398d90SAndrew Baumann }; 31297398d90SAndrew Baumann 31397398d90SAndrew Baumann static void bcm2835_aux_register_types(void) 31497398d90SAndrew Baumann { 31597398d90SAndrew Baumann type_register_static(&bcm2835_aux_info); 31697398d90SAndrew Baumann } 31797398d90SAndrew Baumann 31897398d90SAndrew Baumann type_init(bcm2835_aux_register_types) 319