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