xref: /openbmc/qemu/hw/char/sh_serial.c (revision 44ae04f0)
19944d320SPaolo Bonzini /*
29944d320SPaolo Bonzini  * QEMU SCI/SCIF serial port emulation
39944d320SPaolo Bonzini  *
49944d320SPaolo Bonzini  * Copyright (c) 2007 Magnus Damm
59944d320SPaolo Bonzini  *
69944d320SPaolo Bonzini  * Based on serial.c - QEMU 16450 UART emulation
79944d320SPaolo Bonzini  * Copyright (c) 2003-2004 Fabrice Bellard
89944d320SPaolo Bonzini  *
99944d320SPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
109944d320SPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
119944d320SPaolo Bonzini  * in the Software without restriction, including without limitation the rights
129944d320SPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
139944d320SPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
149944d320SPaolo Bonzini  * furnished to do so, subject to the following conditions:
159944d320SPaolo Bonzini  *
169944d320SPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
179944d320SPaolo Bonzini  * all copies or substantial portions of the Software.
189944d320SPaolo Bonzini  *
199944d320SPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
209944d320SPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
219944d320SPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
229944d320SPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
239944d320SPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
249944d320SPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
259944d320SPaolo Bonzini  * THE SOFTWARE.
269944d320SPaolo Bonzini  */
2764552b6bSMarkus Armbruster 
280430891cSPeter Maydell #include "qemu/osdep.h"
29beeb5209SBALATON Zoltan #include "hw/sysbus.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
31beeb5209SBALATON Zoltan #include "hw/qdev-core.h"
32beeb5209SBALATON Zoltan #include "hw/qdev-properties.h"
33beeb5209SBALATON Zoltan #include "hw/qdev-properties-system.h"
349944d320SPaolo 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"
409944d320SPaolo Bonzini 
419944d320SPaolo Bonzini #define SH_SERIAL_FLAG_TEND (1 << 0)
429944d320SPaolo Bonzini #define SH_SERIAL_FLAG_TDE  (1 << 1)
439944d320SPaolo Bonzini #define SH_SERIAL_FLAG_RDF  (1 << 2)
449944d320SPaolo Bonzini #define SH_SERIAL_FLAG_BRK  (1 << 3)
459944d320SPaolo Bonzini #define SH_SERIAL_FLAG_DR   (1 << 4)
469944d320SPaolo Bonzini 
479944d320SPaolo Bonzini #define SH_RX_FIFO_LENGTH (16)
489944d320SPaolo Bonzini 
49beeb5209SBALATON Zoltan OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
50beeb5209SBALATON Zoltan 
51beeb5209SBALATON Zoltan struct SHSerialState {
52beeb5209SBALATON Zoltan     SysBusDevice parent;
539944d320SPaolo Bonzini     uint8_t smr;
549944d320SPaolo Bonzini     uint8_t brr;
559944d320SPaolo Bonzini     uint8_t scr;
569944d320SPaolo Bonzini     uint8_t dr; /* ftdr / tdr */
579944d320SPaolo Bonzini     uint8_t sr; /* fsr / ssr */
589944d320SPaolo Bonzini     uint16_t fcr;
599944d320SPaolo Bonzini     uint8_t sptr;
609944d320SPaolo Bonzini 
619944d320SPaolo Bonzini     uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
629944d320SPaolo Bonzini     uint8_t rx_cnt;
639944d320SPaolo Bonzini     uint8_t rx_tail;
649944d320SPaolo Bonzini     uint8_t rx_head;
659944d320SPaolo Bonzini 
66beeb5209SBALATON Zoltan     uint8_t feat;
679944d320SPaolo Bonzini     int flags;
689944d320SPaolo Bonzini     int rtrg;
699944d320SPaolo Bonzini 
7032a6ebecSMarc-André Lureau     CharBackend chr;
715b344b02SBALATON Zoltan     QEMUTimer fifo_timeout_timer;
7271bb4ce1SGeert Uytterhoeven     uint64_t etu; /* Elementary Time Unit (ns) */
739944d320SPaolo Bonzini 
749944d320SPaolo Bonzini     qemu_irq eri;
759944d320SPaolo Bonzini     qemu_irq rxi;
769944d320SPaolo Bonzini     qemu_irq txi;
779944d320SPaolo Bonzini     qemu_irq tei;
789944d320SPaolo Bonzini     qemu_irq bri;
79beeb5209SBALATON Zoltan };
80beeb5209SBALATON Zoltan 
81beeb5209SBALATON Zoltan typedef struct {} SHSerialStateClass;
82beeb5209SBALATON Zoltan 
OBJECT_DEFINE_TYPE(SHSerialState,sh_serial,SH_SERIAL,SYS_BUS_DEVICE)83beeb5209SBALATON Zoltan OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
849944d320SPaolo Bonzini 
852f6df137SBALATON Zoltan static void sh_serial_clear_fifo(SHSerialState *s)
869944d320SPaolo Bonzini {
879944d320SPaolo Bonzini     memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
889944d320SPaolo Bonzini     s->rx_cnt = 0;
899944d320SPaolo Bonzini     s->rx_head = 0;
909944d320SPaolo Bonzini     s->rx_tail = 0;
919944d320SPaolo Bonzini }
929944d320SPaolo Bonzini 
sh_serial_write(void * opaque,hwaddr offs,uint64_t val,unsigned size)939944d320SPaolo Bonzini static void sh_serial_write(void *opaque, hwaddr offs,
949944d320SPaolo Bonzini                             uint64_t val, unsigned size)
959944d320SPaolo Bonzini {
962f6df137SBALATON Zoltan     SHSerialState *s = opaque;
97*44ae04f0SBALATON Zoltan     DeviceState *d = DEVICE(s);
989944d320SPaolo Bonzini     unsigned char ch;
999944d320SPaolo Bonzini 
100*44ae04f0SBALATON Zoltan     trace_sh_serial_write(d->id, size, offs, val);
1019944d320SPaolo Bonzini     switch (offs) {
1029944d320SPaolo Bonzini     case 0x00: /* SMR */
1039944d320SPaolo Bonzini         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
1049944d320SPaolo Bonzini         return;
1059944d320SPaolo Bonzini     case 0x04: /* BRR */
1069944d320SPaolo Bonzini         s->brr = val;
1079944d320SPaolo Bonzini         return;
1089944d320SPaolo Bonzini     case 0x08: /* SCR */
1099944d320SPaolo Bonzini         /* TODO : For SH7751, SCIF mask should be 0xfb. */
1109944d320SPaolo Bonzini         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
111ac3c9e74SBALATON Zoltan         if (!(val & (1 << 5))) {
1129944d320SPaolo Bonzini             s->flags |= SH_SERIAL_FLAG_TEND;
113ac3c9e74SBALATON Zoltan         }
1149944d320SPaolo Bonzini         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
1159944d320SPaolo Bonzini             qemu_set_irq(s->txi, val & (1 << 7));
1169944d320SPaolo Bonzini         }
1179944d320SPaolo Bonzini         if (!(val & (1 << 6))) {
1189944d320SPaolo Bonzini             qemu_set_irq(s->rxi, 0);
1199944d320SPaolo Bonzini         }
1209944d320SPaolo Bonzini         return;
1219944d320SPaolo Bonzini     case 0x0c: /* FTDR / TDR */
12230650701SAnton Nefedov         if (qemu_chr_fe_backend_connected(&s->chr)) {
1239944d320SPaolo Bonzini             ch = val;
12422138965SBALATON Zoltan             /*
12522138965SBALATON Zoltan              * XXX this blocks entire thread. Rewrite to use
12622138965SBALATON Zoltan              * qemu_chr_fe_write and background I/O callbacks
12722138965SBALATON Zoltan              */
1285345fdb4SMarc-André Lureau             qemu_chr_fe_write_all(&s->chr, &ch, 1);
1299944d320SPaolo Bonzini         }
1309944d320SPaolo Bonzini         s->dr = val;
1319944d320SPaolo Bonzini         s->flags &= ~SH_SERIAL_FLAG_TDE;
1329944d320SPaolo Bonzini         return;
1339944d320SPaolo Bonzini #if 0
1349944d320SPaolo Bonzini     case 0x14: /* FRDR / RDR */
1359944d320SPaolo Bonzini         ret = 0;
1369944d320SPaolo Bonzini         break;
1379944d320SPaolo Bonzini #endif
1389944d320SPaolo Bonzini     }
1399944d320SPaolo Bonzini     if (s->feat & SH_SERIAL_FEAT_SCIF) {
1409944d320SPaolo Bonzini         switch (offs) {
1419944d320SPaolo Bonzini         case 0x10: /* FSR */
142ac3c9e74SBALATON Zoltan             if (!(val & (1 << 6))) {
1439944d320SPaolo Bonzini                 s->flags &= ~SH_SERIAL_FLAG_TEND;
144ac3c9e74SBALATON Zoltan             }
145ac3c9e74SBALATON Zoltan             if (!(val & (1 << 5))) {
1469944d320SPaolo Bonzini                 s->flags &= ~SH_SERIAL_FLAG_TDE;
147ac3c9e74SBALATON Zoltan             }
148ac3c9e74SBALATON Zoltan             if (!(val & (1 << 4))) {
1499944d320SPaolo Bonzini                 s->flags &= ~SH_SERIAL_FLAG_BRK;
150ac3c9e74SBALATON Zoltan             }
151ac3c9e74SBALATON Zoltan             if (!(val & (1 << 1))) {
1529944d320SPaolo Bonzini                 s->flags &= ~SH_SERIAL_FLAG_RDF;
153ac3c9e74SBALATON Zoltan             }
154ac3c9e74SBALATON Zoltan             if (!(val & (1 << 0))) {
1559944d320SPaolo Bonzini                 s->flags &= ~SH_SERIAL_FLAG_DR;
156ac3c9e74SBALATON Zoltan             }
1579944d320SPaolo Bonzini 
1589944d320SPaolo Bonzini             if (!(val & (1 << 1)) || !(val & (1 << 0))) {
1599944d320SPaolo Bonzini                 if (s->rxi) {
1609944d320SPaolo Bonzini                     qemu_set_irq(s->rxi, 0);
1619944d320SPaolo Bonzini                 }
1629944d320SPaolo Bonzini             }
1639944d320SPaolo Bonzini             return;
1649944d320SPaolo Bonzini         case 0x18: /* FCR */
1659944d320SPaolo Bonzini             s->fcr = val;
1669944d320SPaolo Bonzini             switch ((val >> 6) & 3) {
1679944d320SPaolo Bonzini             case 0:
1689944d320SPaolo Bonzini                 s->rtrg = 1;
1699944d320SPaolo Bonzini                 break;
1709944d320SPaolo Bonzini             case 1:
1719944d320SPaolo Bonzini                 s->rtrg = 4;
1729944d320SPaolo Bonzini                 break;
1739944d320SPaolo Bonzini             case 2:
1749944d320SPaolo Bonzini                 s->rtrg = 8;
1759944d320SPaolo Bonzini                 break;
1769944d320SPaolo Bonzini             case 3:
1779944d320SPaolo Bonzini                 s->rtrg = 14;
1789944d320SPaolo Bonzini                 break;
1799944d320SPaolo Bonzini             }
1809944d320SPaolo Bonzini             if (val & (1 << 1)) {
1819944d320SPaolo Bonzini                 sh_serial_clear_fifo(s);
1829944d320SPaolo Bonzini                 s->sr &= ~(1 << 1);
1839944d320SPaolo Bonzini             }
1849944d320SPaolo Bonzini 
1859944d320SPaolo Bonzini             return;
1869944d320SPaolo Bonzini         case 0x20: /* SPTR */
1879944d320SPaolo Bonzini             s->sptr = val & 0xf3;
1889944d320SPaolo Bonzini             return;
1899944d320SPaolo Bonzini         case 0x24: /* LSR */
1909944d320SPaolo Bonzini             return;
1919944d320SPaolo Bonzini         }
192f94bff13SBALATON Zoltan     } else {
1939944d320SPaolo Bonzini         switch (offs) {
1949944d320SPaolo Bonzini #if 0
1959944d320SPaolo Bonzini         case 0x0c:
1969944d320SPaolo Bonzini             ret = s->dr;
1979944d320SPaolo Bonzini             break;
1989944d320SPaolo Bonzini         case 0x10:
1999944d320SPaolo Bonzini             ret = 0;
2009944d320SPaolo Bonzini             break;
2019944d320SPaolo Bonzini #endif
2029944d320SPaolo Bonzini         case 0x1c:
2039944d320SPaolo Bonzini             s->sptr = val & 0x8f;
2049944d320SPaolo Bonzini             return;
2059944d320SPaolo Bonzini         }
2069944d320SPaolo Bonzini     }
2073cf7ce43SBALATON Zoltan     qemu_log_mask(LOG_GUEST_ERROR,
2083cf7ce43SBALATON Zoltan                   "%s: unsupported write to 0x%02" HWADDR_PRIx "\n",
2093cf7ce43SBALATON Zoltan                   __func__, offs);
2109944d320SPaolo Bonzini }
2119944d320SPaolo Bonzini 
sh_serial_read(void * opaque,hwaddr offs,unsigned size)2129944d320SPaolo Bonzini static uint64_t sh_serial_read(void *opaque, hwaddr offs,
2139944d320SPaolo Bonzini                                unsigned size)
2149944d320SPaolo Bonzini {
2152f6df137SBALATON Zoltan     SHSerialState *s = opaque;
216*44ae04f0SBALATON Zoltan     DeviceState *d = DEVICE(s);
2173cf7ce43SBALATON Zoltan     uint32_t ret = UINT32_MAX;
2189944d320SPaolo Bonzini 
2199944d320SPaolo Bonzini #if 0
2209944d320SPaolo Bonzini     switch (offs) {
2219944d320SPaolo Bonzini     case 0x00:
2229944d320SPaolo Bonzini         ret = s->smr;
2239944d320SPaolo Bonzini         break;
2249944d320SPaolo Bonzini     case 0x04:
2259944d320SPaolo Bonzini         ret = s->brr;
2269944d320SPaolo Bonzini         break;
2279944d320SPaolo Bonzini     case 0x08:
2289944d320SPaolo Bonzini         ret = s->scr;
2299944d320SPaolo Bonzini         break;
2309944d320SPaolo Bonzini     case 0x14:
2319944d320SPaolo Bonzini         ret = 0;
2329944d320SPaolo Bonzini         break;
2339944d320SPaolo Bonzini     }
2349944d320SPaolo Bonzini #endif
2359944d320SPaolo Bonzini     if (s->feat & SH_SERIAL_FEAT_SCIF) {
2369944d320SPaolo Bonzini         switch (offs) {
2379944d320SPaolo Bonzini         case 0x00: /* SMR */
2389944d320SPaolo Bonzini             ret = s->smr;
2399944d320SPaolo Bonzini             break;
2409944d320SPaolo Bonzini         case 0x08: /* SCR */
2419944d320SPaolo Bonzini             ret = s->scr;
2429944d320SPaolo Bonzini             break;
2439944d320SPaolo Bonzini         case 0x10: /* FSR */
2449944d320SPaolo Bonzini             ret = 0;
245ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_TEND) {
2469944d320SPaolo Bonzini                 ret |= (1 << 6);
247ac3c9e74SBALATON Zoltan             }
248ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_TDE) {
2499944d320SPaolo Bonzini                 ret |= (1 << 5);
250ac3c9e74SBALATON Zoltan             }
251ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_BRK) {
2529944d320SPaolo Bonzini                 ret |= (1 << 4);
253ac3c9e74SBALATON Zoltan             }
254ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_RDF) {
2559944d320SPaolo Bonzini                 ret |= (1 << 1);
256ac3c9e74SBALATON Zoltan             }
257ac3c9e74SBALATON Zoltan             if (s->flags & SH_SERIAL_FLAG_DR) {
2589944d320SPaolo Bonzini                 ret |= (1 << 0);
259ac3c9e74SBALATON Zoltan             }
2609944d320SPaolo Bonzini 
261ac3c9e74SBALATON Zoltan             if (s->scr & (1 << 5)) {
2629944d320SPaolo Bonzini                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
263ac3c9e74SBALATON Zoltan             }
2649944d320SPaolo Bonzini 
2659944d320SPaolo Bonzini             break;
2669944d320SPaolo Bonzini         case 0x14:
2679944d320SPaolo Bonzini             if (s->rx_cnt > 0) {
2689944d320SPaolo Bonzini                 ret = s->rx_fifo[s->rx_tail++];
2699944d320SPaolo Bonzini                 s->rx_cnt--;
270ac3c9e74SBALATON Zoltan                 if (s->rx_tail == SH_RX_FIFO_LENGTH) {
2719944d320SPaolo Bonzini                     s->rx_tail = 0;
272ac3c9e74SBALATON Zoltan                 }
273ac3c9e74SBALATON Zoltan                 if (s->rx_cnt < s->rtrg) {
2749944d320SPaolo Bonzini                     s->flags &= ~SH_SERIAL_FLAG_RDF;
2759944d320SPaolo Bonzini                 }
276ac3c9e74SBALATON Zoltan             }
2779944d320SPaolo Bonzini             break;
2789944d320SPaolo Bonzini         case 0x18:
2799944d320SPaolo Bonzini             ret = s->fcr;
2809944d320SPaolo Bonzini             break;
2819944d320SPaolo Bonzini         case 0x1c:
2829944d320SPaolo Bonzini             ret = s->rx_cnt;
2839944d320SPaolo Bonzini             break;
2849944d320SPaolo Bonzini         case 0x20:
2859944d320SPaolo Bonzini             ret = s->sptr;
2869944d320SPaolo Bonzini             break;
2879944d320SPaolo Bonzini         case 0x24:
2889944d320SPaolo Bonzini             ret = 0;
2899944d320SPaolo Bonzini             break;
2909944d320SPaolo Bonzini         }
291f94bff13SBALATON Zoltan     } else {
2929944d320SPaolo Bonzini         switch (offs) {
2939944d320SPaolo Bonzini #if 0
2949944d320SPaolo Bonzini         case 0x0c:
2959944d320SPaolo Bonzini             ret = s->dr;
2969944d320SPaolo Bonzini             break;
2979944d320SPaolo Bonzini         case 0x10:
2989944d320SPaolo Bonzini             ret = 0;
2999944d320SPaolo Bonzini             break;
3009944d320SPaolo Bonzini         case 0x14:
3019944d320SPaolo Bonzini             ret = s->rx_fifo[0];
3029944d320SPaolo Bonzini             break;
3039944d320SPaolo Bonzini #endif
3049944d320SPaolo Bonzini         case 0x1c:
3059944d320SPaolo Bonzini             ret = s->sptr;
3069944d320SPaolo Bonzini             break;
3079944d320SPaolo Bonzini         }
3089944d320SPaolo Bonzini     }
309*44ae04f0SBALATON Zoltan     trace_sh_serial_read(d->id, size, offs, ret);
3109944d320SPaolo Bonzini 
3113cf7ce43SBALATON Zoltan     if (ret > UINT16_MAX) {
3123cf7ce43SBALATON Zoltan         qemu_log_mask(LOG_GUEST_ERROR,
3133cf7ce43SBALATON Zoltan                       "%s: unsupported read from 0x%02" HWADDR_PRIx "\n",
3143cf7ce43SBALATON Zoltan                       __func__, offs);
3153cf7ce43SBALATON Zoltan         ret = 0;
3169944d320SPaolo Bonzini     }
3179944d320SPaolo Bonzini 
3189944d320SPaolo Bonzini     return ret;
3199944d320SPaolo Bonzini }
3209944d320SPaolo Bonzini 
sh_serial_can_receive(SHSerialState * s)3212f6df137SBALATON Zoltan static int sh_serial_can_receive(SHSerialState *s)
3229944d320SPaolo Bonzini {
3239944d320SPaolo Bonzini     return s->scr & (1 << 4);
3249944d320SPaolo Bonzini }
3259944d320SPaolo Bonzini 
sh_serial_receive_break(SHSerialState * s)3262f6df137SBALATON Zoltan static void sh_serial_receive_break(SHSerialState *s)
3279944d320SPaolo Bonzini {
328ac3c9e74SBALATON Zoltan     if (s->feat & SH_SERIAL_FEAT_SCIF) {
3299944d320SPaolo Bonzini         s->sr |= (1 << 4);
3309944d320SPaolo Bonzini     }
331ac3c9e74SBALATON Zoltan }
3329944d320SPaolo Bonzini 
sh_serial_can_receive1(void * opaque)3339944d320SPaolo Bonzini static int sh_serial_can_receive1(void *opaque)
3349944d320SPaolo Bonzini {
3352f6df137SBALATON Zoltan     SHSerialState *s = opaque;
3369944d320SPaolo Bonzini     return sh_serial_can_receive(s);
3379944d320SPaolo Bonzini }
3389944d320SPaolo Bonzini 
sh_serial_timeout_int(void * opaque)33971bb4ce1SGeert Uytterhoeven static void sh_serial_timeout_int(void *opaque)
34071bb4ce1SGeert Uytterhoeven {
3412f6df137SBALATON Zoltan     SHSerialState *s = opaque;
34271bb4ce1SGeert Uytterhoeven 
34371bb4ce1SGeert Uytterhoeven     s->flags |= SH_SERIAL_FLAG_RDF;
34471bb4ce1SGeert Uytterhoeven     if (s->scr & (1 << 6) && s->rxi) {
34571bb4ce1SGeert Uytterhoeven         qemu_set_irq(s->rxi, 1);
34671bb4ce1SGeert Uytterhoeven     }
34771bb4ce1SGeert Uytterhoeven }
34871bb4ce1SGeert Uytterhoeven 
sh_serial_receive1(void * opaque,const uint8_t * buf,int size)3499944d320SPaolo Bonzini static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
3509944d320SPaolo Bonzini {
3512f6df137SBALATON Zoltan     SHSerialState *s = opaque;
3529944d320SPaolo Bonzini 
3539944d320SPaolo Bonzini     if (s->feat & SH_SERIAL_FEAT_SCIF) {
3549944d320SPaolo Bonzini         int i;
3559944d320SPaolo Bonzini         for (i = 0; i < size; i++) {
3569944d320SPaolo Bonzini             if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
3579944d320SPaolo Bonzini                 s->rx_fifo[s->rx_head++] = buf[i];
3589944d320SPaolo Bonzini                 if (s->rx_head == SH_RX_FIFO_LENGTH) {
3599944d320SPaolo Bonzini                     s->rx_head = 0;
3609944d320SPaolo Bonzini                 }
3619944d320SPaolo Bonzini                 s->rx_cnt++;
3629944d320SPaolo Bonzini                 if (s->rx_cnt >= s->rtrg) {
3639944d320SPaolo Bonzini                     s->flags |= SH_SERIAL_FLAG_RDF;
3649944d320SPaolo Bonzini                     if (s->scr & (1 << 6) && s->rxi) {
3655b344b02SBALATON Zoltan                         timer_del(&s->fifo_timeout_timer);
3669944d320SPaolo Bonzini                         qemu_set_irq(s->rxi, 1);
3679944d320SPaolo Bonzini                     }
36871bb4ce1SGeert Uytterhoeven                 } else {
3695b344b02SBALATON Zoltan                     timer_mod(&s->fifo_timeout_timer,
37071bb4ce1SGeert Uytterhoeven                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
3719944d320SPaolo Bonzini                 }
3729944d320SPaolo Bonzini             }
3739944d320SPaolo Bonzini         }
3749944d320SPaolo Bonzini     } else {
3759944d320SPaolo Bonzini         s->rx_fifo[0] = buf[0];
3769944d320SPaolo Bonzini     }
3779944d320SPaolo Bonzini }
3789944d320SPaolo Bonzini 
sh_serial_event(void * opaque,QEMUChrEvent event)379083b266fSPhilippe Mathieu-Daudé static void sh_serial_event(void *opaque, QEMUChrEvent event)
3809944d320SPaolo Bonzini {
3812f6df137SBALATON Zoltan     SHSerialState *s = opaque;
382ac3c9e74SBALATON Zoltan     if (event == CHR_EVENT_BREAK) {
3839944d320SPaolo Bonzini         sh_serial_receive_break(s);
3849944d320SPaolo Bonzini     }
385ac3c9e74SBALATON Zoltan }
3869944d320SPaolo Bonzini 
3879944d320SPaolo Bonzini static const MemoryRegionOps sh_serial_ops = {
3889944d320SPaolo Bonzini     .read = sh_serial_read,
3899944d320SPaolo Bonzini     .write = sh_serial_write,
3909944d320SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3919944d320SPaolo Bonzini };
3929944d320SPaolo Bonzini 
sh_serial_reset(DeviceState * dev)393beeb5209SBALATON Zoltan static void sh_serial_reset(DeviceState *dev)
394017f77bbSBALATON Zoltan {
395beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(dev);
396beeb5209SBALATON Zoltan 
397017f77bbSBALATON Zoltan     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
398017f77bbSBALATON Zoltan     s->rtrg = 1;
399017f77bbSBALATON Zoltan 
400017f77bbSBALATON Zoltan     s->smr = 0;
401017f77bbSBALATON Zoltan     s->brr = 0xff;
402017f77bbSBALATON Zoltan     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
403017f77bbSBALATON Zoltan     s->sptr = 0;
404017f77bbSBALATON Zoltan 
405017f77bbSBALATON Zoltan     if (s->feat & SH_SERIAL_FEAT_SCIF) {
406017f77bbSBALATON Zoltan         s->fcr = 0;
407017f77bbSBALATON Zoltan     } else {
408017f77bbSBALATON Zoltan         s->dr = 0xff;
409017f77bbSBALATON Zoltan     }
410017f77bbSBALATON Zoltan 
411017f77bbSBALATON Zoltan     sh_serial_clear_fifo(s);
412017f77bbSBALATON Zoltan }
413017f77bbSBALATON Zoltan 
sh_serial_realize(DeviceState * d,Error ** errp)414beeb5209SBALATON Zoltan static void sh_serial_realize(DeviceState *d, Error **errp)
4159944d320SPaolo Bonzini {
416beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(d);
417beeb5209SBALATON Zoltan     MemoryRegion *iomem = g_malloc(sizeof(*iomem));
4189944d320SPaolo Bonzini 
419beeb5209SBALATON Zoltan     assert(d->id);
420beeb5209SBALATON Zoltan     memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28);
421beeb5209SBALATON Zoltan     sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem);
422beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->eri, "eri", 1);
423beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1);
424beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->txi, "txi", 1);
425beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->tei, "tei", 1);
426beeb5209SBALATON Zoltan     qdev_init_gpio_out_named(d, &s->bri, "bri", 1);
4279944d320SPaolo Bonzini 
428beeb5209SBALATON Zoltan     if (qemu_chr_fe_backend_connected(&s->chr)) {
4295345fdb4SMarc-André Lureau         qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
4305345fdb4SMarc-André Lureau                                  sh_serial_receive1,
43181517ba3SAnton Nefedov                                  sh_serial_event, NULL, s, NULL, true);
4329944d320SPaolo Bonzini     }
4339944d320SPaolo Bonzini 
4345b344b02SBALATON Zoltan     timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL,
43571bb4ce1SGeert Uytterhoeven                   sh_serial_timeout_int, s);
43671bb4ce1SGeert Uytterhoeven     s->etu = NANOSECONDS_PER_SECOND / 9600;
437beeb5209SBALATON Zoltan }
438beeb5209SBALATON Zoltan 
sh_serial_finalize(Object * obj)439beeb5209SBALATON Zoltan static void sh_serial_finalize(Object *obj)
440beeb5209SBALATON Zoltan {
441beeb5209SBALATON Zoltan     SHSerialState *s = SH_SERIAL(obj);
442beeb5209SBALATON Zoltan 
443beeb5209SBALATON Zoltan     timer_del(&s->fifo_timeout_timer);
444beeb5209SBALATON Zoltan }
445beeb5209SBALATON Zoltan 
sh_serial_init(Object * obj)446beeb5209SBALATON Zoltan static void sh_serial_init(Object *obj)
447beeb5209SBALATON Zoltan {
448beeb5209SBALATON Zoltan }
449beeb5209SBALATON Zoltan 
450beeb5209SBALATON Zoltan static Property sh_serial_properties[] = {
451beeb5209SBALATON Zoltan     DEFINE_PROP_CHR("chardev", SHSerialState, chr),
452beeb5209SBALATON Zoltan     DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
453beeb5209SBALATON Zoltan     DEFINE_PROP_END_OF_LIST()
454beeb5209SBALATON Zoltan };
455beeb5209SBALATON Zoltan 
sh_serial_class_init(ObjectClass * oc,void * data)456beeb5209SBALATON Zoltan static void sh_serial_class_init(ObjectClass *oc, void *data)
457beeb5209SBALATON Zoltan {
458beeb5209SBALATON Zoltan     DeviceClass *dc = DEVICE_CLASS(oc);
459beeb5209SBALATON Zoltan 
460beeb5209SBALATON Zoltan     device_class_set_props(dc, sh_serial_properties);
461beeb5209SBALATON Zoltan     dc->realize = sh_serial_realize;
462beeb5209SBALATON Zoltan     dc->reset = sh_serial_reset;
463beeb5209SBALATON Zoltan     /* Reason: part of SuperH CPU/SoC, needs to be wired up */
464beeb5209SBALATON Zoltan     dc->user_creatable = false;
4659944d320SPaolo Bonzini }
466