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