1 /* 2 * BCM2835 (Raspberry Pi / Pi 2) Aux block (mini UART and SPI). 3 * Copyright (c) 2015, Microsoft 4 * Written by Andrew Baumann 5 * Based on pl011.c, copyright terms below: 6 * 7 * Arm PrimeCell PL011 UART 8 * 9 * Copyright (c) 2006 CodeSourcery. 10 * Written by Paul Brook 11 * 12 * This code is licensed under the GPL. 13 * 14 * At present only the core UART functions (data path for tx/rx) are 15 * implemented. The following features/registers are unimplemented: 16 * - Line/modem control 17 * - Scratch register 18 * - Extra control 19 * - Baudrate 20 * - SPI interfaces 21 */ 22 23 #include "qemu/osdep.h" 24 #include "hw/char/bcm2835_aux.h" 25 #include "hw/irq.h" 26 #include "migration/vmstate.h" 27 #include "qemu/log.h" 28 #include "qemu/module.h" 29 30 #define AUX_IRQ 0x0 31 #define AUX_ENABLES 0x4 32 #define AUX_MU_IO_REG 0x40 33 #define AUX_MU_IER_REG 0x44 34 #define AUX_MU_IIR_REG 0x48 35 #define AUX_MU_LCR_REG 0x4c 36 #define AUX_MU_MCR_REG 0x50 37 #define AUX_MU_LSR_REG 0x54 38 #define AUX_MU_MSR_REG 0x58 39 #define AUX_MU_SCRATCH 0x5c 40 #define AUX_MU_CNTL_REG 0x60 41 #define AUX_MU_STAT_REG 0x64 42 #define AUX_MU_BAUD_REG 0x68 43 44 /* bits in IER/IIR registers */ 45 #define RX_INT 0x1 46 #define TX_INT 0x2 47 48 static void bcm2835_aux_update(BCM2835AuxState *s) 49 { 50 /* signal an interrupt if either: 51 * 1. rx interrupt is enabled and we have a non-empty rx fifo, or 52 * 2. the tx interrupt is enabled (since we instantly drain the tx fifo) 53 */ 54 s->iir = 0; 55 if ((s->ier & RX_INT) && s->read_count != 0) { 56 s->iir |= RX_INT; 57 } 58 if (s->ier & TX_INT) { 59 s->iir |= TX_INT; 60 } 61 qemu_set_irq(s->irq, s->iir != 0); 62 } 63 64 static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size) 65 { 66 BCM2835AuxState *s = opaque; 67 uint32_t c, res; 68 69 switch (offset) { 70 case AUX_IRQ: 71 return s->iir != 0; 72 73 case AUX_ENABLES: 74 return 1; /* mini UART permanently enabled */ 75 76 case AUX_MU_IO_REG: 77 /* "DLAB bit set means access baudrate register" is NYI */ 78 c = s->read_fifo[s->read_pos]; 79 if (s->read_count > 0) { 80 s->read_count--; 81 if (++s->read_pos == BCM2835_AUX_RX_FIFO_LEN) { 82 s->read_pos = 0; 83 } 84 } 85 qemu_chr_fe_accept_input(&s->chr); 86 bcm2835_aux_update(s); 87 return c; 88 89 case AUX_MU_IER_REG: 90 /* "DLAB bit set means access baudrate register" is NYI */ 91 return 0xc0 | s->ier; /* FIFO enables always read 1 */ 92 93 case AUX_MU_IIR_REG: 94 res = 0xc0; /* FIFO enables */ 95 /* The spec is unclear on what happens when both tx and rx 96 * interrupts are active, besides that this cannot occur. At 97 * present, we choose to prioritise the rx interrupt, since 98 * the tx fifo is always empty. */ 99 if (s->read_count != 0) { 100 res |= 0x4; 101 } else { 102 res |= 0x2; 103 } 104 if (s->iir == 0) { 105 res |= 0x1; 106 } 107 return res; 108 109 case AUX_MU_LCR_REG: 110 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); 111 return 0; 112 113 case AUX_MU_MCR_REG: 114 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); 115 return 0; 116 117 case AUX_MU_LSR_REG: 118 res = 0x60; /* tx idle, empty */ 119 if (s->read_count != 0) { 120 res |= 0x1; 121 } 122 return res; 123 124 case AUX_MU_MSR_REG: 125 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MSR_REG unsupported\n", __func__); 126 return 0; 127 128 case AUX_MU_SCRATCH: 129 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); 130 return 0; 131 132 case AUX_MU_CNTL_REG: 133 return 0x3; /* tx, rx enabled */ 134 135 case AUX_MU_STAT_REG: 136 res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */ 137 if (s->read_count > 0) { 138 res |= 0x1; /* data in input buffer */ 139 assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN); 140 res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */ 141 } 142 return res; 143 144 case AUX_MU_BAUD_REG: 145 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); 146 return 0; 147 148 default: 149 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 150 __func__, offset); 151 return 0; 152 } 153 } 154 155 static void bcm2835_aux_write(void *opaque, hwaddr offset, uint64_t value, 156 unsigned size) 157 { 158 BCM2835AuxState *s = opaque; 159 unsigned char ch; 160 161 switch (offset) { 162 case AUX_ENABLES: 163 if (value != 1) { 164 qemu_log_mask(LOG_UNIMP, "%s: unsupported attempt to enable SPI " 165 "or disable UART\n", __func__); 166 } 167 break; 168 169 case AUX_MU_IO_REG: 170 /* "DLAB bit set means access baudrate register" is NYI */ 171 ch = value; 172 /* XXX this blocks entire thread. Rewrite to use 173 * qemu_chr_fe_write and background I/O callbacks */ 174 qemu_chr_fe_write_all(&s->chr, &ch, 1); 175 break; 176 177 case AUX_MU_IER_REG: 178 /* "DLAB bit set means access baudrate register" is NYI */ 179 s->ier = value & (TX_INT | RX_INT); 180 bcm2835_aux_update(s); 181 break; 182 183 case AUX_MU_IIR_REG: 184 if (value & 0x2) { 185 s->read_count = 0; 186 } 187 break; 188 189 case AUX_MU_LCR_REG: 190 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_LCR_REG unsupported\n", __func__); 191 break; 192 193 case AUX_MU_MCR_REG: 194 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_MCR_REG unsupported\n", __func__); 195 break; 196 197 case AUX_MU_SCRATCH: 198 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_SCRATCH unsupported\n", __func__); 199 break; 200 201 case AUX_MU_CNTL_REG: 202 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_CNTL_REG unsupported\n", __func__); 203 break; 204 205 case AUX_MU_BAUD_REG: 206 qemu_log_mask(LOG_UNIMP, "%s: AUX_MU_BAUD_REG unsupported\n", __func__); 207 break; 208 209 default: 210 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", 211 __func__, offset); 212 } 213 214 bcm2835_aux_update(s); 215 } 216 217 static int bcm2835_aux_can_receive(void *opaque) 218 { 219 BCM2835AuxState *s = opaque; 220 221 return s->read_count < BCM2835_AUX_RX_FIFO_LEN; 222 } 223 224 static void bcm2835_aux_put_fifo(void *opaque, uint8_t value) 225 { 226 BCM2835AuxState *s = opaque; 227 int slot; 228 229 slot = s->read_pos + s->read_count; 230 if (slot >= BCM2835_AUX_RX_FIFO_LEN) { 231 slot -= BCM2835_AUX_RX_FIFO_LEN; 232 } 233 s->read_fifo[slot] = value; 234 s->read_count++; 235 if (s->read_count == BCM2835_AUX_RX_FIFO_LEN) { 236 /* buffer full */ 237 } 238 bcm2835_aux_update(s); 239 } 240 241 static void bcm2835_aux_receive(void *opaque, const uint8_t *buf, int size) 242 { 243 bcm2835_aux_put_fifo(opaque, *buf); 244 } 245 246 static const MemoryRegionOps bcm2835_aux_ops = { 247 .read = bcm2835_aux_read, 248 .write = bcm2835_aux_write, 249 .endianness = DEVICE_NATIVE_ENDIAN, 250 .valid.min_access_size = 4, 251 .valid.max_access_size = 4, 252 }; 253 254 static const VMStateDescription vmstate_bcm2835_aux = { 255 .name = TYPE_BCM2835_AUX, 256 .version_id = 1, 257 .minimum_version_id = 1, 258 .fields = (VMStateField[]) { 259 VMSTATE_UINT8_ARRAY(read_fifo, BCM2835AuxState, 260 BCM2835_AUX_RX_FIFO_LEN), 261 VMSTATE_UINT8(read_pos, BCM2835AuxState), 262 VMSTATE_UINT8(read_count, BCM2835AuxState), 263 VMSTATE_UINT8(ier, BCM2835AuxState), 264 VMSTATE_UINT8(iir, BCM2835AuxState), 265 VMSTATE_END_OF_LIST() 266 } 267 }; 268 269 static void bcm2835_aux_init(Object *obj) 270 { 271 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 272 BCM2835AuxState *s = BCM2835_AUX(obj); 273 274 memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_aux_ops, s, 275 TYPE_BCM2835_AUX, 0x100); 276 sysbus_init_mmio(sbd, &s->iomem); 277 sysbus_init_irq(sbd, &s->irq); 278 } 279 280 static void bcm2835_aux_realize(DeviceState *dev, Error **errp) 281 { 282 BCM2835AuxState *s = BCM2835_AUX(dev); 283 284 qemu_chr_fe_set_handlers(&s->chr, bcm2835_aux_can_receive, 285 bcm2835_aux_receive, NULL, NULL, s, NULL, true); 286 } 287 288 static Property bcm2835_aux_props[] = { 289 DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr), 290 DEFINE_PROP_END_OF_LIST(), 291 }; 292 293 static void bcm2835_aux_class_init(ObjectClass *oc, void *data) 294 { 295 DeviceClass *dc = DEVICE_CLASS(oc); 296 297 dc->realize = bcm2835_aux_realize; 298 dc->vmsd = &vmstate_bcm2835_aux; 299 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 300 dc->props = bcm2835_aux_props; 301 } 302 303 static const TypeInfo bcm2835_aux_info = { 304 .name = TYPE_BCM2835_AUX, 305 .parent = TYPE_SYS_BUS_DEVICE, 306 .instance_size = sizeof(BCM2835AuxState), 307 .instance_init = bcm2835_aux_init, 308 .class_init = bcm2835_aux_class_init, 309 }; 310 311 static void bcm2835_aux_register_types(void) 312 { 313 type_register_static(&bcm2835_aux_info); 314 } 315 316 type_init(bcm2835_aux_register_types) 317