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