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