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