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