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