pl011.c (11888B)
1/* 2 * Arm PrimeCell PL011 UART 3 * 4 * Copyright (c) 2006 CodeSourcery. 5 * Written by Paul Brook 6 * 7 * This code is licensed under the GPL. 8 */ 9 10/* 11 * QEMU interface: 12 * + sysbus MMIO region 0: device registers 13 * + sysbus IRQ 0: UARTINTR (combined interrupt line) 14 * + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line) 15 * + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line) 16 * + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line) 17 * + sysbus IRQ 4: UARTMSINTR (momem status interrupt line) 18 * + sysbus IRQ 5: UARTEINTR (error interrupt line) 19 */ 20 21#include "qemu/osdep.h" 22#include "hw/char/pl011.h" 23#include "hw/irq.h" 24#include "hw/sysbus.h" 25#include "hw/qdev-clock.h" 26#include "hw/qdev-properties-system.h" 27#include "migration/vmstate.h" 28#include "chardev/char-fe.h" 29#include "chardev/char-serial.h" 30#include "qemu/log.h" 31#include "qemu/module.h" 32#include "trace.h" 33 34#define PL011_INT_TX 0x20 35#define PL011_INT_RX 0x10 36 37#define PL011_FLAG_TXFE 0x80 38#define PL011_FLAG_RXFF 0x40 39#define PL011_FLAG_TXFF 0x20 40#define PL011_FLAG_RXFE 0x10 41 42/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */ 43#define INT_OE (1 << 10) 44#define INT_BE (1 << 9) 45#define INT_PE (1 << 8) 46#define INT_FE (1 << 7) 47#define INT_RT (1 << 6) 48#define INT_TX (1 << 5) 49#define INT_RX (1 << 4) 50#define INT_DSR (1 << 3) 51#define INT_DCD (1 << 2) 52#define INT_CTS (1 << 1) 53#define INT_RI (1 << 0) 54#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE) 55#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS) 56 57static const unsigned char pl011_id_arm[8] = 58 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 59static const unsigned char pl011_id_luminary[8] = 60 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; 61 62/* Which bits in the interrupt status matter for each outbound IRQ line ? */ 63static const uint32_t irqmask[] = { 64 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */ 65 INT_RX, 66 INT_TX, 67 INT_RT, 68 INT_MS, 69 INT_E, 70}; 71 72static void pl011_update(PL011State *s) 73{ 74 uint32_t flags; 75 int i; 76 77 flags = s->int_level & s->int_enabled; 78 trace_pl011_irq_state(flags != 0); 79 for (i = 0; i < ARRAY_SIZE(s->irq); i++) { 80 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0); 81 } 82} 83 84static uint64_t pl011_read(void *opaque, hwaddr offset, 85 unsigned size) 86{ 87 PL011State *s = (PL011State *)opaque; 88 uint32_t c; 89 uint64_t r; 90 91 switch (offset >> 2) { 92 case 0: /* UARTDR */ 93 s->flags &= ~PL011_FLAG_RXFF; 94 c = s->read_fifo[s->read_pos]; 95 if (s->read_count > 0) { 96 s->read_count--; 97 if (++s->read_pos == 16) 98 s->read_pos = 0; 99 } 100 if (s->read_count == 0) { 101 s->flags |= PL011_FLAG_RXFE; 102 } 103 if (s->read_count == s->read_trigger - 1) 104 s->int_level &= ~ PL011_INT_RX; 105 trace_pl011_read_fifo(s->read_count); 106 s->rsr = c >> 8; 107 pl011_update(s); 108 qemu_chr_fe_accept_input(&s->chr); 109 r = c; 110 break; 111 case 1: /* UARTRSR */ 112 r = s->rsr; 113 break; 114 case 6: /* UARTFR */ 115 r = s->flags; 116 break; 117 case 8: /* UARTILPR */ 118 r = s->ilpr; 119 break; 120 case 9: /* UARTIBRD */ 121 r = s->ibrd; 122 break; 123 case 10: /* UARTFBRD */ 124 r = s->fbrd; 125 break; 126 case 11: /* UARTLCR_H */ 127 r = s->lcr; 128 break; 129 case 12: /* UARTCR */ 130 r = s->cr; 131 break; 132 case 13: /* UARTIFLS */ 133 r = s->ifl; 134 break; 135 case 14: /* UARTIMSC */ 136 r = s->int_enabled; 137 break; 138 case 15: /* UARTRIS */ 139 r = s->int_level; 140 break; 141 case 16: /* UARTMIS */ 142 r = s->int_level & s->int_enabled; 143 break; 144 case 18: /* UARTDMACR */ 145 r = s->dmacr; 146 break; 147 case 0x3f8 ... 0x400: 148 r = s->id[(offset - 0xfe0) >> 2]; 149 break; 150 default: 151 qemu_log_mask(LOG_GUEST_ERROR, 152 "pl011_read: Bad offset 0x%x\n", (int)offset); 153 r = 0; 154 break; 155 } 156 157 trace_pl011_read(offset, r); 158 return r; 159} 160 161static void pl011_set_read_trigger(PL011State *s) 162{ 163#if 0 164 /* The docs say the RX interrupt is triggered when the FIFO exceeds 165 the threshold. However linux only reads the FIFO in response to an 166 interrupt. Triggering the interrupt when the FIFO is non-empty seems 167 to make things work. */ 168 if (s->lcr & 0x10) 169 s->read_trigger = (s->ifl >> 1) & 0x1c; 170 else 171#endif 172 s->read_trigger = 1; 173} 174 175static unsigned int pl011_get_baudrate(const PL011State *s) 176{ 177 uint64_t clk; 178 179 if (s->fbrd == 0) { 180 return 0; 181 } 182 183 clk = clock_get_hz(s->clk); 184 return (clk / ((s->ibrd << 6) + s->fbrd)) << 2; 185} 186 187static void pl011_trace_baudrate_change(const PL011State *s) 188{ 189 trace_pl011_baudrate_change(pl011_get_baudrate(s), 190 clock_get_hz(s->clk), 191 s->ibrd, s->fbrd); 192} 193 194static void pl011_write(void *opaque, hwaddr offset, 195 uint64_t value, unsigned size) 196{ 197 PL011State *s = (PL011State *)opaque; 198 unsigned char ch; 199 200 trace_pl011_write(offset, value); 201 202 switch (offset >> 2) { 203 case 0: /* UARTDR */ 204 /* ??? Check if transmitter is enabled. */ 205 ch = value; 206 /* XXX this blocks entire thread. Rewrite to use 207 * qemu_chr_fe_write and background I/O callbacks */ 208 qemu_chr_fe_write_all(&s->chr, &ch, 1); 209 s->int_level |= PL011_INT_TX; 210 pl011_update(s); 211 break; 212 case 1: /* UARTRSR/UARTECR */ 213 s->rsr = 0; 214 break; 215 case 6: /* UARTFR */ 216 /* Writes to Flag register are ignored. */ 217 break; 218 case 8: /* UARTUARTILPR */ 219 s->ilpr = value; 220 break; 221 case 9: /* UARTIBRD */ 222 s->ibrd = value; 223 pl011_trace_baudrate_change(s); 224 break; 225 case 10: /* UARTFBRD */ 226 s->fbrd = value; 227 pl011_trace_baudrate_change(s); 228 break; 229 case 11: /* UARTLCR_H */ 230 /* Reset the FIFO state on FIFO enable or disable */ 231 if ((s->lcr ^ value) & 0x10) { 232 s->read_count = 0; 233 s->read_pos = 0; 234 } 235 if ((s->lcr ^ value) & 0x1) { 236 int break_enable = value & 0x1; 237 qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, 238 &break_enable); 239 } 240 s->lcr = value; 241 pl011_set_read_trigger(s); 242 break; 243 case 12: /* UARTCR */ 244 /* ??? Need to implement the enable and loopback bits. */ 245 s->cr = value; 246 break; 247 case 13: /* UARTIFS */ 248 s->ifl = value; 249 pl011_set_read_trigger(s); 250 break; 251 case 14: /* UARTIMSC */ 252 s->int_enabled = value; 253 pl011_update(s); 254 break; 255 case 17: /* UARTICR */ 256 s->int_level &= ~value; 257 pl011_update(s); 258 break; 259 case 18: /* UARTDMACR */ 260 s->dmacr = value; 261 if (value & 3) { 262 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); 263 } 264 break; 265 default: 266 qemu_log_mask(LOG_GUEST_ERROR, 267 "pl011_write: Bad offset 0x%x\n", (int)offset); 268 } 269} 270 271static int pl011_can_receive(void *opaque) 272{ 273 PL011State *s = (PL011State *)opaque; 274 int r; 275 276 if (s->lcr & 0x10) { 277 r = s->read_count < 16; 278 } else { 279 r = s->read_count < 1; 280 } 281 trace_pl011_can_receive(s->lcr, s->read_count, r); 282 return r; 283} 284 285static void pl011_put_fifo(void *opaque, uint32_t value) 286{ 287 PL011State *s = (PL011State *)opaque; 288 int slot; 289 290 slot = s->read_pos + s->read_count; 291 if (slot >= 16) 292 slot -= 16; 293 s->read_fifo[slot] = value; 294 s->read_count++; 295 s->flags &= ~PL011_FLAG_RXFE; 296 trace_pl011_put_fifo(value, s->read_count); 297 if (!(s->lcr & 0x10) || s->read_count == 16) { 298 trace_pl011_put_fifo_full(); 299 s->flags |= PL011_FLAG_RXFF; 300 } 301 if (s->read_count == s->read_trigger) { 302 s->int_level |= PL011_INT_RX; 303 pl011_update(s); 304 } 305} 306 307static void pl011_receive(void *opaque, const uint8_t *buf, int size) 308{ 309 pl011_put_fifo(opaque, *buf); 310} 311 312static void pl011_event(void *opaque, QEMUChrEvent event) 313{ 314 if (event == CHR_EVENT_BREAK) 315 pl011_put_fifo(opaque, 0x400); 316} 317 318static void pl011_clock_update(void *opaque, ClockEvent event) 319{ 320 PL011State *s = PL011(opaque); 321 322 pl011_trace_baudrate_change(s); 323} 324 325static const MemoryRegionOps pl011_ops = { 326 .read = pl011_read, 327 .write = pl011_write, 328 .endianness = DEVICE_NATIVE_ENDIAN, 329}; 330 331static bool pl011_clock_needed(void *opaque) 332{ 333 PL011State *s = PL011(opaque); 334 335 return s->migrate_clk; 336} 337 338static const VMStateDescription vmstate_pl011_clock = { 339 .name = "pl011/clock", 340 .version_id = 1, 341 .minimum_version_id = 1, 342 .needed = pl011_clock_needed, 343 .fields = (VMStateField[]) { 344 VMSTATE_CLOCK(clk, PL011State), 345 VMSTATE_END_OF_LIST() 346 } 347}; 348 349static const VMStateDescription vmstate_pl011 = { 350 .name = "pl011", 351 .version_id = 2, 352 .minimum_version_id = 2, 353 .fields = (VMStateField[]) { 354 VMSTATE_UINT32(readbuff, PL011State), 355 VMSTATE_UINT32(flags, PL011State), 356 VMSTATE_UINT32(lcr, PL011State), 357 VMSTATE_UINT32(rsr, PL011State), 358 VMSTATE_UINT32(cr, PL011State), 359 VMSTATE_UINT32(dmacr, PL011State), 360 VMSTATE_UINT32(int_enabled, PL011State), 361 VMSTATE_UINT32(int_level, PL011State), 362 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16), 363 VMSTATE_UINT32(ilpr, PL011State), 364 VMSTATE_UINT32(ibrd, PL011State), 365 VMSTATE_UINT32(fbrd, PL011State), 366 VMSTATE_UINT32(ifl, PL011State), 367 VMSTATE_INT32(read_pos, PL011State), 368 VMSTATE_INT32(read_count, PL011State), 369 VMSTATE_INT32(read_trigger, PL011State), 370 VMSTATE_END_OF_LIST() 371 }, 372 .subsections = (const VMStateDescription * []) { 373 &vmstate_pl011_clock, 374 NULL 375 } 376}; 377 378static Property pl011_properties[] = { 379 DEFINE_PROP_CHR("chardev", PL011State, chr), 380 DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true), 381 DEFINE_PROP_END_OF_LIST(), 382}; 383 384static void pl011_init(Object *obj) 385{ 386 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 387 PL011State *s = PL011(obj); 388 int i; 389 390 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000); 391 sysbus_init_mmio(sbd, &s->iomem); 392 for (i = 0; i < ARRAY_SIZE(s->irq); i++) { 393 sysbus_init_irq(sbd, &s->irq[i]); 394 } 395 396 s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s, 397 ClockUpdate); 398 399 s->read_trigger = 1; 400 s->ifl = 0x12; 401 s->cr = 0x300; 402 s->flags = 0x90; 403 404 s->id = pl011_id_arm; 405} 406 407static void pl011_realize(DeviceState *dev, Error **errp) 408{ 409 PL011State *s = PL011(dev); 410 411 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive, 412 pl011_event, NULL, s, NULL, true); 413} 414 415static void pl011_class_init(ObjectClass *oc, void *data) 416{ 417 DeviceClass *dc = DEVICE_CLASS(oc); 418 419 dc->realize = pl011_realize; 420 dc->vmsd = &vmstate_pl011; 421 device_class_set_props(dc, pl011_properties); 422} 423 424static const TypeInfo pl011_arm_info = { 425 .name = TYPE_PL011, 426 .parent = TYPE_SYS_BUS_DEVICE, 427 .instance_size = sizeof(PL011State), 428 .instance_init = pl011_init, 429 .class_init = pl011_class_init, 430}; 431 432static void pl011_luminary_init(Object *obj) 433{ 434 PL011State *s = PL011(obj); 435 436 s->id = pl011_id_luminary; 437} 438 439static const TypeInfo pl011_luminary_info = { 440 .name = TYPE_PL011_LUMINARY, 441 .parent = TYPE_PL011, 442 .instance_init = pl011_luminary_init, 443}; 444 445static void pl011_register_types(void) 446{ 447 type_register_static(&pl011_arm_info); 448 type_register_static(&pl011_luminary_info); 449} 450 451type_init(pl011_register_types)