xref: /openbmc/qemu/hw/char/exynos4210_uart.c (revision c9d3396d)
1 /*
2  *  Exynos4210 UART Emulation
3  *
4  *  Copyright (C) 2011 Samsung Electronics Co Ltd.
5  *    Maksim Kozlov, <m.kozlov@samsung.com>
6  *
7  *  This program is free software; you can redistribute it and/or modify it
8  *  under the terms of the GNU General Public License as published by the
9  *  Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful, but WITHOUT
13  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15  *  for more details.
16  *
17  *  You should have received a copy of the GNU General Public License along
18  *  with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "qemu/osdep.h"
23 #include "hw/sysbus.h"
24 #include "migration/vmstate.h"
25 #include "qemu/error-report.h"
26 #include "qemu/module.h"
27 #include "chardev/char-fe.h"
28 #include "chardev/char-serial.h"
29 
30 #include "hw/arm/exynos4210.h"
31 #include "hw/irq.h"
32 #include "hw/qdev-properties.h"
33 
34 #include "trace.h"
35 
36 /*
37  *  Offsets for UART registers relative to SFR base address
38  *  for UARTn
39  *
40  */
41 #define ULCON      0x0000 /* Line Control             */
42 #define UCON       0x0004 /* Control                  */
43 #define UFCON      0x0008 /* FIFO Control             */
44 #define UMCON      0x000C /* Modem Control            */
45 #define UTRSTAT    0x0010 /* Tx/Rx Status             */
46 #define UERSTAT    0x0014 /* UART Error Status        */
47 #define UFSTAT     0x0018 /* FIFO Status              */
48 #define UMSTAT     0x001C /* Modem Status             */
49 #define UTXH       0x0020 /* Transmit Buffer          */
50 #define URXH       0x0024 /* Receive Buffer           */
51 #define UBRDIV     0x0028 /* Baud Rate Divisor        */
52 #define UFRACVAL   0x002C /* Divisor Fractional Value */
53 #define UINTP      0x0030 /* Interrupt Pending        */
54 #define UINTSP     0x0034 /* Interrupt Source Pending */
55 #define UINTM      0x0038 /* Interrupt Mask           */
56 
57 /*
58  * for indexing register in the uint32_t array
59  *
60  * 'reg' - register offset (see offsets definitions above)
61  *
62  */
63 #define I_(reg) (reg / sizeof(uint32_t))
64 
65 typedef struct Exynos4210UartReg {
66     const char         *name; /* the only reason is the debug output */
67     hwaddr  offset;
68     uint32_t            reset_value;
69 } Exynos4210UartReg;
70 
71 static const Exynos4210UartReg exynos4210_uart_regs[] = {
72     {"ULCON",    ULCON,    0x00000000},
73     {"UCON",     UCON,     0x00003000},
74     {"UFCON",    UFCON,    0x00000000},
75     {"UMCON",    UMCON,    0x00000000},
76     {"UTRSTAT",  UTRSTAT,  0x00000006}, /* RO */
77     {"UERSTAT",  UERSTAT,  0x00000000}, /* RO */
78     {"UFSTAT",   UFSTAT,   0x00000000}, /* RO */
79     {"UMSTAT",   UMSTAT,   0x00000000}, /* RO */
80     {"UTXH",     UTXH,     0x5c5c5c5c}, /* WO, undefined reset value*/
81     {"URXH",     URXH,     0x00000000}, /* RO */
82     {"UBRDIV",   UBRDIV,   0x00000000},
83     {"UFRACVAL", UFRACVAL, 0x00000000},
84     {"UINTP",    UINTP,    0x00000000},
85     {"UINTSP",   UINTSP,   0x00000000},
86     {"UINTM",    UINTM,    0x00000000},
87 };
88 
89 #define EXYNOS4210_UART_REGS_MEM_SIZE    0x3C
90 
91 /* UART FIFO Control */
92 #define UFCON_FIFO_ENABLE                    0x1
93 #define UFCON_Rx_FIFO_RESET                  0x2
94 #define UFCON_Tx_FIFO_RESET                  0x4
95 #define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT    8
96 #define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
97 #define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT    4
98 #define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
99 
100 /* Uart FIFO Status */
101 #define UFSTAT_Rx_FIFO_COUNT        0xff
102 #define UFSTAT_Rx_FIFO_FULL         0x100
103 #define UFSTAT_Rx_FIFO_ERROR        0x200
104 #define UFSTAT_Tx_FIFO_COUNT_SHIFT  16
105 #define UFSTAT_Tx_FIFO_COUNT        (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
106 #define UFSTAT_Tx_FIFO_FULL_SHIFT   24
107 #define UFSTAT_Tx_FIFO_FULL         (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
108 
109 /* UART Interrupt Source Pending */
110 #define UINTSP_RXD      0x1 /* Receive interrupt  */
111 #define UINTSP_ERROR    0x2 /* Error interrupt    */
112 #define UINTSP_TXD      0x4 /* Transmit interrupt */
113 #define UINTSP_MODEM    0x8 /* Modem interrupt    */
114 
115 /* UART Line Control */
116 #define ULCON_IR_MODE_SHIFT   6
117 #define ULCON_PARITY_SHIFT    3
118 #define ULCON_STOP_BIT_SHIFT  1
119 
120 /* UART Tx/Rx Status */
121 #define UTRSTAT_TRANSMITTER_EMPTY       0x4
122 #define UTRSTAT_Tx_BUFFER_EMPTY         0x2
123 #define UTRSTAT_Rx_BUFFER_DATA_READY    0x1
124 
125 /* UART Error Status */
126 #define UERSTAT_OVERRUN  0x1
127 #define UERSTAT_PARITY   0x2
128 #define UERSTAT_FRAME    0x4
129 #define UERSTAT_BREAK    0x8
130 
131 typedef struct {
132     uint8_t    *data;
133     uint32_t    sp, rp; /* store and retrieve pointers */
134     uint32_t    size;
135 } Exynos4210UartFIFO;
136 
137 #define TYPE_EXYNOS4210_UART "exynos4210.uart"
138 #define EXYNOS4210_UART(obj) \
139     OBJECT_CHECK(Exynos4210UartState, (obj), TYPE_EXYNOS4210_UART)
140 
141 typedef struct Exynos4210UartState {
142     SysBusDevice parent_obj;
143 
144     MemoryRegion iomem;
145 
146     uint32_t             reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
147     Exynos4210UartFIFO   rx;
148     Exynos4210UartFIFO   tx;
149 
150     CharBackend       chr;
151     qemu_irq          irq;
152 
153     uint32_t channel;
154 
155 } Exynos4210UartState;
156 
157 
158 /* Used only for tracing */
159 static const char *exynos4210_uart_regname(hwaddr  offset)
160 {
161 
162     int i;
163 
164     for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
165         if (offset == exynos4210_uart_regs[i].offset) {
166             return exynos4210_uart_regs[i].name;
167         }
168     }
169 
170     return NULL;
171 }
172 
173 
174 static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
175 {
176     q->data[q->sp] = ch;
177     q->sp = (q->sp + 1) % q->size;
178 }
179 
180 static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
181 {
182     uint8_t ret = q->data[q->rp];
183     q->rp = (q->rp + 1) % q->size;
184     return  ret;
185 }
186 
187 static int fifo_elements_number(const Exynos4210UartFIFO *q)
188 {
189     if (q->sp < q->rp) {
190         return q->size - q->rp + q->sp;
191     }
192 
193     return q->sp - q->rp;
194 }
195 
196 static int fifo_empty_elements_number(const Exynos4210UartFIFO *q)
197 {
198     return q->size - fifo_elements_number(q);
199 }
200 
201 static void fifo_reset(Exynos4210UartFIFO *q)
202 {
203     g_free(q->data);
204     q->data = NULL;
205 
206     q->data = (uint8_t *)g_malloc0(q->size);
207 
208     q->sp = 0;
209     q->rp = 0;
210 }
211 
212 static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
213 {
214     uint32_t level = 0;
215     uint32_t reg;
216 
217     reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
218             UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
219 
220     switch (s->channel) {
221     case 0:
222         level = reg * 32;
223         break;
224     case 1:
225     case 4:
226         level = reg * 8;
227         break;
228     case 2:
229     case 3:
230         level = reg * 2;
231         break;
232     default:
233         level = 0;
234         trace_exynos_uart_channel_error(s->channel);
235     }
236 
237     return level;
238 }
239 
240 static void exynos4210_uart_update_irq(Exynos4210UartState *s)
241 {
242     /*
243      * The Tx interrupt is always requested if the number of data in the
244      * transmit FIFO is smaller than the trigger level.
245      */
246     if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
247 
248         uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
249                 UFSTAT_Tx_FIFO_COUNT_SHIFT;
250 
251         if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
252             s->reg[I_(UINTSP)] |= UINTSP_TXD;
253         }
254     }
255 
256     s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
257 
258     if (s->reg[I_(UINTP)]) {
259         qemu_irq_raise(s->irq);
260         trace_exynos_uart_irq_raised(s->channel, s->reg[I_(UINTP)]);
261     } else {
262         qemu_irq_lower(s->irq);
263         trace_exynos_uart_irq_lowered(s->channel);
264     }
265 }
266 
267 static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
268 {
269     int speed, parity, data_bits, stop_bits;
270     QEMUSerialSetParams ssp;
271     uint64_t uclk_rate;
272 
273     if (s->reg[I_(UBRDIV)] == 0) {
274         return;
275     }
276 
277     if (s->reg[I_(ULCON)] & 0x20) {
278         if (s->reg[I_(ULCON)] & 0x28) {
279             parity = 'E';
280         } else {
281             parity = 'O';
282         }
283     } else {
284         parity = 'N';
285     }
286 
287     if (s->reg[I_(ULCON)] & 0x4) {
288         stop_bits = 2;
289     } else {
290         stop_bits = 1;
291     }
292 
293     data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
294 
295     uclk_rate = 24000000;
296 
297     speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
298             (s->reg[I_(UFRACVAL)] & 0x7) + 16);
299 
300     ssp.speed     = speed;
301     ssp.parity    = parity;
302     ssp.data_bits = data_bits;
303     ssp.stop_bits = stop_bits;
304 
305     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
306 
307     trace_exynos_uart_update_params(
308                 s->channel, speed, parity, data_bits, stop_bits);
309 }
310 
311 static void exynos4210_uart_write(void *opaque, hwaddr offset,
312                                uint64_t val, unsigned size)
313 {
314     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
315     uint8_t ch;
316 
317     trace_exynos_uart_write(s->channel, offset,
318                             exynos4210_uart_regname(offset), val);
319 
320     switch (offset) {
321     case ULCON:
322     case UBRDIV:
323     case UFRACVAL:
324         s->reg[I_(offset)] = val;
325         exynos4210_uart_update_parameters(s);
326         break;
327     case UFCON:
328         s->reg[I_(UFCON)] = val;
329         if (val & UFCON_Rx_FIFO_RESET) {
330             fifo_reset(&s->rx);
331             s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
332             trace_exynos_uart_rx_fifo_reset(s->channel);
333         }
334         if (val & UFCON_Tx_FIFO_RESET) {
335             fifo_reset(&s->tx);
336             s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
337             trace_exynos_uart_tx_fifo_reset(s->channel);
338         }
339         break;
340 
341     case UTXH:
342         if (qemu_chr_fe_backend_connected(&s->chr)) {
343             s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
344                     UTRSTAT_Tx_BUFFER_EMPTY);
345             ch = (uint8_t)val;
346             /* XXX this blocks entire thread. Rewrite to use
347              * qemu_chr_fe_write and background I/O callbacks */
348             qemu_chr_fe_write_all(&s->chr, &ch, 1);
349             trace_exynos_uart_tx(s->channel, ch);
350             s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
351                     UTRSTAT_Tx_BUFFER_EMPTY;
352             s->reg[I_(UINTSP)]  |= UINTSP_TXD;
353             exynos4210_uart_update_irq(s);
354         }
355         break;
356 
357     case UINTP:
358         s->reg[I_(UINTP)] &= ~val;
359         s->reg[I_(UINTSP)] &= ~val;
360         trace_exynos_uart_intclr(s->channel, s->reg[I_(UINTP)]);
361         exynos4210_uart_update_irq(s);
362         break;
363     case UTRSTAT:
364     case UERSTAT:
365     case UFSTAT:
366     case UMSTAT:
367     case URXH:
368         trace_exynos_uart_ro_write(
369                     s->channel, exynos4210_uart_regname(offset), offset);
370         break;
371     case UINTSP:
372         s->reg[I_(UINTSP)]  &= ~val;
373         break;
374     case UINTM:
375         s->reg[I_(UINTM)] = val;
376         exynos4210_uart_update_irq(s);
377         break;
378     case UCON:
379     case UMCON:
380     default:
381         s->reg[I_(offset)] = val;
382         break;
383     }
384 }
385 static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
386                                   unsigned size)
387 {
388     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
389     uint32_t res;
390 
391     switch (offset) {
392     case UERSTAT: /* Read Only */
393         res = s->reg[I_(UERSTAT)];
394         s->reg[I_(UERSTAT)] = 0;
395         trace_exynos_uart_read(s->channel, offset,
396                                exynos4210_uart_regname(offset), res);
397         return res;
398     case UFSTAT: /* Read Only */
399         s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
400         if (fifo_empty_elements_number(&s->rx) == 0) {
401             s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
402             s->reg[I_(UFSTAT)] &= ~0xff;
403         }
404         trace_exynos_uart_read(s->channel, offset,
405                                exynos4210_uart_regname(offset),
406                                s->reg[I_(UFSTAT)]);
407         return s->reg[I_(UFSTAT)];
408     case URXH:
409         if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
410             if (fifo_elements_number(&s->rx)) {
411                 res = fifo_retrieve(&s->rx);
412                 trace_exynos_uart_rx(s->channel, res);
413                 if (!fifo_elements_number(&s->rx)) {
414                     s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
415                 } else {
416                     s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
417                 }
418             } else {
419                 trace_exynos_uart_rx_error(s->channel);
420                 s->reg[I_(UINTSP)] |= UINTSP_ERROR;
421                 exynos4210_uart_update_irq(s);
422                 res = 0;
423             }
424         } else {
425             s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
426             res = s->reg[I_(URXH)];
427         }
428         trace_exynos_uart_read(s->channel, offset,
429                                exynos4210_uart_regname(offset), res);
430         return res;
431     case UTXH:
432         trace_exynos_uart_wo_read(s->channel, exynos4210_uart_regname(offset),
433                                   offset);
434         break;
435     default:
436         trace_exynos_uart_read(s->channel, offset,
437                                exynos4210_uart_regname(offset),
438                                s->reg[I_(offset)]);
439         return s->reg[I_(offset)];
440     }
441 
442     trace_exynos_uart_read(s->channel, offset, exynos4210_uart_regname(offset),
443                            0);
444     return 0;
445 }
446 
447 static const MemoryRegionOps exynos4210_uart_ops = {
448     .read = exynos4210_uart_read,
449     .write = exynos4210_uart_write,
450     .endianness = DEVICE_NATIVE_ENDIAN,
451     .valid = {
452         .max_access_size = 4,
453         .unaligned = false
454     },
455 };
456 
457 static int exynos4210_uart_can_receive(void *opaque)
458 {
459     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
460 
461     return fifo_empty_elements_number(&s->rx);
462 }
463 
464 
465 static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
466 {
467     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
468     int i;
469 
470     if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
471         if (fifo_empty_elements_number(&s->rx) < size) {
472             for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
473                 fifo_store(&s->rx, buf[i]);
474             }
475             s->reg[I_(UINTSP)] |= UINTSP_ERROR;
476             s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
477         } else {
478             for (i = 0; i < size; i++) {
479                 fifo_store(&s->rx, buf[i]);
480             }
481             s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
482         }
483         /* XXX: Around here we maybe should check Rx trigger level */
484         s->reg[I_(UINTSP)] |= UINTSP_RXD;
485     } else {
486         s->reg[I_(URXH)] = buf[0];
487         s->reg[I_(UINTSP)] |= UINTSP_RXD;
488         s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
489     }
490 
491     exynos4210_uart_update_irq(s);
492 }
493 
494 
495 static void exynos4210_uart_event(void *opaque, QEMUChrEvent event)
496 {
497     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
498 
499     if (event == CHR_EVENT_BREAK) {
500         /* When the RxDn is held in logic 0, then a null byte is pushed into the
501          * fifo */
502         fifo_store(&s->rx, '\0');
503         s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
504         exynos4210_uart_update_irq(s);
505     }
506 }
507 
508 
509 static void exynos4210_uart_reset(DeviceState *dev)
510 {
511     Exynos4210UartState *s = EXYNOS4210_UART(dev);
512     int i;
513 
514     for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
515         s->reg[I_(exynos4210_uart_regs[i].offset)] =
516                 exynos4210_uart_regs[i].reset_value;
517     }
518 
519     fifo_reset(&s->rx);
520     fifo_reset(&s->tx);
521 
522     trace_exynos_uart_rxsize(s->channel, s->rx.size);
523 }
524 
525 static int exynos4210_uart_post_load(void *opaque, int version_id)
526 {
527     Exynos4210UartState *s = (Exynos4210UartState *)opaque;
528 
529     exynos4210_uart_update_parameters(s);
530 
531     return 0;
532 }
533 
534 static const VMStateDescription vmstate_exynos4210_uart_fifo = {
535     .name = "exynos4210.uart.fifo",
536     .version_id = 1,
537     .minimum_version_id = 1,
538     .post_load = exynos4210_uart_post_load,
539     .fields = (VMStateField[]) {
540         VMSTATE_UINT32(sp, Exynos4210UartFIFO),
541         VMSTATE_UINT32(rp, Exynos4210UartFIFO),
542         VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, size),
543         VMSTATE_END_OF_LIST()
544     }
545 };
546 
547 static const VMStateDescription vmstate_exynos4210_uart = {
548     .name = "exynos4210.uart",
549     .version_id = 1,
550     .minimum_version_id = 1,
551     .fields = (VMStateField[]) {
552         VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
553                        vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
554         VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
555                              EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
556         VMSTATE_END_OF_LIST()
557     }
558 };
559 
560 DeviceState *exynos4210_uart_create(hwaddr addr,
561                                     int fifo_size,
562                                     int channel,
563                                     Chardev *chr,
564                                     qemu_irq irq)
565 {
566     DeviceState  *dev;
567     SysBusDevice *bus;
568 
569     dev = qdev_create(NULL, TYPE_EXYNOS4210_UART);
570 
571     qdev_prop_set_chr(dev, "chardev", chr);
572     qdev_prop_set_uint32(dev, "channel", channel);
573     qdev_prop_set_uint32(dev, "rx-size", fifo_size);
574     qdev_prop_set_uint32(dev, "tx-size", fifo_size);
575 
576     bus = SYS_BUS_DEVICE(dev);
577     qdev_init_nofail(dev);
578     if (addr != (hwaddr)-1) {
579         sysbus_mmio_map(bus, 0, addr);
580     }
581     sysbus_connect_irq(bus, 0, irq);
582 
583     return dev;
584 }
585 
586 static void exynos4210_uart_init(Object *obj)
587 {
588     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
589     Exynos4210UartState *s = EXYNOS4210_UART(dev);
590 
591     /* memory mapping */
592     memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
593                           "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
594     sysbus_init_mmio(dev, &s->iomem);
595 
596     sysbus_init_irq(dev, &s->irq);
597 }
598 
599 static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
600 {
601     Exynos4210UartState *s = EXYNOS4210_UART(dev);
602 
603     qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
604                              exynos4210_uart_receive, exynos4210_uart_event,
605                              NULL, s, NULL, true);
606 }
607 
608 static Property exynos4210_uart_properties[] = {
609     DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
610     DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
611     DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
612     DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
613     DEFINE_PROP_END_OF_LIST(),
614 };
615 
616 static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
617 {
618     DeviceClass *dc = DEVICE_CLASS(klass);
619 
620     dc->realize = exynos4210_uart_realize;
621     dc->reset = exynos4210_uart_reset;
622     dc->props = exynos4210_uart_properties;
623     dc->vmsd = &vmstate_exynos4210_uart;
624 }
625 
626 static const TypeInfo exynos4210_uart_info = {
627     .name          = TYPE_EXYNOS4210_UART,
628     .parent        = TYPE_SYS_BUS_DEVICE,
629     .instance_size = sizeof(Exynos4210UartState),
630     .instance_init = exynos4210_uart_init,
631     .class_init    = exynos4210_uart_class_init,
632 };
633 
634 static void exynos4210_uart_register(void)
635 {
636     type_register_static(&exynos4210_uart_info);
637 }
638 
639 type_init(exynos4210_uart_register)
640