Statistics
| Branch: | Revision:

root / hw / pl181.c @ 9c17d615

History | View | Annotate | Download (15.4 kB)

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, ...) \
18
do { 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

    
25
typedef 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

    
55
static 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

    
125
static const unsigned char pl181_id[] =
126
{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
127

    
128
static 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

    
136
static 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

    
150
static 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

    
165
static 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

    
201
error:
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

    
210
static 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

    
288
static 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

    
372
static 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

    
444
static const MemoryRegionOps pl181_ops = {
445
    .read = pl181_read,
446
    .write = pl181_write,
447
    .endianness = DEVICE_NATIVE_ENDIAN,
448
};
449

    
450
static 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

    
477
static 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

    
492
static 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

    
503
static 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

    
510
static void pl181_register_types(void)
511
{
512
    type_register_static(&pl181_info);
513
}
514

    
515
type_init(pl181_register_types)