qemu/hw/char/sh_serial.c
<<
>>
Prefs
   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
  49OBJECT_DECLARE_SIMPLE_TYPE(SHSerialState, SH_SERIAL)
  50
  51struct 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
  81typedef struct {} SHSerialStateClass;
  82
  83OBJECT_DEFINE_TYPE(SHSerialState, sh_serial, SH_SERIAL, SYS_BUS_DEVICE)
  84
  85static 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
  93static 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
 212static 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
 321static int sh_serial_can_receive(SHSerialState *s)
 322{
 323    return s->scr & (1 << 4);
 324}
 325
 326static void sh_serial_receive_break(SHSerialState *s)
 327{
 328    if (s->feat & SH_SERIAL_FEAT_SCIF) {
 329        s->sr |= (1 << 4);
 330    }
 331}
 332
 333static int sh_serial_can_receive1(void *opaque)
 334{
 335    SHSerialState *s = opaque;
 336    return sh_serial_can_receive(s);
 337}
 338
 339static 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
 349static 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
 379static 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
 387static const MemoryRegionOps sh_serial_ops = {
 388    .read = sh_serial_read,
 389    .write = sh_serial_write,
 390    .endianness = DEVICE_NATIVE_ENDIAN,
 391};
 392
 393static 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
 414static 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
 439static void sh_serial_finalize(Object *obj)
 440{
 441    SHSerialState *s = SH_SERIAL(obj);
 442
 443    timer_del(&s->fifo_timeout_timer);
 444}
 445
 446static void sh_serial_init(Object *obj)
 447{
 448}
 449
 450static 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
 456static 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}
 466