xref: /qemu/hw/char/sh_serial.c (revision beeb520925d54f5c69c66656a96dc68de0eec9a4)
12f062c72Sths /*
22f062c72Sths  * QEMU SCI/SCIF serial port emulation
32f062c72Sths  *
42f062c72Sths  * Copyright (c) 2007 Magnus Damm
52f062c72Sths  *
62f062c72Sths  * Based on serial.c - QEMU 16450 UART emulation
72f062c72Sths  * Copyright (c) 2003-2004 Fabrice Bellard
82f062c72Sths  *
92f062c72Sths  * Permission is hereby granted, free of charge, to any person obtaining a copy
102f062c72Sths  * of this software and associated documentation files (the "Software"), to deal
112f062c72Sths  * in the Software without restriction, including without limitation the rights
122f062c72Sths  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
132f062c72Sths  * copies of the Software, and to permit persons to whom the Software is
142f062c72Sths  * furnished to do so, subject to the following conditions:
152f062c72Sths  *
162f062c72Sths  * The above copyright notice and this permission notice shall be included in
172f062c72Sths  * all copies or substantial portions of the Software.
182f062c72Sths  *
192f062c72Sths  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
202f062c72Sths  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
212f062c72Sths  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
222f062c72Sths  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
232f062c72Sths  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
242f062c72Sths  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
252f062c72Sths  * THE SOFTWARE.
262f062c72Sths  */
2764552b6bSMarkus Armbruster 
280430891cSPeter Maydell #include "qemu/osdep.h"
29*beeb5209SBALATON Zoltan #include "hw/sysbus.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
31*beeb5209SBALATON Zoltan #include "hw/qdev-core.h"
32*beeb5209SBALATON Zoltan #include "hw/qdev-properties.h"
33*beeb5209SBALATON Zoltan #include "hw/qdev-properties-system.h"
340d09e41aSPaolo Bonzini #include "hw/sh4/sh.h"
354d43a603SMarc-André Lureau #include "chardev/char-fe.h"
3632a6ebecSMarc-André Lureau #include "qapi/error.h"
3771bb4ce1SGeert Uytterhoeven #include "qemu/timer.h"
383cf7ce43SBALATON Zoltan #include "qemu/log.h"
39ad52cfc1SBALATON Zoltan #include "trace.h"
402f062c72Sths 
412f062c72Sths #define SH_SERIAL_FLAG_TEND (1 << 0)
422f062c72Sths #define SH_SERIAL_FLAG_TDE  (1 << 1)
432f062c72Sths #define SH_SERIAL_FLAG_RDF  (1 << 2)
442f062c72Sths #define SH_SERIAL_FLAG_BRK  (1 << 3)
452f062c72Sths #define SH_SERIAL_FLAG_DR   (1 << 4)
462f062c72Sths 
4763242a00Saurel32 #define SH_RX_FIFO_LENGTH (16)
4863242a00Saurel32 
49*beeb5209SBALATON Zoltan OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
50*beeb5209SBALATON Zoltan 
51*beeb5209SBALATON Zoltan struct SHSerialState {
52*beeb5209SBALATON Zoltan     SysBusDevice parent;
532f062c72Sths     uint8_t smr;
542f062c72Sths     uint8_t brr;
552f062c72Sths     uint8_t scr;
562f062c72Sths     uint8_t dr; /* ftdr / tdr */
572f062c72Sths     uint8_t sr; /* fsr / ssr */
582f062c72Sths     uint16_t fcr;
592f062c72Sths     uint8_t sptr;
602f062c72Sths 
6163242a00Saurel32     uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
622f062c72Sths     uint8_t rx_cnt;
6363242a00Saurel32     uint8_t rx_tail;
6463242a00Saurel32     uint8_t rx_head;
652f062c72Sths 
66*beeb5209SBALATON Zoltan     uint8_t feat;
672f062c72Sths     int flags;
6863242a00Saurel32     int rtrg;
692f062c72Sths 
7032a6ebecSMarc-André Lureau     CharBackend chr;
715b344b02SBALATON Zoltan     QEMUTimer fifo_timeout_timer;
7271bb4ce1SGeert Uytterhoeven     uint64_t etu; /* Elementary Time Unit (ns) */
73bf5b7423Saurel32 
744e7ed2d1Saurel32     qemu_irq eri;
754e7ed2d1Saurel32     qemu_irq rxi;
764e7ed2d1Saurel32     qemu_irq txi;
774e7ed2d1Saurel32     qemu_irq tei;
784e7ed2d1Saurel32     qemu_irq bri;
79*beeb5209SBALATON Zoltan };
80*beeb5209SBALATON Zoltan 
81*beeb5209SBALATON Zoltan typedef struct {} SHSerialStateClass;
82*beeb5209SBALATON Zoltan 
83*beeb5209SBALATON Zoltan OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
842f062c72Sths 
852f6df137SBALATON Zoltan static void sh_serial_clear_fifo(SHSerialState *s)
8663242a00Saurel32 {
8763242a00Saurel32     memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
8863242a00Saurel32     s->rx_cnt = 0;
8963242a00Saurel32     s->rx_head = 0;
9063242a00Saurel32     s->rx_tail = 0;
9163242a00Saurel32 }
9263242a00Saurel32 
93a8170e5eSAvi Kivity static void sh_serial_write(void *opaque, hwaddr offs,
949a9d0b81SBenoît Canet                             uint64_t val, unsigned size)
952f062c72Sths {
962f6df137SBALATON Zoltan     SHSerialState *s = opaque;
972f062c72Sths     unsigned char ch;
982f062c72Sths 
99ad52cfc1SBALATON Zoltan     trace_sh_serial_write(size, offs, val);
1002f062c72Sths     switch (offs) {
1012f062c72Sths     case 0x00: /* SMR */
1022f062c72Sths         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
1032f062c72Sths         return;
1042f062c72Sths     case 0x04: /* BRR */
1052f062c72Sths         s->brr = val;
1062f062c72Sths         return;
1072f062c72Sths     case 0x08: /* SCR */
10863242a00Saurel32         /* TODO : For SH7751, SCIF mask should be 0xfb. */
109bf5b7423Saurel32         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
110ac3c9e74SBALATON Zoltan         if (!(val & (1 << 5))) {
1112f062c72Sths             s->flags |= SH_SERIAL_FLAG_TEND;
112ac3c9e74SBALATON Zoltan         }
113bf5b7423Saurel32         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
1144e7ed2d1Saurel32             qemu_set_irq(s->txi, val & (1 << 7));
115bf5b7423Saurel32         }
1164e7ed2d1Saurel32         if (!(val & (1 << 6))) {
1174e7ed2d1Saurel32             qemu_set_irq(s->rxi, 0);
11863242a00Saurel32         }
1192f062c72Sths         return;
1202f062c72Sths     case 0x0c: /* FTDR / TDR */
12130650701SAnton Nefedov         if (qemu_chr_fe_backend_connected(&s->chr)) {
1222f062c72Sths             ch = val;
12322138965SBALATON Zoltan             /*
12422138965SBALATON Zoltan              * XXX this blocks entire thread. Rewrite to use
12522138965SBALATON Zoltan              * qemu_chr_fe_write and background I/O callbacks
12622138965SBALATON Zoltan              */
1275345fdb4SMarc-André Lureau             qemu_chr_fe_write_all(&s->chr, &ch, 1);
1282f062c72Sths         }
1292f062c72Sths         s->dr = val;
1302f062c72Sths         s->flags &= ~SH_SERIAL_FLAG_TDE;
1312f062c72Sths         return;
1322f062c72Sths #if 0
1332f062c72Sths     case 0x14: /* FRDR / RDR */
1342f062c72Sths         ret = 0;
1352f062c72Sths         break;
1362f062c72Sths #endif
1372f062c72Sths     }
1382f062c72Sths     if (s->feat & SH_SERIAL_FEAT_SCIF) {
1392f062c72Sths         switch (offs) {
1402f062c72Sths         case 0x10: /* FSR */
141ac3c9e74SBALATON Zoltan             if (!(val & (1 << 6))) {
1422f062c72Sths                 s->flags &= ~SH_SERIAL_FLAG_TEND;
143ac3c9e74SBALATON Zoltan             }
144ac3c9e74SBALATON Zoltan             if (!(val & (1 << 5))) {
1452f062c72Sths                 s->flags &= ~SH_SERIAL_FLAG_TDE;
146ac3c9e74SBALATON Zoltan             }
147ac3c9e74SBALATON Zoltan             if (!(val & (1 << 4))) {
1482f062c72Sths                 s->flags &= ~SH_SERIAL_FLAG_BRK;
149ac3c9e74SBALATON Zoltan             }
150ac3c9e74SBALATON Zoltan             if (!(val & (1 << 1))) {
1512f062c72Sths                 s->flags &= ~SH_SERIAL_FLAG_RDF;
152ac3c9e74SBALATON Zoltan             }
153ac3c9e74SBALATON Zoltan             if (!(val & (1 << 0))) {
1542f062c72Sths                 s->flags &= ~SH_SERIAL_FLAG_DR;
155ac3c9e74SBALATON Zoltan             }
15663242a00Saurel32 
15763242a00Saurel32             if (!(val & (1 << 1)) || !(val & (1 << 0))) {
1584e7ed2d1Saurel32                 if (s->rxi) {
1594e7ed2d1Saurel32                     qemu_set_irq(s->rxi, 0);
16063242a00Saurel32                 }
16163242a00Saurel32             }
1622f062c72Sths             return;
1632f062c72Sths         case 0x18: /* FCR */
1642f062c72Sths             s->fcr = val;
16563242a00Saurel32             switch ((val >> 6) & 3) {
16663242a00Saurel32             case 0:
16763242a00Saurel32                 s->rtrg = 1;
16863242a00Saurel32                 break;
16963242a00Saurel32             case 1:
17063242a00Saurel32                 s->rtrg = 4;
17163242a00Saurel32                 break;
17263242a00Saurel32             case 2:
17363242a00Saurel32                 s->rtrg = 8;
17463242a00Saurel32                 break;
17563242a00Saurel32             case 3:
17663242a00Saurel32                 s->rtrg = 14;
17763242a00Saurel32                 break;
17863242a00Saurel32             }
17963242a00Saurel32             if (val & (1 << 1)) {
18063242a00Saurel32                 sh_serial_clear_fifo(s);
18163242a00Saurel32                 s->sr &= ~(1 << 1);
18263242a00Saurel32             }
18363242a00Saurel32 
1842f062c72Sths             return;
1852f062c72Sths         case 0x20: /* SPTR */
18663242a00Saurel32             s->sptr = val & 0xf3;
1872f062c72Sths             return;
1882f062c72Sths         case 0x24: /* LSR */
1892f062c72Sths             return;
1902f062c72Sths         }
191f94bff13SBALATON Zoltan     } else {
1922f062c72Sths         switch (offs) {
193d1f193b0Saurel32 #if 0
1942f062c72Sths         case 0x0c:
1952f062c72Sths             ret = s->dr;
1962f062c72Sths             break;
1972f062c72Sths         case 0x10:
1982f062c72Sths             ret = 0;
1992f062c72Sths             break;
2002f062c72Sths #endif
201d1f193b0Saurel32         case 0x1c:
202d1f193b0Saurel32             s->sptr = val & 0x8f;
203d1f193b0Saurel32             return;
204d1f193b0Saurel32         }
2052f062c72Sths     }
2063cf7ce43SBALATON Zoltan     qemu_log_mask(LOG_GUEST_ERROR,
2073cf7ce43SBALATON Zoltan                   "%s: unsupported write to 0x%02" HWADDR_PRIx "\n",
2083cf7ce43SBALATON Zoltan                   __func__, offs);
2092f062c72Sths }
2102f062c72Sths 
211a8170e5eSAvi Kivity static uint64_t sh_serial_read(void *opaque, hwaddr offs,
2129a9d0b81SBenoît Canet                                unsigned size)
2132f062c72Sths {
2142f6df137SBALATON Zoltan     SHSerialState *s = opaque;
2153cf7ce43SBALATON Zoltan     uint32_t ret = UINT32_MAX;
2162f062c72Sths 
2172f062c72Sths #if 0
2182f062c72Sths     switch (offs) {
2192f062c72Sths     case 0x00:
2202f062c72Sths         ret = s->smr;
2212f062c72Sths         break;
2222f062c72Sths     case 0x04:
2232f062c72Sths         ret = s->brr;
2242f062c72Sths         break;
2252f062c72Sths     case 0x08:
2262f062c72Sths         ret = s->scr;
2272f062c72Sths         break;
2282f062c72Sths     case 0x14:
2292f062c72Sths         ret = 0;
2302f062c72Sths         break;
2312f062c72Sths     }
2322f062c72Sths #endif
2332f062c72Sths     if (s->feat & SH_SERIAL_FEAT_SCIF) {
2342f062c72Sths         switch (offs) {
235bf5b7423Saurel32         case 0x00: /* SMR */
236bf5b7423Saurel32             ret = s->smr;
237bf5b7423Saurel32             break;
238bf5b7423Saurel32         case 0x08: /* SCR */
239bf5b7423Saurel32             ret = s->scr;
240bf5b7423Saurel32             break;
2412f062c72Sths         case 0x10: /* FSR */
2422f062c72Sths             ret = 0;
243ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_TEND) {
2442f062c72Sths                 ret |= (1 << 6);
245ac3c9e74SBALATON Zoltan             }
246ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_TDE) {
2472f062c72Sths                 ret |= (1 << 5);
248ac3c9e74SBALATON Zoltan             }
249ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_BRK) {
2502f062c72Sths                 ret |= (1 << 4);
251ac3c9e74SBALATON Zoltan             }
252ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_RDF) {
2532f062c72Sths                 ret |= (1 << 1);
254ac3c9e74SBALATON Zoltan             }
255ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_DR) {
2562f062c72Sths                 ret |= (1 << 0);
257ac3c9e74SBALATON Zoltan             }
2582f062c72Sths 
259ac3c9e74SBALATON Zoltan             if (s->scr & (1 << 5)) {
2602f062c72Sths                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
261ac3c9e74SBALATON Zoltan             }
2622f062c72Sths 
2632f062c72Sths             break;
26463242a00Saurel32         case 0x14:
26563242a00Saurel32             if (s->rx_cnt > 0) {
26663242a00Saurel32                 ret = s->rx_fifo[s->rx_tail++];
26763242a00Saurel32                 s->rx_cnt--;
268ac3c9e74SBALATON Zoltan                 if (s->rx_tail == SH_RX_FIFO_LENGTH) {
26963242a00Saurel32                     s->rx_tail = 0;
270ac3c9e74SBALATON Zoltan                 }
271ac3c9e74SBALATON Zoltan                 if (s->rx_cnt < s->rtrg) {
27263242a00Saurel32                     s->flags &= ~SH_SERIAL_FLAG_RDF;
27363242a00Saurel32                 }
274ac3c9e74SBALATON Zoltan             }
27563242a00Saurel32             break;
2762f062c72Sths         case 0x18:
2772f062c72Sths             ret = s->fcr;
2782f062c72Sths             break;
2792f062c72Sths         case 0x1c:
2802f062c72Sths             ret = s->rx_cnt;
2812f062c72Sths             break;
2822f062c72Sths         case 0x20:
2832f062c72Sths             ret = s->sptr;
2842f062c72Sths             break;
2852f062c72Sths         case 0x24:
2862f062c72Sths             ret = 0;
2872f062c72Sths             break;
2882f062c72Sths         }
289f94bff13SBALATON Zoltan     } else {
2902f062c72Sths         switch (offs) {
291d1f193b0Saurel32 #if 0
2922f062c72Sths         case 0x0c:
2932f062c72Sths             ret = s->dr;
2942f062c72Sths             break;
2952f062c72Sths         case 0x10:
2962f062c72Sths             ret = 0;
2972f062c72Sths             break;
29863242a00Saurel32         case 0x14:
29963242a00Saurel32             ret = s->rx_fifo[0];
30063242a00Saurel32             break;
301d1f193b0Saurel32 #endif
3022f062c72Sths         case 0x1c:
3032f062c72Sths             ret = s->sptr;
3042f062c72Sths             break;
3052f062c72Sths         }
3062f062c72Sths     }
307ad52cfc1SBALATON Zoltan     trace_sh_serial_read(size, offs, ret);
3082f062c72Sths 
3093cf7ce43SBALATON Zoltan     if (ret > UINT16_MAX) {
3103cf7ce43SBALATON Zoltan         qemu_log_mask(LOG_GUEST_ERROR,
3113cf7ce43SBALATON Zoltan                       "%s: unsupported read from 0x%02" HWADDR_PRIx "\n",
3123cf7ce43SBALATON Zoltan                       __func__, offs);
3133cf7ce43SBALATON Zoltan         ret = 0;
3142f062c72Sths     }
3152f062c72Sths 
3162f062c72Sths     return ret;
3172f062c72Sths }
3182f062c72Sths 
3192f6df137SBALATON Zoltan static int sh_serial_can_receive(SHSerialState *s)
3202f062c72Sths {
32163242a00Saurel32     return s->scr & (1 << 4);
3222f062c72Sths }
3232f062c72Sths 
3242f6df137SBALATON Zoltan static void sh_serial_receive_break(SHSerialState *s)
3252f062c72Sths {
326ac3c9e74SBALATON Zoltan     if (s->feat & SH_SERIAL_FEAT_SCIF) {
32763242a00Saurel32         s->sr |= (1 << 4);
3282f062c72Sths     }
329ac3c9e74SBALATON Zoltan }
3302f062c72Sths 
3312f062c72Sths static int sh_serial_can_receive1(void *opaque)
3322f062c72Sths {
3332f6df137SBALATON Zoltan     SHSerialState *s = opaque;
3342f062c72Sths     return sh_serial_can_receive(s);
3352f062c72Sths }
3362f062c72Sths 
33771bb4ce1SGeert Uytterhoeven static void sh_serial_timeout_int(void *opaque)
33871bb4ce1SGeert Uytterhoeven {
3392f6df137SBALATON Zoltan     SHSerialState *s = opaque;
34071bb4ce1SGeert Uytterhoeven 
34171bb4ce1SGeert Uytterhoeven     s->flags |= SH_SERIAL_FLAG_RDF;
34271bb4ce1SGeert Uytterhoeven     if (s->scr & (1 << 6) && s->rxi) {
34371bb4ce1SGeert Uytterhoeven         qemu_set_irq(s->rxi, 1);
34471bb4ce1SGeert Uytterhoeven     }
34571bb4ce1SGeert Uytterhoeven }
34671bb4ce1SGeert Uytterhoeven 
3472f062c72Sths static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
3482f062c72Sths {
3492f6df137SBALATON Zoltan     SHSerialState *s = opaque;
350b7d2b020SAurelien Jarno 
351b7d2b020SAurelien Jarno     if (s->feat & SH_SERIAL_FEAT_SCIF) {
352b7d2b020SAurelien Jarno         int i;
353b7d2b020SAurelien Jarno         for (i = 0; i < size; i++) {
354b7d2b020SAurelien Jarno             if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
355b7d2b020SAurelien Jarno                 s->rx_fifo[s->rx_head++] = buf[i];
356b7d2b020SAurelien Jarno                 if (s->rx_head == SH_RX_FIFO_LENGTH) {
357b7d2b020SAurelien Jarno                     s->rx_head = 0;
358b7d2b020SAurelien Jarno                 }
359b7d2b020SAurelien Jarno                 s->rx_cnt++;
360b7d2b020SAurelien Jarno                 if (s->rx_cnt >= s->rtrg) {
361b7d2b020SAurelien Jarno                     s->flags |= SH_SERIAL_FLAG_RDF;
362b7d2b020SAurelien Jarno                     if (s->scr & (1 << 6) && s->rxi) {
3635b344b02SBALATON Zoltan                         timer_del(&s->fifo_timeout_timer);
364b7d2b020SAurelien Jarno                         qemu_set_irq(s->rxi, 1);
365b7d2b020SAurelien Jarno                     }
36671bb4ce1SGeert Uytterhoeven                 } else {
3675b344b02SBALATON Zoltan                     timer_mod(&s->fifo_timeout_timer,
36871bb4ce1SGeert Uytterhoeven                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
369b7d2b020SAurelien Jarno                 }
370b7d2b020SAurelien Jarno             }
371b7d2b020SAurelien Jarno         }
372b7d2b020SAurelien Jarno     } else {
373b7d2b020SAurelien Jarno         s->rx_fifo[0] = buf[0];
374b7d2b020SAurelien Jarno     }
3752f062c72Sths }
3762f062c72Sths 
377083b266fSPhilippe Mathieu-Daudé static void sh_serial_event(void *opaque, QEMUChrEvent event)
3782f062c72Sths {
3792f6df137SBALATON Zoltan     SHSerialState *s = opaque;
380ac3c9e74SBALATON Zoltan     if (event == CHR_EVENT_BREAK) {
3812f062c72Sths         sh_serial_receive_break(s);
3822f062c72Sths     }
383ac3c9e74SBALATON Zoltan }
3842f062c72Sths 
3859a9d0b81SBenoît Canet static const MemoryRegionOps sh_serial_ops = {
3869a9d0b81SBenoît Canet     .read = sh_serial_read,
3879a9d0b81SBenoît Canet     .write = sh_serial_write,
3889a9d0b81SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
3892f062c72Sths };
3902f062c72Sths 
391*beeb5209SBALATON Zoltan static void sh_serial_reset(DeviceState *dev)
392017f77bbSBALATON Zoltan {
393*beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(dev);
394*beeb5209SBALATON Zoltan 
395017f77bbSBALATON Zoltan     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
396017f77bbSBALATON Zoltan     s->rtrg = 1;
397017f77bbSBALATON Zoltan 
398017f77bbSBALATON Zoltan     s->smr = 0;
399017f77bbSBALATON Zoltan     s->brr = 0xff;
400017f77bbSBALATON Zoltan     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
401017f77bbSBALATON Zoltan     s->sptr = 0;
402017f77bbSBALATON Zoltan 
403017f77bbSBALATON Zoltan     if (s->feat & SH_SERIAL_FEAT_SCIF) {
404017f77bbSBALATON Zoltan         s->fcr = 0;
405017f77bbSBALATON Zoltan     } else {
406017f77bbSBALATON Zoltan         s->dr = 0xff;
407017f77bbSBALATON Zoltan     }
408017f77bbSBALATON Zoltan 
409017f77bbSBALATON Zoltan     sh_serial_clear_fifo(s);
410017f77bbSBALATON Zoltan }
411017f77bbSBALATON Zoltan 
412*beeb5209SBALATON Zoltan static void sh_serial_realize(DeviceState *d, Error **errp)
4132f062c72Sths {
414*beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(d);
415*beeb5209SBALATON Zoltan     MemoryRegion *iomem = g_malloc(sizeof(*iomem));
4162f062c72Sths 
417*beeb5209SBALATON Zoltan     assert(d->id);
418*beeb5209SBALATON Zoltan     memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28);
419*beeb5209SBALATON Zoltan     sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem);
420*beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->eri, "eri", 1);
421*beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1);
422*beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->txi, "txi", 1);
423*beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->tei, "tei", 1);
424*beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->bri, "bri", 1);
4252f062c72Sths 
426*beeb5209SBALATON Zoltan     if (qemu_chr_fe_backend_connected(&s->chr)) {
4275345fdb4SMarc-André Lureau         qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
4285345fdb4SMarc-André Lureau                                  sh_serial_receive1,
42981517ba3SAnton Nefedov                                  sh_serial_event, NULL, s, NULL, true);
430456d6069SHans de Goede     }
431bf5b7423Saurel32 
4325b344b02SBALATON Zoltan     timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL,
43371bb4ce1SGeert Uytterhoeven                   sh_serial_timeout_int, s);
43471bb4ce1SGeert Uytterhoeven     s->etu = NANOSECONDS_PER_SECOND / 9600;
435*beeb5209SBALATON Zoltan }
436*beeb5209SBALATON Zoltan 
437*beeb5209SBALATON Zoltan static void sh_serial_finalize(Object *obj)
438*beeb5209SBALATON Zoltan {
439*beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(obj);
440*beeb5209SBALATON Zoltan 
441*beeb5209SBALATON Zoltan     timer_del(&s->fifo_timeout_timer);
442*beeb5209SBALATON Zoltan }
443*beeb5209SBALATON Zoltan 
444*beeb5209SBALATON Zoltan static void sh_serial_init(Object *obj)
445*beeb5209SBALATON Zoltan {
446*beeb5209SBALATON Zoltan }
447*beeb5209SBALATON Zoltan 
448*beeb5209SBALATON Zoltan static Property sh_serial_properties[] = {
449*beeb5209SBALATON Zoltan     DEFINE_PROP_CHR("chardev", SHSerialState, chr),
450*beeb5209SBALATON Zoltan     DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
451*beeb5209SBALATON Zoltan     DEFINE_PROP_END_OF_LIST()
452*beeb5209SBALATON Zoltan };
453*beeb5209SBALATON Zoltan 
454*beeb5209SBALATON Zoltan static void sh_serial_class_init(ObjectClass *oc, void *data)
455*beeb5209SBALATON Zoltan {
456*beeb5209SBALATON Zoltan     DeviceClass *dc = DEVICE_CLASS(oc);
457*beeb5209SBALATON Zoltan 
458*beeb5209SBALATON Zoltan     device_class_set_props(dc, sh_serial_properties);
459*beeb5209SBALATON Zoltan     dc->realize = sh_serial_realize;
460*beeb5209SBALATON Zoltan     dc->reset = sh_serial_reset;
461*beeb5209SBALATON Zoltan     /* Reason: part of SuperH CPU/SoC, needs to be wired up */
462*beeb5209SBALATON Zoltan     dc->user_creatable = false;
4632f062c72Sths }
464