qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sh_serial.c (12418B)


      1 /*
      2  * QEMU SCI/SCIF serial port emulation
      3  *
      4  * Copyright (c) 2007 Magnus Damm
      5  *
      6  * Based on serial.c - QEMU 16450 UART emulation
      7  * Copyright (c) 2003-2004 Fabrice Bellard
      8  *
      9  * Permission is hereby granted, free of charge, to any person obtaining a copy
     10  * of this software and associated documentation files (the "Software"), to deal
     11  * in the Software without restriction, including without limitation the rights
     12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     13  * copies of the Software, and to permit persons to whom the Software is
     14  * furnished to do so, subject to the following conditions:
     15  *
     16  * The above copyright notice and this permission notice shall be included in
     17  * all copies or substantial portions of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     25  * THE SOFTWARE.
     26  */
     27 
     28 #include "qemu/osdep.h"
     29 #include "hw/sysbus.h"
     30 #include "hw/irq.h"
     31 #include "hw/qdev-core.h"
     32 #include "hw/qdev-properties.h"
     33 #include "hw/qdev-properties-system.h"
     34 #include "hw/sh4/sh.h"
     35 #include "chardev/char-fe.h"
     36 #include "qapi/error.h"
     37 #include "qemu/timer.h"
     38 #include "qemu/log.h"
     39 #include "trace.h"
     40 
     41 #define SH_SERIAL_FLAG_TEND (1 << 0)
     42 #define SH_SERIAL_FLAG_TDE  (1 << 1)
     43 #define SH_SERIAL_FLAG_RDF  (1 << 2)
     44 #define SH_SERIAL_FLAG_BRK  (1 << 3)
     45 #define SH_SERIAL_FLAG_DR   (1 << 4)
     46 
     47 #define SH_RX_FIFO_LENGTH (16)
     48 
     49 OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
     50 
     51 struct SHSerialState {
     52     SysBusDevice parent;
     53     uint8_t smr;
     54     uint8_t brr;
     55     uint8_t scr;
     56     uint8_t dr; /* ftdr / tdr */
     57     uint8_t sr; /* fsr / ssr */
     58     uint16_t fcr;
     59     uint8_t sptr;
     60 
     61     uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
     62     uint8_t rx_cnt;
     63     uint8_t rx_tail;
     64     uint8_t rx_head;
     65 
     66     uint8_t feat;
     67     int flags;
     68     int rtrg;
     69 
     70     CharBackend chr;
     71     QEMUTimer fifo_timeout_timer;
     72     uint64_t etu; /* Elementary Time Unit (ns) */
     73 
     74     qemu_irq eri;
     75     qemu_irq rxi;
     76     qemu_irq txi;
     77     qemu_irq tei;
     78     qemu_irq bri;
     79 };
     80 
     81 typedef struct {} SHSerialStateClass;
     82 
     83 OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
     84 
     85 static void sh_serial_clear_fifo(SHSerialState *s)
     86 {
     87     memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
     88     s->rx_cnt = 0;
     89     s->rx_head = 0;
     90     s->rx_tail = 0;
     91 }
     92 
     93 static void sh_serial_write(void *opaque, hwaddr offs,
     94                             uint64_t val, unsigned size)
     95 {
     96     SHSerialState *s = opaque;
     97     DeviceState *d = DEVICE(s);
     98     unsigned char ch;
     99 
    100     trace_sh_serial_write(d->id, size, offs, val);
    101     switch (offs) {
    102     case 0x00: /* SMR */
    103         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
    104         return;
    105     case 0x04: /* BRR */
    106         s->brr = val;
    107         return;
    108     case 0x08: /* SCR */
    109         /* TODO : For SH7751, SCIF mask should be 0xfb. */
    110         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
    111         if (!(val & (1 << 5))) {
    112             s->flags |= SH_SERIAL_FLAG_TEND;
    113         }
    114         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
    115             qemu_set_irq(s->txi, val & (1 << 7));
    116         }
    117         if (!(val & (1 << 6))) {
    118             qemu_set_irq(s->rxi, 0);
    119         }
    120         return;
    121     case 0x0c: /* FTDR / TDR */
    122         if (qemu_chr_fe_backend_connected(&s->chr)) {
    123             ch = val;
    124             /*
    125              * XXX this blocks entire thread. Rewrite to use
    126              * qemu_chr_fe_write and background I/O callbacks
    127              */
    128             qemu_chr_fe_write_all(&s->chr, &ch, 1);
    129         }
    130         s->dr = val;
    131         s->flags &= ~SH_SERIAL_FLAG_TDE;
    132         return;
    133 #if 0
    134     case 0x14: /* FRDR / RDR */
    135         ret = 0;
    136         break;
    137 #endif
    138     }
    139     if (s->feat & SH_SERIAL_FEAT_SCIF) {
    140         switch (offs) {
    141         case 0x10: /* FSR */
    142             if (!(val & (1 << 6))) {
    143                 s->flags &= ~SH_SERIAL_FLAG_TEND;
    144             }
    145             if (!(val & (1 << 5))) {
    146                 s->flags &= ~SH_SERIAL_FLAG_TDE;
    147             }
    148             if (!(val & (1 << 4))) {
    149                 s->flags &= ~SH_SERIAL_FLAG_BRK;
    150             }
    151             if (!(val & (1 << 1))) {
    152                 s->flags &= ~SH_SERIAL_FLAG_RDF;
    153             }
    154             if (!(val & (1 << 0))) {
    155                 s->flags &= ~SH_SERIAL_FLAG_DR;
    156             }
    157 
    158             if (!(val & (1 << 1)) || !(val & (1 << 0))) {
    159                 if (s->rxi) {
    160                     qemu_set_irq(s->rxi, 0);
    161                 }
    162             }
    163             return;
    164         case 0x18: /* FCR */
    165             s->fcr = val;
    166             switch ((val >> 6) & 3) {
    167             case 0:
    168                 s->rtrg = 1;
    169                 break;
    170             case 1:
    171                 s->rtrg = 4;
    172                 break;
    173             case 2:
    174                 s->rtrg = 8;
    175                 break;
    176             case 3:
    177                 s->rtrg = 14;
    178                 break;
    179             }
    180             if (val & (1 << 1)) {
    181                 sh_serial_clear_fifo(s);
    182                 s->sr &= ~(1 << 1);
    183             }
    184 
    185             return;
    186         case 0x20: /* SPTR */
    187             s->sptr = val & 0xf3;
    188             return;
    189         case 0x24: /* LSR */
    190             return;
    191         }
    192     } else {
    193         switch (offs) {
    194 #if 0
    195         case 0x0c:
    196             ret = s->dr;
    197             break;
    198         case 0x10:
    199             ret = 0;
    200             break;
    201 #endif
    202         case 0x1c:
    203             s->sptr = val & 0x8f;
    204             return;
    205         }
    206     }
    207     qemu_log_mask(LOG_GUEST_ERROR,
    208                   "%s: unsupported write to 0x%02" HWADDR_PRIx "\n",
    209                   __func__, offs);
    210 }
    211 
    212 static uint64_t sh_serial_read(void *opaque, hwaddr offs,
    213                                unsigned size)
    214 {
    215     SHSerialState *s = opaque;
    216     DeviceState *d = DEVICE(s);
    217     uint32_t ret = UINT32_MAX;
    218 
    219 #if 0
    220     switch (offs) {
    221     case 0x00:
    222         ret = s->smr;
    223         break;
    224     case 0x04:
    225         ret = s->brr;
    226         break;
    227     case 0x08:
    228         ret = s->scr;
    229         break;
    230     case 0x14:
    231         ret = 0;
    232         break;
    233     }
    234 #endif
    235     if (s->feat & SH_SERIAL_FEAT_SCIF) {
    236         switch (offs) {
    237         case 0x00: /* SMR */
    238             ret = s->smr;
    239             break;
    240         case 0x08: /* SCR */
    241             ret = s->scr;
    242             break;
    243         case 0x10: /* FSR */
    244             ret = 0;
    245             if (s->flags & SH_SERIAL_FLAG_TEND) {
    246                 ret |= (1 << 6);
    247             }
    248             if (s->flags & SH_SERIAL_FLAG_TDE) {
    249                 ret |= (1 << 5);
    250             }
    251             if (s->flags & SH_SERIAL_FLAG_BRK) {
    252                 ret |= (1 << 4);
    253             }
    254             if (s->flags & SH_SERIAL_FLAG_RDF) {
    255                 ret |= (1 << 1);
    256             }
    257             if (s->flags & SH_SERIAL_FLAG_DR) {
    258                 ret |= (1 << 0);
    259             }
    260 
    261             if (s->scr & (1 << 5)) {
    262                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
    263             }
    264 
    265             break;
    266         case 0x14:
    267             if (s->rx_cnt > 0) {
    268                 ret = s->rx_fifo[s->rx_tail++];
    269                 s->rx_cnt--;
    270                 if (s->rx_tail == SH_RX_FIFO_LENGTH) {
    271                     s->rx_tail = 0;
    272                 }
    273                 if (s->rx_cnt < s->rtrg) {
    274                     s->flags &= ~SH_SERIAL_FLAG_RDF;
    275                 }
    276             }
    277             break;
    278         case 0x18:
    279             ret = s->fcr;
    280             break;
    281         case 0x1c:
    282             ret = s->rx_cnt;
    283             break;
    284         case 0x20:
    285             ret = s->sptr;
    286             break;
    287         case 0x24:
    288             ret = 0;
    289             break;
    290         }
    291     } else {
    292         switch (offs) {
    293 #if 0
    294         case 0x0c:
    295             ret = s->dr;
    296             break;
    297         case 0x10:
    298             ret = 0;
    299             break;
    300         case 0x14:
    301             ret = s->rx_fifo[0];
    302             break;
    303 #endif
    304         case 0x1c:
    305             ret = s->sptr;
    306             break;
    307         }
    308     }
    309     trace_sh_serial_read(d->id, size, offs, ret);
    310 
    311     if (ret > UINT16_MAX) {
    312         qemu_log_mask(LOG_GUEST_ERROR,
    313                       "%s: unsupported read from 0x%02" HWADDR_PRIx "\n",
    314                       __func__, offs);
    315         ret = 0;
    316     }
    317 
    318     return ret;
    319 }
    320 
    321 static int sh_serial_can_receive(SHSerialState *s)
    322 {
    323     return s->scr & (1 << 4);
    324 }
    325 
    326 static void sh_serial_receive_break(SHSerialState *s)
    327 {
    328     if (s->feat & SH_SERIAL_FEAT_SCIF) {
    329         s->sr |= (1 << 4);
    330     }
    331 }
    332 
    333 static int sh_serial_can_receive1(void *opaque)
    334 {
    335     SHSerialState *s = opaque;
    336     return sh_serial_can_receive(s);
    337 }
    338 
    339 static void sh_serial_timeout_int(void *opaque)
    340 {
    341     SHSerialState *s = opaque;
    342 
    343     s->flags |= SH_SERIAL_FLAG_RDF;
    344     if (s->scr & (1 << 6) && s->rxi) {
    345         qemu_set_irq(s->rxi, 1);
    346     }
    347 }
    348 
    349 static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
    350 {
    351     SHSerialState *s = opaque;
    352 
    353     if (s->feat & SH_SERIAL_FEAT_SCIF) {
    354         int i;
    355         for (i = 0; i < size; i++) {
    356             if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
    357                 s->rx_fifo[s->rx_head++] = buf[i];
    358                 if (s->rx_head == SH_RX_FIFO_LENGTH) {
    359                     s->rx_head = 0;
    360                 }
    361                 s->rx_cnt++;
    362                 if (s->rx_cnt >= s->rtrg) {
    363                     s->flags |= SH_SERIAL_FLAG_RDF;
    364                     if (s->scr & (1 << 6) && s->rxi) {
    365                         timer_del(&s->fifo_timeout_timer);
    366                         qemu_set_irq(s->rxi, 1);
    367                     }
    368                 } else {
    369                     timer_mod(&s->fifo_timeout_timer,
    370                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
    371                 }
    372             }
    373         }
    374     } else {
    375         s->rx_fifo[0] = buf[0];
    376     }
    377 }
    378 
    379 static void sh_serial_event(void *opaque, QEMUChrEvent event)
    380 {
    381     SHSerialState *s = opaque;
    382     if (event == CHR_EVENT_BREAK) {
    383         sh_serial_receive_break(s);
    384     }
    385 }
    386 
    387 static const MemoryRegionOps sh_serial_ops = {
    388     .read = sh_serial_read,
    389     .write = sh_serial_write,
    390     .endianness = DEVICE_NATIVE_ENDIAN,
    391 };
    392 
    393 static void sh_serial_reset(DeviceState *dev)
    394 {
    395     SHSerialState *s = SH_SERIAL(dev);
    396 
    397     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
    398     s->rtrg = 1;
    399 
    400     s->smr = 0;
    401     s->brr = 0xff;
    402     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
    403     s->sptr = 0;
    404 
    405     if (s->feat & SH_SERIAL_FEAT_SCIF) {
    406         s->fcr = 0;
    407     } else {
    408         s->dr = 0xff;
    409     }
    410 
    411     sh_serial_clear_fifo(s);
    412 }
    413 
    414 static void sh_serial_realize(DeviceState *d, Error **errp)
    415 {
    416     SHSerialState *s = SH_SERIAL(d);
    417     MemoryRegion *iomem = g_malloc(sizeof(*iomem));
    418 
    419     assert(d->id);
    420     memory_region_init_io(iomem, OBJECT(d), &sh_serial_ops, s, d->id, 0x28);
    421     sysbus_init_mmio(SYS_BUS_DEVICE(d), iomem);
    422     qdev_init_gpio_out_named(d, &s->eri, "eri", 1);
    423     qdev_init_gpio_out_named(d, &s->rxi, "rxi", 1);
    424     qdev_init_gpio_out_named(d, &s->txi, "txi", 1);
    425     qdev_init_gpio_out_named(d, &s->tei, "tei", 1);
    426     qdev_init_gpio_out_named(d, &s->bri, "bri", 1);
    427 
    428     if (qemu_chr_fe_backend_connected(&s->chr)) {
    429         qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
    430                                  sh_serial_receive1,
    431                                  sh_serial_event, NULL, s, NULL, true);
    432     }
    433 
    434     timer_init_ns(&s->fifo_timeout_timer, QEMU_CLOCK_VIRTUAL,
    435                   sh_serial_timeout_int, s);
    436     s->etu = NANOSECONDS_PER_SECOND / 9600;
    437 }
    438 
    439 static void sh_serial_finalize(Object *obj)
    440 {
    441     SHSerialState *s = SH_SERIAL(obj);
    442 
    443     timer_del(&s->fifo_timeout_timer);
    444 }
    445 
    446 static void sh_serial_init(Object *obj)
    447 {
    448 }
    449 
    450 static Property sh_serial_properties[] = {
    451     DEFINE_PROP_CHR("chardev", SHSerialState, chr),
    452     DEFINE_PROP_UINT8("features", SHSerialState, feat, 0),
    453     DEFINE_PROP_END_OF_LIST()
    454 };
    455 
    456 static void sh_serial_class_init(ObjectClass *oc, void *data)
    457 {
    458     DeviceClass *dc = DEVICE_CLASS(oc);
    459 
    460     device_class_set_props(dc, sh_serial_properties);
    461     dc->realize = sh_serial_realize;
    462     dc->reset = sh_serial_reset;
    463     /* Reason: part of SuperH CPU/SoC, needs to be wired up */
    464     dc->user_creatable = false;
    465 }