qemu/hw/sd/pl181.c
<<
>>
Prefs
   1/*
   2 * Arm PrimeCell PL181 MultiMedia Card Interface
   3 *
   4 * Copyright (c) 2007 CodeSourcery.
   5 * Written by Paul Brook
   6 *
   7 * This code is licensed under the GPL.
   8 */
   9
  10#include "sysemu/block-backend.h"
  11#include "sysemu/blockdev.h"
  12#include "hw/sysbus.h"
  13#include "hw/sd/sd.h"
  14
  15//#define DEBUG_PL181 1
  16
  17#ifdef DEBUG_PL181
  18#define DPRINTF(fmt, ...) \
  19do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
  20#else
  21#define DPRINTF(fmt, ...) do {} while(0)
  22#endif
  23
  24#define PL181_FIFO_LEN 16
  25
  26#define TYPE_PL181 "pl181"
  27#define PL181(obj) OBJECT_CHECK(PL181State, (obj), TYPE_PL181)
  28
  29typedef struct PL181State {
  30    SysBusDevice parent_obj;
  31
  32    MemoryRegion iomem;
  33    SDState *card;
  34    uint32_t clock;
  35    uint32_t power;
  36    uint32_t cmdarg;
  37    uint32_t cmd;
  38    uint32_t datatimer;
  39    uint32_t datalength;
  40    uint32_t respcmd;
  41    uint32_t response[4];
  42    uint32_t datactrl;
  43    uint32_t datacnt;
  44    uint32_t status;
  45    uint32_t mask[2];
  46    int32_t fifo_pos;
  47    int32_t fifo_len;
  48    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
  49       while it is reading the FIFO.  We hack around this by deferring
  50       subsequent transfers until after the driver polls the status word.
  51       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
  52     */
  53    int32_t linux_hack;
  54    uint32_t fifo[PL181_FIFO_LEN];
  55    qemu_irq irq[2];
  56    /* GPIO outputs for 'card is readonly' and 'card inserted' */
  57    qemu_irq cardstatus[2];
  58} PL181State;
  59
  60static const VMStateDescription vmstate_pl181 = {
  61    .name = "pl181",
  62    .version_id = 1,
  63    .minimum_version_id = 1,
  64    .fields = (VMStateField[]) {
  65        VMSTATE_UINT32(clock, PL181State),
  66        VMSTATE_UINT32(power, PL181State),
  67        VMSTATE_UINT32(cmdarg, PL181State),
  68        VMSTATE_UINT32(cmd, PL181State),
  69        VMSTATE_UINT32(datatimer, PL181State),
  70        VMSTATE_UINT32(datalength, PL181State),
  71        VMSTATE_UINT32(respcmd, PL181State),
  72        VMSTATE_UINT32_ARRAY(response, PL181State, 4),
  73        VMSTATE_UINT32(datactrl, PL181State),
  74        VMSTATE_UINT32(datacnt, PL181State),
  75        VMSTATE_UINT32(status, PL181State),
  76        VMSTATE_UINT32_ARRAY(mask, PL181State, 2),
  77        VMSTATE_INT32(fifo_pos, PL181State),
  78        VMSTATE_INT32(fifo_len, PL181State),
  79        VMSTATE_INT32(linux_hack, PL181State),
  80        VMSTATE_UINT32_ARRAY(fifo, PL181State, PL181_FIFO_LEN),
  81        VMSTATE_END_OF_LIST()
  82    }
  83};
  84
  85#define PL181_CMD_INDEX     0x3f
  86#define PL181_CMD_RESPONSE  (1 << 6)
  87#define PL181_CMD_LONGRESP  (1 << 7)
  88#define PL181_CMD_INTERRUPT (1 << 8)
  89#define PL181_CMD_PENDING   (1 << 9)
  90#define PL181_CMD_ENABLE    (1 << 10)
  91
  92#define PL181_DATA_ENABLE             (1 << 0)
  93#define PL181_DATA_DIRECTION          (1 << 1)
  94#define PL181_DATA_MODE               (1 << 2)
  95#define PL181_DATA_DMAENABLE          (1 << 3)
  96
  97#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
  98#define PL181_STATUS_DATACRCFAIL      (1 << 1)
  99#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
 100#define PL181_STATUS_DATATIMEOUT      (1 << 3)
 101#define PL181_STATUS_TXUNDERRUN       (1 << 4)
 102#define PL181_STATUS_RXOVERRUN        (1 << 5)
 103#define PL181_STATUS_CMDRESPEND       (1 << 6)
 104#define PL181_STATUS_CMDSENT          (1 << 7)
 105#define PL181_STATUS_DATAEND          (1 << 8)
 106#define PL181_STATUS_DATABLOCKEND     (1 << 10)
 107#define PL181_STATUS_CMDACTIVE        (1 << 11)
 108#define PL181_STATUS_TXACTIVE         (1 << 12)
 109#define PL181_STATUS_RXACTIVE         (1 << 13)
 110#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
 111#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
 112#define PL181_STATUS_TXFIFOFULL       (1 << 16)
 113#define PL181_STATUS_RXFIFOFULL       (1 << 17)
 114#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
 115#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
 116#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
 117#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
 118
 119#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
 120                             |PL181_STATUS_TXFIFOHALFEMPTY \
 121                             |PL181_STATUS_TXFIFOFULL \
 122                             |PL181_STATUS_TXFIFOEMPTY \
 123                             |PL181_STATUS_TXDATAAVLBL)
 124#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
 125                             |PL181_STATUS_RXFIFOHALFFULL \
 126                             |PL181_STATUS_RXFIFOFULL \
 127                             |PL181_STATUS_RXFIFOEMPTY \
 128                             |PL181_STATUS_RXDATAAVLBL)
 129
 130static const unsigned char pl181_id[] =
 131{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
 132
 133static void pl181_update(PL181State *s)
 134{
 135    int i;
 136    for (i = 0; i < 2; i++) {
 137        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
 138    }
 139}
 140
 141static void pl181_fifo_push(PL181State *s, uint32_t value)
 142{
 143    int n;
 144
 145    if (s->fifo_len == PL181_FIFO_LEN) {
 146        fprintf(stderr, "pl181: FIFO overflow\n");
 147        return;
 148    }
 149    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
 150    s->fifo_len++;
 151    s->fifo[n] = value;
 152    DPRINTF("FIFO push %08x\n", (int)value);
 153}
 154
 155static uint32_t pl181_fifo_pop(PL181State *s)
 156{
 157    uint32_t value;
 158
 159    if (s->fifo_len == 0) {
 160        fprintf(stderr, "pl181: FIFO underflow\n");
 161        return 0;
 162    }
 163    value = s->fifo[s->fifo_pos];
 164    s->fifo_len--;
 165    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
 166    DPRINTF("FIFO pop %08x\n", (int)value);
 167    return value;
 168}
 169
 170static void pl181_send_command(PL181State *s)
 171{
 172    SDRequest request;
 173    uint8_t response[16];
 174    int rlen;
 175
 176    request.cmd = s->cmd & PL181_CMD_INDEX;
 177    request.arg = s->cmdarg;
 178    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
 179    rlen = sd_do_command(s->card, &request, response);
 180    if (rlen < 0)
 181        goto error;
 182    if (s->cmd & PL181_CMD_RESPONSE) {
 183#define RWORD(n) (((uint32_t)response[n] << 24) | (response[n + 1] << 16) \
 184                  | (response[n + 2] << 8) | response[n + 3])
 185        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
 186            goto error;
 187        if (rlen != 4 && rlen != 16)
 188            goto error;
 189        s->response[0] = RWORD(0);
 190        if (rlen == 4) {
 191            s->response[1] = s->response[2] = s->response[3] = 0;
 192        } else {
 193            s->response[1] = RWORD(4);
 194            s->response[2] = RWORD(8);
 195            s->response[3] = RWORD(12) & ~1;
 196        }
 197        DPRINTF("Response received\n");
 198        s->status |= PL181_STATUS_CMDRESPEND;
 199#undef RWORD
 200    } else {
 201        DPRINTF("Command sent\n");
 202        s->status |= PL181_STATUS_CMDSENT;
 203    }
 204    return;
 205
 206error:
 207    DPRINTF("Timeout\n");
 208    s->status |= PL181_STATUS_CMDTIMEOUT;
 209}
 210
 211/* Transfer data between the card and the FIFO.  This is complicated by
 212   the FIFO holding 32-bit words and the card taking data in single byte
 213   chunks.  FIFO bytes are transferred in little-endian order.  */
 214
 215static void pl181_fifo_run(PL181State *s)
 216{
 217    uint32_t bits;
 218    uint32_t value = 0;
 219    int n;
 220    int is_read;
 221
 222    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
 223    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
 224            && !s->linux_hack) {
 225        if (is_read) {
 226            n = 0;
 227            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
 228                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
 229                s->datacnt--;
 230                n++;
 231                if (n == 4) {
 232                    pl181_fifo_push(s, value);
 233                    n = 0;
 234                    value = 0;
 235                }
 236            }
 237            if (n != 0) {
 238                pl181_fifo_push(s, value);
 239            }
 240        } else { /* write */
 241            n = 0;
 242            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
 243                if (n == 0) {
 244                    value = pl181_fifo_pop(s);
 245                    n = 4;
 246                }
 247                n--;
 248                s->datacnt--;
 249                sd_write_data(s->card, value & 0xff);
 250                value >>= 8;
 251            }
 252        }
 253    }
 254    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
 255    if (s->datacnt == 0) {
 256        s->status |= PL181_STATUS_DATAEND;
 257        /* HACK: */
 258        s->status |= PL181_STATUS_DATABLOCKEND;
 259        DPRINTF("Transfer Complete\n");
 260    }
 261    if (s->datacnt == 0 && s->fifo_len == 0) {
 262        s->datactrl &= ~PL181_DATA_ENABLE;
 263        DPRINTF("Data engine idle\n");
 264    } else {
 265        /* Update FIFO bits.  */
 266        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
 267        if (s->fifo_len == 0) {
 268            bits |= PL181_STATUS_TXFIFOEMPTY;
 269            bits |= PL181_STATUS_RXFIFOEMPTY;
 270        } else {
 271            bits |= PL181_STATUS_TXDATAAVLBL;
 272            bits |= PL181_STATUS_RXDATAAVLBL;
 273        }
 274        if (s->fifo_len == 16) {
 275            bits |= PL181_STATUS_TXFIFOFULL;
 276            bits |= PL181_STATUS_RXFIFOFULL;
 277        }
 278        if (s->fifo_len <= 8) {
 279            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
 280        }
 281        if (s->fifo_len >= 8) {
 282            bits |= PL181_STATUS_RXFIFOHALFFULL;
 283        }
 284        if (s->datactrl & PL181_DATA_DIRECTION) {
 285            bits &= PL181_STATUS_RX_FIFO;
 286        } else {
 287            bits &= PL181_STATUS_TX_FIFO;
 288        }
 289        s->status |= bits;
 290    }
 291}
 292
 293static uint64_t pl181_read(void *opaque, hwaddr offset,
 294                           unsigned size)
 295{
 296    PL181State *s = (PL181State *)opaque;
 297    uint32_t tmp;
 298
 299    if (offset >= 0xfe0 && offset < 0x1000) {
 300        return pl181_id[(offset - 0xfe0) >> 2];
 301    }
 302    switch (offset) {
 303    case 0x00: /* Power */
 304        return s->power;
 305    case 0x04: /* Clock */
 306        return s->clock;
 307    case 0x08: /* Argument */
 308        return s->cmdarg;
 309    case 0x0c: /* Command */
 310        return s->cmd;
 311    case 0x10: /* RespCmd */
 312        return s->respcmd;
 313    case 0x14: /* Response0 */
 314        return s->response[0];
 315    case 0x18: /* Response1 */
 316        return s->response[1];
 317    case 0x1c: /* Response2 */
 318        return s->response[2];
 319    case 0x20: /* Response3 */
 320        return s->response[3];
 321    case 0x24: /* DataTimer */
 322        return s->datatimer;
 323    case 0x28: /* DataLength */
 324        return s->datalength;
 325    case 0x2c: /* DataCtrl */
 326        return s->datactrl;
 327    case 0x30: /* DataCnt */
 328        return s->datacnt;
 329    case 0x34: /* Status */
 330        tmp = s->status;
 331        if (s->linux_hack) {
 332            s->linux_hack = 0;
 333            pl181_fifo_run(s);
 334            pl181_update(s);
 335        }
 336        return tmp;
 337    case 0x3c: /* Mask0 */
 338        return s->mask[0];
 339    case 0x40: /* Mask1 */
 340        return s->mask[1];
 341    case 0x48: /* FifoCnt */
 342        /* The documentation is somewhat vague about exactly what FifoCnt
 343           does.  On real hardware it appears to be when decrememnted
 344           when a word is transferred between the FIFO and the serial
 345           data engine.  DataCnt is decremented after each byte is
 346           transferred between the serial engine and the card.
 347           We don't emulate this level of detail, so both can be the same.  */
 348        tmp = (s->datacnt + 3) >> 2;
 349        if (s->linux_hack) {
 350            s->linux_hack = 0;
 351            pl181_fifo_run(s);
 352            pl181_update(s);
 353        }
 354        return tmp;
 355    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
 356    case 0x90: case 0x94: case 0x98: case 0x9c:
 357    case 0xa0: case 0xa4: case 0xa8: case 0xac:
 358    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
 359        if (s->fifo_len == 0) {
 360            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
 361            return 0;
 362        } else {
 363            uint32_t value;
 364            value = pl181_fifo_pop(s);
 365            s->linux_hack = 1;
 366            pl181_fifo_run(s);
 367            pl181_update(s);
 368            return value;
 369        }
 370    default:
 371        qemu_log_mask(LOG_GUEST_ERROR,
 372                      "pl181_read: Bad offset %x\n", (int)offset);
 373        return 0;
 374    }
 375}
 376
 377static void pl181_write(void *opaque, hwaddr offset,
 378                        uint64_t value, unsigned size)
 379{
 380    PL181State *s = (PL181State *)opaque;
 381
 382    switch (offset) {
 383    case 0x00: /* Power */
 384        s->power = value & 0xff;
 385        break;
 386    case 0x04: /* Clock */
 387        s->clock = value & 0xff;
 388        break;
 389    case 0x08: /* Argument */
 390        s->cmdarg = value;
 391        break;
 392    case 0x0c: /* Command */
 393        s->cmd = value;
 394        if (s->cmd & PL181_CMD_ENABLE) {
 395            if (s->cmd & PL181_CMD_INTERRUPT) {
 396                qemu_log_mask(LOG_UNIMP,
 397                              "pl181: Interrupt mode not implemented\n");
 398            } if (s->cmd & PL181_CMD_PENDING) {
 399                qemu_log_mask(LOG_UNIMP,
 400                              "pl181: Pending commands not implemented\n");
 401            } else {
 402                pl181_send_command(s);
 403                pl181_fifo_run(s);
 404            }
 405            /* The command has completed one way or the other.  */
 406            s->cmd &= ~PL181_CMD_ENABLE;
 407        }
 408        break;
 409    case 0x24: /* DataTimer */
 410        s->datatimer = value;
 411        break;
 412    case 0x28: /* DataLength */
 413        s->datalength = value & 0xffff;
 414        break;
 415    case 0x2c: /* DataCtrl */
 416        s->datactrl = value & 0xff;
 417        if (value & PL181_DATA_ENABLE) {
 418            s->datacnt = s->datalength;
 419            pl181_fifo_run(s);
 420        }
 421        break;
 422    case 0x38: /* Clear */
 423        s->status &= ~(value & 0x7ff);
 424        break;
 425    case 0x3c: /* Mask0 */
 426        s->mask[0] = value;
 427        break;
 428    case 0x40: /* Mask1 */
 429        s->mask[1] = value;
 430        break;
 431    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
 432    case 0x90: case 0x94: case 0x98: case 0x9c:
 433    case 0xa0: case 0xa4: case 0xa8: case 0xac:
 434    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
 435        if (s->datacnt == 0) {
 436            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
 437        } else {
 438            pl181_fifo_push(s, value);
 439            pl181_fifo_run(s);
 440        }
 441        break;
 442    default:
 443        qemu_log_mask(LOG_GUEST_ERROR,
 444                      "pl181_write: Bad offset %x\n", (int)offset);
 445    }
 446    pl181_update(s);
 447}
 448
 449static const MemoryRegionOps pl181_ops = {
 450    .read = pl181_read,
 451    .write = pl181_write,
 452    .endianness = DEVICE_NATIVE_ENDIAN,
 453};
 454
 455static void pl181_reset(DeviceState *d)
 456{
 457    PL181State *s = PL181(d);
 458
 459    s->power = 0;
 460    s->cmdarg = 0;
 461    s->cmd = 0;
 462    s->datatimer = 0;
 463    s->datalength = 0;
 464    s->respcmd = 0;
 465    s->response[0] = 0;
 466    s->response[1] = 0;
 467    s->response[2] = 0;
 468    s->response[3] = 0;
 469    s->datatimer = 0;
 470    s->datalength = 0;
 471    s->datactrl = 0;
 472    s->datacnt = 0;
 473    s->status = 0;
 474    s->linux_hack = 0;
 475    s->mask[0] = 0;
 476    s->mask[1] = 0;
 477
 478    /* We can assume our GPIO outputs have been wired up now */
 479    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
 480}
 481
 482static int pl181_init(SysBusDevice *sbd)
 483{
 484    DeviceState *dev = DEVICE(sbd);
 485    PL181State *s = PL181(dev);
 486    DriveInfo *dinfo;
 487
 488    memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000);
 489    sysbus_init_mmio(sbd, &s->iomem);
 490    sysbus_init_irq(sbd, &s->irq[0]);
 491    sysbus_init_irq(sbd, &s->irq[1]);
 492    qdev_init_gpio_out(dev, s->cardstatus, 2);
 493    /* FIXME use a qdev drive property instead of drive_get_next() */
 494    dinfo = drive_get_next(IF_SD);
 495    s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false);
 496    if (s->card == NULL) {
 497        return -1;
 498    }
 499
 500    return 0;
 501}
 502
 503static void pl181_class_init(ObjectClass *klass, void *data)
 504{
 505    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 506    DeviceClass *k = DEVICE_CLASS(klass);
 507
 508    sdc->init = pl181_init;
 509    k->vmsd = &vmstate_pl181;
 510    k->reset = pl181_reset;
 511    /* Reason: init() method uses drive_get_next() */
 512    k->cannot_instantiate_with_device_add_yet = true;
 513}
 514
 515static const TypeInfo pl181_info = {
 516    .name          = TYPE_PL181,
 517    .parent        = TYPE_SYS_BUS_DEVICE,
 518    .instance_size = sizeof(PL181State),
 519    .class_init    = pl181_class_init,
 520};
 521
 522static void pl181_register_types(void)
 523{
 524    type_register_static(&pl181_info);
 525}
 526
 527type_init(pl181_register_types)
 528