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 "qapi/error.h" 23 #include "hw/char/pl011.h" 24 #include "hw/irq.h" 25 #include "hw/sysbus.h" 26 #include "hw/qdev-clock.h" 27 #include "hw/qdev-properties.h" 28 #include "hw/qdev-properties-system.h" 29 #include "migration/vmstate.h" 30 #include "chardev/char-fe.h" 31 #include "chardev/char-serial.h" 32 #include "qemu/log.h" 33 #include "qemu/module.h" 34 #include "trace.h" 35 36 DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr) 37 { 38 DeviceState *dev; 39 SysBusDevice *s; 40 41 dev = qdev_new("pl011"); 42 s = SYS_BUS_DEVICE(dev); 43 qdev_prop_set_chr(dev, "chardev", chr); 44 sysbus_realize_and_unref(s, &error_fatal); 45 sysbus_mmio_map(s, 0, addr); 46 sysbus_connect_irq(s, 0, irq); 47 48 return dev; 49 } 50 51 /* Flag Register, UARTFR */ 52 #define PL011_FLAG_RI 0x100 53 #define PL011_FLAG_TXFE 0x80 54 #define PL011_FLAG_RXFF 0x40 55 #define PL011_FLAG_TXFF 0x20 56 #define PL011_FLAG_RXFE 0x10 57 #define PL011_FLAG_DCD 0x04 58 #define PL011_FLAG_DSR 0x02 59 #define PL011_FLAG_CTS 0x01 60 61 /* Data Register, UARTDR */ 62 #define DR_BE (1 << 10) 63 64 /* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */ 65 #define INT_OE (1 << 10) 66 #define INT_BE (1 << 9) 67 #define INT_PE (1 << 8) 68 #define INT_FE (1 << 7) 69 #define INT_RT (1 << 6) 70 #define INT_TX (1 << 5) 71 #define INT_RX (1 << 4) 72 #define INT_DSR (1 << 3) 73 #define INT_DCD (1 << 2) 74 #define INT_CTS (1 << 1) 75 #define INT_RI (1 << 0) 76 #define INT_E (INT_OE | INT_BE | INT_PE | INT_FE) 77 #define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS) 78 79 /* Line Control Register, UARTLCR_H */ 80 #define LCR_FEN (1 << 4) 81 #define LCR_BRK (1 << 0) 82 83 /* Control Register, UARTCR */ 84 #define CR_OUT2 (1 << 13) 85 #define CR_OUT1 (1 << 12) 86 #define CR_RTS (1 << 11) 87 #define CR_DTR (1 << 10) 88 #define CR_RXE (1 << 9) 89 #define CR_TXE (1 << 8) 90 #define CR_LBE (1 << 7) 91 #define CR_UARTEN (1 << 0) 92 93 /* Integer Baud Rate Divider, UARTIBRD */ 94 #define IBRD_MASK 0xffff 95 96 /* Fractional Baud Rate Divider, UARTFBRD */ 97 #define FBRD_MASK 0x3f 98 99 static const unsigned char pl011_id_arm[8] = 100 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 101 static const unsigned char pl011_id_luminary[8] = 102 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; 103 104 static const char *pl011_regname(hwaddr offset) 105 { 106 static const char *const rname[] = { 107 [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD", 108 [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC", 109 [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR", 110 }; 111 unsigned idx = offset >> 2; 112 113 if (idx < ARRAY_SIZE(rname) && rname[idx]) { 114 return rname[idx]; 115 } 116 if (idx >= 0x3f8 && idx <= 0x400) { 117 return "ID"; 118 } 119 return "UNKN"; 120 } 121 122 /* Which bits in the interrupt status matter for each outbound IRQ line ? */ 123 static const uint32_t irqmask[] = { 124 INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */ 125 INT_RX, 126 INT_TX, 127 INT_RT, 128 INT_MS, 129 INT_E, 130 }; 131 132 static void pl011_update(PL011State *s) 133 { 134 uint32_t flags; 135 int i; 136 137 flags = s->int_level & s->int_enabled; 138 trace_pl011_irq_state(flags != 0); 139 for (i = 0; i < ARRAY_SIZE(s->irq); i++) { 140 qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0); 141 } 142 } 143 144 static bool pl011_loopback_enabled(PL011State *s) 145 { 146 return !!(s->cr & CR_LBE); 147 } 148 149 static bool pl011_is_fifo_enabled(PL011State *s) 150 { 151 return (s->lcr & LCR_FEN) != 0; 152 } 153 154 static inline unsigned pl011_get_fifo_depth(PL011State *s) 155 { 156 /* Note: FIFO depth is expected to be power-of-2 */ 157 return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1; 158 } 159 160 static inline void pl011_reset_rx_fifo(PL011State *s) 161 { 162 s->read_count = 0; 163 s->read_pos = 0; 164 165 /* Reset FIFO flags */ 166 s->flags &= ~PL011_FLAG_RXFF; 167 s->flags |= PL011_FLAG_RXFE; 168 } 169 170 static inline void pl011_reset_tx_fifo(PL011State *s) 171 { 172 /* Reset FIFO flags */ 173 s->flags &= ~PL011_FLAG_TXFF; 174 s->flags |= PL011_FLAG_TXFE; 175 } 176 177 static void pl011_fifo_rx_put(void *opaque, uint32_t value) 178 { 179 PL011State *s = (PL011State *)opaque; 180 int slot; 181 unsigned pipe_depth; 182 183 pipe_depth = pl011_get_fifo_depth(s); 184 slot = (s->read_pos + s->read_count) & (pipe_depth - 1); 185 s->read_fifo[slot] = value; 186 s->read_count++; 187 s->flags &= ~PL011_FLAG_RXFE; 188 trace_pl011_fifo_rx_put(value, s->read_count); 189 if (s->read_count == pipe_depth) { 190 trace_pl011_fifo_rx_full(); 191 s->flags |= PL011_FLAG_RXFF; 192 } 193 if (s->read_count == s->read_trigger) { 194 s->int_level |= INT_RX; 195 pl011_update(s); 196 } 197 } 198 199 static void pl011_loopback_tx(PL011State *s, uint32_t value) 200 { 201 if (!pl011_loopback_enabled(s)) { 202 return; 203 } 204 205 /* 206 * Caveat: 207 * 208 * In real hardware, TX loopback happens at the serial-bit level 209 * and then reassembled by the RX logics back into bytes and placed 210 * into the RX fifo. That is, loopback happens after TX fifo. 211 * 212 * Because the real hardware TX fifo is time-drained at the frame 213 * rate governed by the configured serial format, some loopback 214 * bytes in TX fifo may still be able to get into the RX fifo 215 * that could be full at times while being drained at software 216 * pace. 217 * 218 * In such scenario, the RX draining pace is the major factor 219 * deciding which loopback bytes get into the RX fifo, unless 220 * hardware flow-control is enabled. 221 * 222 * For simplicity, the above described is not emulated. 223 */ 224 pl011_fifo_rx_put(s, value); 225 } 226 227 static void pl011_write_txdata(PL011State *s, uint8_t data) 228 { 229 if (!(s->cr & CR_UARTEN)) { 230 qemu_log_mask(LOG_GUEST_ERROR, 231 "PL011 data written to disabled UART\n"); 232 } 233 if (!(s->cr & CR_TXE)) { 234 qemu_log_mask(LOG_GUEST_ERROR, 235 "PL011 data written to disabled TX UART\n"); 236 } 237 238 /* 239 * XXX this blocks entire thread. Rewrite to use 240 * qemu_chr_fe_write and background I/O callbacks 241 */ 242 qemu_chr_fe_write_all(&s->chr, &data, 1); 243 pl011_loopback_tx(s, data); 244 s->int_level |= INT_TX; 245 pl011_update(s); 246 } 247 248 static uint32_t pl011_read_rxdata(PL011State *s) 249 { 250 uint32_t c; 251 252 s->flags &= ~PL011_FLAG_RXFF; 253 c = s->read_fifo[s->read_pos]; 254 if (s->read_count > 0) { 255 s->read_count--; 256 s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1); 257 } 258 if (s->read_count == 0) { 259 s->flags |= PL011_FLAG_RXFE; 260 } 261 if (s->read_count == s->read_trigger - 1) { 262 s->int_level &= ~INT_RX; 263 } 264 trace_pl011_read_fifo(s->read_count); 265 s->rsr = c >> 8; 266 pl011_update(s); 267 qemu_chr_fe_accept_input(&s->chr); 268 return c; 269 } 270 271 static uint64_t pl011_read(void *opaque, hwaddr offset, 272 unsigned size) 273 { 274 PL011State *s = (PL011State *)opaque; 275 uint64_t r; 276 277 switch (offset >> 2) { 278 case 0: /* UARTDR */ 279 r = pl011_read_rxdata(s); 280 break; 281 case 1: /* UARTRSR */ 282 r = s->rsr; 283 break; 284 case 6: /* UARTFR */ 285 r = s->flags; 286 break; 287 case 8: /* UARTILPR */ 288 r = s->ilpr; 289 break; 290 case 9: /* UARTIBRD */ 291 r = s->ibrd; 292 break; 293 case 10: /* UARTFBRD */ 294 r = s->fbrd; 295 break; 296 case 11: /* UARTLCR_H */ 297 r = s->lcr; 298 break; 299 case 12: /* UARTCR */ 300 r = s->cr; 301 break; 302 case 13: /* UARTIFLS */ 303 r = s->ifl; 304 break; 305 case 14: /* UARTIMSC */ 306 r = s->int_enabled; 307 break; 308 case 15: /* UARTRIS */ 309 r = s->int_level; 310 break; 311 case 16: /* UARTMIS */ 312 r = s->int_level & s->int_enabled; 313 break; 314 case 18: /* UARTDMACR */ 315 r = s->dmacr; 316 break; 317 case 0x3f8 ... 0x400: 318 r = s->id[(offset - 0xfe0) >> 2]; 319 break; 320 default: 321 qemu_log_mask(LOG_GUEST_ERROR, 322 "pl011_read: Bad offset 0x%x\n", (int)offset); 323 r = 0; 324 break; 325 } 326 327 trace_pl011_read(offset, r, pl011_regname(offset)); 328 return r; 329 } 330 331 static void pl011_set_read_trigger(PL011State *s) 332 { 333 #if 0 334 /* The docs say the RX interrupt is triggered when the FIFO exceeds 335 the threshold. However linux only reads the FIFO in response to an 336 interrupt. Triggering the interrupt when the FIFO is non-empty seems 337 to make things work. */ 338 if (s->lcr & LCR_FEN) 339 s->read_trigger = (s->ifl >> 1) & 0x1c; 340 else 341 #endif 342 s->read_trigger = 1; 343 } 344 345 static unsigned int pl011_get_baudrate(const PL011State *s) 346 { 347 uint64_t clk; 348 349 if (s->ibrd == 0) { 350 return 0; 351 } 352 353 clk = clock_get_hz(s->clk); 354 return (clk / ((s->ibrd << 6) + s->fbrd)) << 2; 355 } 356 357 static void pl011_trace_baudrate_change(const PL011State *s) 358 { 359 trace_pl011_baudrate_change(pl011_get_baudrate(s), 360 clock_get_hz(s->clk), 361 s->ibrd, s->fbrd); 362 } 363 364 static void pl011_loopback_mdmctrl(PL011State *s) 365 { 366 uint32_t cr, fr, il; 367 368 if (!pl011_loopback_enabled(s)) { 369 return; 370 } 371 372 /* 373 * Loopback software-driven modem control outputs to modem status inputs: 374 * FR.RI <= CR.Out2 375 * FR.DCD <= CR.Out1 376 * FR.CTS <= CR.RTS 377 * FR.DSR <= CR.DTR 378 * 379 * The loopback happens immediately even if this call is triggered 380 * by setting only CR.LBE. 381 * 382 * CTS/RTS updates due to enabled hardware flow controls are not 383 * dealt with here. 384 */ 385 cr = s->cr; 386 fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD | 387 PL011_FLAG_DSR | PL011_FLAG_CTS); 388 fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0; 389 fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0; 390 fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0; 391 fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0; 392 393 /* Change interrupts based on updated FR */ 394 il = s->int_level & ~(INT_DSR | INT_DCD | INT_CTS | INT_RI); 395 il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0; 396 il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0; 397 il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0; 398 il |= (fr & PL011_FLAG_RI) ? INT_RI : 0; 399 400 s->flags = fr; 401 s->int_level = il; 402 pl011_update(s); 403 } 404 405 static void pl011_loopback_break(PL011State *s, int brk_enable) 406 { 407 if (brk_enable) { 408 pl011_loopback_tx(s, DR_BE); 409 } 410 } 411 412 static void pl011_write(void *opaque, hwaddr offset, 413 uint64_t value, unsigned size) 414 { 415 PL011State *s = (PL011State *)opaque; 416 unsigned char ch; 417 418 trace_pl011_write(offset, value, pl011_regname(offset)); 419 420 switch (offset >> 2) { 421 case 0: /* UARTDR */ 422 ch = value; 423 pl011_write_txdata(s, ch); 424 break; 425 case 1: /* UARTRSR/UARTECR */ 426 s->rsr = 0; 427 break; 428 case 6: /* UARTFR */ 429 /* Writes to Flag register are ignored. */ 430 break; 431 case 8: /* UARTILPR */ 432 s->ilpr = value; 433 break; 434 case 9: /* UARTIBRD */ 435 s->ibrd = value & IBRD_MASK; 436 pl011_trace_baudrate_change(s); 437 break; 438 case 10: /* UARTFBRD */ 439 s->fbrd = value & FBRD_MASK; 440 pl011_trace_baudrate_change(s); 441 break; 442 case 11: /* UARTLCR_H */ 443 /* Reset the FIFO state on FIFO enable or disable */ 444 if ((s->lcr ^ value) & LCR_FEN) { 445 pl011_reset_rx_fifo(s); 446 pl011_reset_tx_fifo(s); 447 } 448 if ((s->lcr ^ value) & LCR_BRK) { 449 int break_enable = value & LCR_BRK; 450 qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK, 451 &break_enable); 452 pl011_loopback_break(s, break_enable); 453 } 454 s->lcr = value; 455 pl011_set_read_trigger(s); 456 break; 457 case 12: /* UARTCR */ 458 /* ??? Need to implement the enable bit. */ 459 s->cr = value; 460 pl011_loopback_mdmctrl(s); 461 break; 462 case 13: /* UARTIFS */ 463 s->ifl = value; 464 pl011_set_read_trigger(s); 465 break; 466 case 14: /* UARTIMSC */ 467 s->int_enabled = value; 468 pl011_update(s); 469 break; 470 case 17: /* UARTICR */ 471 s->int_level &= ~value; 472 pl011_update(s); 473 break; 474 case 18: /* UARTDMACR */ 475 s->dmacr = value; 476 if (value & 3) { 477 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); 478 } 479 break; 480 default: 481 qemu_log_mask(LOG_GUEST_ERROR, 482 "pl011_write: Bad offset 0x%x\n", (int)offset); 483 } 484 } 485 486 static int pl011_can_receive(void *opaque) 487 { 488 PL011State *s = (PL011State *)opaque; 489 unsigned fifo_depth = pl011_get_fifo_depth(s); 490 unsigned fifo_available = fifo_depth - s->read_count; 491 int r = fifo_available ? 1 : 0; 492 493 if (!(s->cr & CR_UARTEN)) { 494 qemu_log_mask(LOG_GUEST_ERROR, 495 "PL011 receiving data on disabled UART\n"); 496 } 497 if (!(s->cr & CR_RXE)) { 498 qemu_log_mask(LOG_GUEST_ERROR, 499 "PL011 receiving data on disabled RX UART\n"); 500 } 501 trace_pl011_can_receive(s->lcr, s->read_count, r); 502 return r; 503 } 504 505 static void pl011_receive(void *opaque, const uint8_t *buf, int size) 506 { 507 /* 508 * In loopback mode, the RX input signal is internally disconnected 509 * from the entire receiving logics; thus, all inputs are ignored, 510 * and BREAK detection on RX input signal is also not performed. 511 */ 512 if (pl011_loopback_enabled(opaque)) { 513 return; 514 } 515 516 pl011_fifo_rx_put(opaque, *buf); 517 } 518 519 static void pl011_event(void *opaque, QEMUChrEvent event) 520 { 521 if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) { 522 pl011_fifo_rx_put(opaque, DR_BE); 523 } 524 } 525 526 static void pl011_clock_update(void *opaque, ClockEvent event) 527 { 528 PL011State *s = PL011(opaque); 529 530 pl011_trace_baudrate_change(s); 531 } 532 533 static const MemoryRegionOps pl011_ops = { 534 .read = pl011_read, 535 .write = pl011_write, 536 .endianness = DEVICE_NATIVE_ENDIAN, 537 .impl.min_access_size = 4, 538 .impl.max_access_size = 4, 539 }; 540 541 static bool pl011_clock_needed(void *opaque) 542 { 543 PL011State *s = PL011(opaque); 544 545 return s->migrate_clk; 546 } 547 548 static const VMStateDescription vmstate_pl011_clock = { 549 .name = "pl011/clock", 550 .version_id = 1, 551 .minimum_version_id = 1, 552 .needed = pl011_clock_needed, 553 .fields = (const VMStateField[]) { 554 VMSTATE_CLOCK(clk, PL011State), 555 VMSTATE_END_OF_LIST() 556 } 557 }; 558 559 static int pl011_post_load(void *opaque, int version_id) 560 { 561 PL011State* s = opaque; 562 563 /* Sanity-check input state */ 564 if (s->read_pos >= ARRAY_SIZE(s->read_fifo) || 565 s->read_count > ARRAY_SIZE(s->read_fifo)) { 566 return -1; 567 } 568 569 if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) { 570 /* 571 * Older versions of PL011 didn't ensure that the single 572 * character in the FIFO in FIFO-disabled mode is in 573 * element 0 of the array; convert to follow the current 574 * code's assumptions. 575 */ 576 s->read_fifo[0] = s->read_fifo[s->read_pos]; 577 s->read_pos = 0; 578 } 579 580 s->ibrd &= IBRD_MASK; 581 s->fbrd &= FBRD_MASK; 582 583 return 0; 584 } 585 586 static const VMStateDescription vmstate_pl011 = { 587 .name = "pl011", 588 .version_id = 2, 589 .minimum_version_id = 2, 590 .post_load = pl011_post_load, 591 .fields = (const VMStateField[]) { 592 VMSTATE_UNUSED(sizeof(uint32_t)), 593 VMSTATE_UINT32(flags, PL011State), 594 VMSTATE_UINT32(lcr, PL011State), 595 VMSTATE_UINT32(rsr, PL011State), 596 VMSTATE_UINT32(cr, PL011State), 597 VMSTATE_UINT32(dmacr, PL011State), 598 VMSTATE_UINT32(int_enabled, PL011State), 599 VMSTATE_UINT32(int_level, PL011State), 600 VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH), 601 VMSTATE_UINT32(ilpr, PL011State), 602 VMSTATE_UINT32(ibrd, PL011State), 603 VMSTATE_UINT32(fbrd, PL011State), 604 VMSTATE_UINT32(ifl, PL011State), 605 VMSTATE_INT32(read_pos, PL011State), 606 VMSTATE_INT32(read_count, PL011State), 607 VMSTATE_INT32(read_trigger, PL011State), 608 VMSTATE_END_OF_LIST() 609 }, 610 .subsections = (const VMStateDescription * const []) { 611 &vmstate_pl011_clock, 612 NULL 613 } 614 }; 615 616 static const Property pl011_properties[] = { 617 DEFINE_PROP_CHR("chardev", PL011State, chr), 618 DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true), 619 }; 620 621 static void pl011_init(Object *obj) 622 { 623 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 624 PL011State *s = PL011(obj); 625 int i; 626 627 memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000); 628 sysbus_init_mmio(sbd, &s->iomem); 629 for (i = 0; i < ARRAY_SIZE(s->irq); i++) { 630 sysbus_init_irq(sbd, &s->irq[i]); 631 } 632 633 s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s, 634 ClockUpdate); 635 636 s->id = pl011_id_arm; 637 } 638 639 static void pl011_realize(DeviceState *dev, Error **errp) 640 { 641 PL011State *s = PL011(dev); 642 643 qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive, 644 pl011_event, NULL, s, NULL, true); 645 } 646 647 static void pl011_reset(DeviceState *dev) 648 { 649 PL011State *s = PL011(dev); 650 651 s->lcr = 0; 652 s->rsr = 0; 653 s->dmacr = 0; 654 s->int_enabled = 0; 655 s->int_level = 0; 656 s->ilpr = 0; 657 s->ibrd = 0; 658 s->fbrd = 0; 659 s->read_trigger = 1; 660 s->ifl = 0x12; 661 s->cr = 0x300; 662 s->flags = 0; 663 pl011_reset_rx_fifo(s); 664 pl011_reset_tx_fifo(s); 665 } 666 667 static void pl011_class_init(ObjectClass *oc, void *data) 668 { 669 DeviceClass *dc = DEVICE_CLASS(oc); 670 671 dc->realize = pl011_realize; 672 device_class_set_legacy_reset(dc, pl011_reset); 673 dc->vmsd = &vmstate_pl011; 674 device_class_set_props(dc, pl011_properties); 675 } 676 677 static const TypeInfo pl011_arm_info = { 678 .name = TYPE_PL011, 679 .parent = TYPE_SYS_BUS_DEVICE, 680 .instance_size = sizeof(PL011State), 681 .instance_init = pl011_init, 682 .class_init = pl011_class_init, 683 }; 684 685 static void pl011_luminary_init(Object *obj) 686 { 687 PL011State *s = PL011(obj); 688 689 s->id = pl011_id_luminary; 690 } 691 692 static const TypeInfo pl011_luminary_info = { 693 .name = TYPE_PL011_LUMINARY, 694 .parent = TYPE_PL011, 695 .instance_init = pl011_luminary_init, 696 }; 697 698 static void pl011_register_types(void) 699 { 700 type_register_static(&pl011_arm_info); 701 type_register_static(&pl011_luminary_info); 702 } 703 704 type_init(pl011_register_types) 705