Ejemplo n.º 1
0
static void pl181_fifo_run(pl181_state *s)
{
    uint32_t bits;
    uint32_t value;
    int n;
    int limit;
    int is_read;

    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
            && !s->linux_hack) {
        limit = is_read ? PL181_FIFO_LEN : 0;
        n = 0;
        value = 0;
        while (s->datacnt && s->fifo_len != limit) {
            if (is_read) {
                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
                n++;
                if (n == 4) {
                    pl181_fifo_push(s, value);
                    value = 0;
                    n = 0;
                }
            } else {
                if (n == 0) {
                    value = pl181_fifo_pop(s);
                    n = 4;
                }
                sd_write_data(s->card, value & 0xff);
                value >>= 8;
                n--;
            }
            s->datacnt--;
        }
        if (n && is_read) {
            pl181_fifo_push(s, value);
        }
    }
Ejemplo n.º 2
0
Archivo: pl181.c Proyecto: poblces/qemu
static uint64_t pl181_read(void *opaque, hwaddr offset,
                           unsigned size)
{
    pl181_state *s = (pl181_state *)opaque;
    uint32_t tmp;

    if (offset >= 0xfe0 && offset < 0x1000) {
        return pl181_id[(offset - 0xfe0) >> 2];
    }
    switch (offset) {
    case 0x00: /* Power */
        return s->power;
    case 0x04: /* Clock */
        return s->clock;
    case 0x08: /* Argument */
        return s->cmdarg;
    case 0x0c: /* Command */
        return s->cmd;
    case 0x10: /* RespCmd */
        return s->respcmd;
    case 0x14: /* Response0 */
        return s->response[0];
    case 0x18: /* Response1 */
        return s->response[1];
    case 0x1c: /* Response2 */
        return s->response[2];
    case 0x20: /* Response3 */
        return s->response[3];
    case 0x24: /* DataTimer */
        return s->datatimer;
    case 0x28: /* DataLength */
        return s->datalength;
    case 0x2c: /* DataCtrl */
        return s->datactrl;
    case 0x30: /* DataCnt */
        return s->datacnt;
    case 0x34: /* Status */
        tmp = s->status;
        if (s->linux_hack) {
            s->linux_hack = 0;
            pl181_fifo_run(s);
            pl181_update(s);
        }
        return tmp;
    case 0x3c: /* Mask0 */
        return s->mask[0];
    case 0x40: /* Mask1 */
        return s->mask[1];
    case 0x48: /* FifoCnt */
        /* The documentation is somewhat vague about exactly what FifoCnt
           does.  On real hardware it appears to be when decrememnted
           when a word is transferred between the FIFO and the serial
           data engine.  DataCnt is decremented after each byte is
           transferred between the serial engine and the card.
           We don't emulate this level of detail, so both can be the same.  */
        tmp = (s->datacnt + 3) >> 2;
        if (s->linux_hack) {
            s->linux_hack = 0;
            pl181_fifo_run(s);
            pl181_update(s);
        }
        return tmp;
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
    case 0x90: case 0x94: case 0x98: case 0x9c:
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
        if (s->fifo_len == 0) {
            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
            return 0;
        } else {
            uint32_t value;
            value = pl181_fifo_pop(s);
            s->linux_hack = 1;
            pl181_fifo_run(s);
            pl181_update(s);
            return value;
        }
    default:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "pl181_read: Bad offset %x\n", (int)offset);
        return 0;
    }
}
Ejemplo n.º 3
0
Archivo: pl181.c Proyecto: poblces/qemu
static void pl181_fifo_run(pl181_state *s)
{
    uint32_t bits;
    uint32_t value = 0;
    int n;
    int is_read;

    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
            && !s->linux_hack) {
        if (is_read) {
            n = 0;
            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
                s->datacnt--;
                n++;
                if (n == 4) {
                    pl181_fifo_push(s, value);
                    n = 0;
                    value = 0;
                }
            }
            if (n != 0) {
                pl181_fifo_push(s, value);
            }
        } else { /* write */
            n = 0;
            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
                if (n == 0) {
                    value = pl181_fifo_pop(s);
                    n = 4;
                }
                n--;
                s->datacnt--;
                sd_write_data(s->card, value & 0xff);
                value >>= 8;
            }
        }
    }
    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
    if (s->datacnt == 0) {
        s->status |= PL181_STATUS_DATAEND;
        /* HACK: */
        s->status |= PL181_STATUS_DATABLOCKEND;
        DPRINTF("Transfer Complete\n");
    }
    if (s->datacnt == 0 && s->fifo_len == 0) {
        s->datactrl &= ~PL181_DATA_ENABLE;
        DPRINTF("Data engine idle\n");
    } else {
        /* Update FIFO bits.  */
        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
        if (s->fifo_len == 0) {
            bits |= PL181_STATUS_TXFIFOEMPTY;
            bits |= PL181_STATUS_RXFIFOEMPTY;
        } else {
            bits |= PL181_STATUS_TXDATAAVLBL;
            bits |= PL181_STATUS_RXDATAAVLBL;
        }
        if (s->fifo_len == 16) {
            bits |= PL181_STATUS_TXFIFOFULL;
            bits |= PL181_STATUS_RXFIFOFULL;
        }
        if (s->fifo_len <= 8) {
            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
        }
        if (s->fifo_len >= 8) {
            bits |= PL181_STATUS_RXFIFOHALFFULL;
        }
        if (s->datactrl & PL181_DATA_DIRECTION) {
            bits &= PL181_STATUS_RX_FIFO;
        } else {
            bits &= PL181_STATUS_TX_FIFO;
        }
        s->status |= bits;
    }
}