Statistics
| Branch: | Revision:

root / hw / pl181.c @ 62ec4832

History | View | Annotate | Download (13.9 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 "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
    int fifo_pos;
42
    int 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
    int 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
#define PL181_CMD_INDEX     0x3f
56
#define PL181_CMD_RESPONSE  (1 << 6)
57
#define PL181_CMD_LONGRESP  (1 << 7)
58
#define PL181_CMD_INTERRUPT (1 << 8)
59
#define PL181_CMD_PENDING   (1 << 9)
60
#define PL181_CMD_ENABLE    (1 << 10)
61

    
62
#define PL181_DATA_ENABLE             (1 << 0)
63
#define PL181_DATA_DIRECTION          (1 << 1)
64
#define PL181_DATA_MODE               (1 << 2)
65
#define PL181_DATA_DMAENABLE          (1 << 3)
66

    
67
#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
68
#define PL181_STATUS_DATACRCFAIL      (1 << 1)
69
#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
70
#define PL181_STATUS_DATATIMEOUT      (1 << 3)
71
#define PL181_STATUS_TXUNDERRUN       (1 << 4)
72
#define PL181_STATUS_RXOVERRUN        (1 << 5)
73
#define PL181_STATUS_CMDRESPEND       (1 << 6)
74
#define PL181_STATUS_CMDSENT          (1 << 7)
75
#define PL181_STATUS_DATAEND          (1 << 8)
76
#define PL181_STATUS_DATABLOCKEND     (1 << 10)
77
#define PL181_STATUS_CMDACTIVE        (1 << 11)
78
#define PL181_STATUS_TXACTIVE         (1 << 12)
79
#define PL181_STATUS_RXACTIVE         (1 << 13)
80
#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
81
#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
82
#define PL181_STATUS_TXFIFOFULL       (1 << 16)
83
#define PL181_STATUS_RXFIFOFULL       (1 << 17)
84
#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
85
#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
86
#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
87
#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
88

    
89
#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
90
                             |PL181_STATUS_TXFIFOHALFEMPTY \
91
                             |PL181_STATUS_TXFIFOFULL \
92
                             |PL181_STATUS_TXFIFOEMPTY \
93
                             |PL181_STATUS_TXDATAAVLBL)
94
#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
95
                             |PL181_STATUS_RXFIFOHALFFULL \
96
                             |PL181_STATUS_RXFIFOFULL \
97
                             |PL181_STATUS_RXFIFOEMPTY \
98
                             |PL181_STATUS_RXDATAAVLBL)
99

    
100
static const unsigned char pl181_id[] =
101
{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
102

    
103
static void pl181_update(pl181_state *s)
104
{
105
    int i;
106
    for (i = 0; i < 2; i++) {
107
        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
108
    }
109
}
110

    
111
static void pl181_fifo_push(pl181_state *s, uint32_t value)
112
{
113
    int n;
114

    
115
    if (s->fifo_len == PL181_FIFO_LEN) {
116
        fprintf(stderr, "pl181: FIFO overflow\n");
117
        return;
118
    }
119
    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
120
    s->fifo_len++;
121
    s->fifo[n] = value;
122
    DPRINTF("FIFO push %08x\n", (int)value);
123
}
124

    
125
static uint32_t pl181_fifo_pop(pl181_state *s)
126
{
127
    uint32_t value;
128

    
129
    if (s->fifo_len == 0) {
130
        fprintf(stderr, "pl181: FIFO underflow\n");
131
        return 0;
132
    }
133
    value = s->fifo[s->fifo_pos];
134
    s->fifo_len--;
135
    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
136
    DPRINTF("FIFO pop %08x\n", (int)value);
137
    return value;
138
}
139

    
140
static void pl181_send_command(pl181_state *s)
141
{
142
    SDRequest request;
143
    uint8_t response[16];
144
    int rlen;
145

    
146
    request.cmd = s->cmd & PL181_CMD_INDEX;
147
    request.arg = s->cmdarg;
148
    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
149
    rlen = sd_do_command(s->card, &request, response);
150
    if (rlen < 0)
151
        goto error;
152
    if (s->cmd & PL181_CMD_RESPONSE) {
153
#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
154
                  | (response[n + 2] << 8) | response[n + 3])
155
        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
156
            goto error;
157
        if (rlen != 4 && rlen != 16)
158
            goto error;
159
        s->response[0] = RWORD(0);
160
        if (rlen == 4) {
161
            s->response[1] = s->response[2] = s->response[3] = 0;
162
        } else {
163
            s->response[1] = RWORD(4);
164
            s->response[2] = RWORD(8);
165
            s->response[3] = RWORD(12) & ~1;
166
        }
167
        DPRINTF("Response received\n");
168
        s->status |= PL181_STATUS_CMDRESPEND;
169
#undef RWORD
170
    } else {
171
        DPRINTF("Command sent\n");
172
        s->status |= PL181_STATUS_CMDSENT;
173
    }
174
    return;
175

    
176
error:
177
    DPRINTF("Timeout\n");
178
    s->status |= PL181_STATUS_CMDTIMEOUT;
179
}
180

    
181
/* Transfer data between the card and the FIFO.  This is complicated by
182
   the FIFO holding 32-bit words and the card taking data in single byte
183
   chunks.  FIFO bytes are transferred in little-endian order.  */
184

    
185
static void pl181_fifo_run(pl181_state *s)
186
{
187
    uint32_t bits;
188
    uint32_t value = 0;
189
    int n;
190
    int is_read;
191

    
192
    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
193
    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
194
            && !s->linux_hack) {
195
        if (is_read) {
196
            n = 0;
197
            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
198
                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
199
                s->datacnt--;
200
                n++;
201
                if (n == 4) {
202
                    pl181_fifo_push(s, value);
203
                    n = 0;
204
                    value = 0;
205
                }
206
            }
207
            if (n != 0) {
208
                pl181_fifo_push(s, value);
209
            }
210
        } else { /* write */
211
            n = 0;
212
            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
213
                if (n == 0) {
214
                    value = pl181_fifo_pop(s);
215
                    n = 4;
216
                }
217
                n--;
218
                s->datacnt--;
219
                sd_write_data(s->card, value & 0xff);
220
                value >>= 8;
221
            }
222
        }
223
    }
224
    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
225
    if (s->datacnt == 0) {
226
        s->status |= PL181_STATUS_DATAEND;
227
        /* HACK: */
228
        s->status |= PL181_STATUS_DATABLOCKEND;
229
        DPRINTF("Transfer Complete\n");
230
    }
231
    if (s->datacnt == 0 && s->fifo_len == 0) {
232
        s->datactrl &= ~PL181_DATA_ENABLE;
233
        DPRINTF("Data engine idle\n");
234
    } else {
235
        /* Update FIFO bits.  */
236
        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
237
        if (s->fifo_len == 0) {
238
            bits |= PL181_STATUS_TXFIFOEMPTY;
239
            bits |= PL181_STATUS_RXFIFOEMPTY;
240
        } else {
241
            bits |= PL181_STATUS_TXDATAAVLBL;
242
            bits |= PL181_STATUS_RXDATAAVLBL;
243
        }
244
        if (s->fifo_len == 16) {
245
            bits |= PL181_STATUS_TXFIFOFULL;
246
            bits |= PL181_STATUS_RXFIFOFULL;
247
        }
248
        if (s->fifo_len <= 8) {
249
            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
250
        }
251
        if (s->fifo_len >= 8) {
252
            bits |= PL181_STATUS_RXFIFOHALFFULL;
253
        }
254
        if (s->datactrl & PL181_DATA_DIRECTION) {
255
            bits &= PL181_STATUS_RX_FIFO;
256
        } else {
257
            bits &= PL181_STATUS_TX_FIFO;
258
        }
259
        s->status |= bits;
260
    }
261
}
262

    
263
static uint64_t pl181_read(void *opaque, target_phys_addr_t offset,
264
                           unsigned size)
265
{
266
    pl181_state *s = (pl181_state *)opaque;
267
    uint32_t tmp;
268

    
269
    if (offset >= 0xfe0 && offset < 0x1000) {
270
        return pl181_id[(offset - 0xfe0) >> 2];
271
    }
272
    switch (offset) {
273
    case 0x00: /* Power */
274
        return s->power;
275
    case 0x04: /* Clock */
276
        return s->clock;
277
    case 0x08: /* Argument */
278
        return s->cmdarg;
279
    case 0x0c: /* Command */
280
        return s->cmd;
281
    case 0x10: /* RespCmd */
282
        return s->respcmd;
283
    case 0x14: /* Response0 */
284
        return s->response[0];
285
    case 0x18: /* Response1 */
286
        return s->response[1];
287
    case 0x1c: /* Response2 */
288
        return s->response[2];
289
    case 0x20: /* Response3 */
290
        return s->response[3];
291
    case 0x24: /* DataTimer */
292
        return s->datatimer;
293
    case 0x28: /* DataLength */
294
        return s->datalength;
295
    case 0x2c: /* DataCtrl */
296
        return s->datactrl;
297
    case 0x30: /* DataCnt */
298
        return s->datacnt;
299
    case 0x34: /* Status */
300
        tmp = s->status;
301
        if (s->linux_hack) {
302
            s->linux_hack = 0;
303
            pl181_fifo_run(s);
304
            pl181_update(s);
305
        }
306
        return tmp;
307
    case 0x3c: /* Mask0 */
308
        return s->mask[0];
309
    case 0x40: /* Mask1 */
310
        return s->mask[1];
311
    case 0x48: /* FifoCnt */
312
        /* The documentation is somewhat vague about exactly what FifoCnt
313
           does.  On real hardware it appears to be when decrememnted
314
           when a word is transferred between the FIFO and the serial
315
           data engine.  DataCnt is decremented after each byte is
316
           transferred between the serial engine and the card.
317
           We don't emulate this level of detail, so both can be the same.  */
318
        tmp = (s->datacnt + 3) >> 2;
319
        if (s->linux_hack) {
320
            s->linux_hack = 0;
321
            pl181_fifo_run(s);
322
            pl181_update(s);
323
        }
324
        return tmp;
325
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
326
    case 0x90: case 0x94: case 0x98: case 0x9c:
327
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
328
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
329
        if (s->fifo_len == 0) {
330
            fprintf(stderr, "pl181: Unexpected FIFO read\n");
331
            return 0;
332
        } else {
333
            uint32_t value;
334
            value = pl181_fifo_pop(s);
335
            s->linux_hack = 1;
336
            pl181_fifo_run(s);
337
            pl181_update(s);
338
            return value;
339
        }
340
    default:
341
        hw_error("pl181_read: Bad offset %x\n", (int)offset);
342
        return 0;
343
    }
344
}
345

    
346
static void pl181_write(void *opaque, target_phys_addr_t offset,
347
                        uint64_t value, unsigned size)
348
{
349
    pl181_state *s = (pl181_state *)opaque;
350

    
351
    switch (offset) {
352
    case 0x00: /* Power */
353
        s->power = value & 0xff;
354
        break;
355
    case 0x04: /* Clock */
356
        s->clock = value & 0xff;
357
        break;
358
    case 0x08: /* Argument */
359
        s->cmdarg = value;
360
        break;
361
    case 0x0c: /* Command */
362
        s->cmd = value;
363
        if (s->cmd & PL181_CMD_ENABLE) {
364
            if (s->cmd & PL181_CMD_INTERRUPT) {
365
                fprintf(stderr, "pl181: Interrupt mode not implemented\n");
366
                abort();
367
            } if (s->cmd & PL181_CMD_PENDING) {
368
                fprintf(stderr, "pl181: Pending commands not implemented\n");
369
                abort();
370
            } else {
371
                pl181_send_command(s);
372
                pl181_fifo_run(s);
373
            }
374
            /* The command has completed one way or the other.  */
375
            s->cmd &= ~PL181_CMD_ENABLE;
376
        }
377
        break;
378
    case 0x24: /* DataTimer */
379
        s->datatimer = value;
380
        break;
381
    case 0x28: /* DataLength */
382
        s->datalength = value & 0xffff;
383
        break;
384
    case 0x2c: /* DataCtrl */
385
        s->datactrl = value & 0xff;
386
        if (value & PL181_DATA_ENABLE) {
387
            s->datacnt = s->datalength;
388
            pl181_fifo_run(s);
389
        }
390
        break;
391
    case 0x38: /* Clear */
392
        s->status &= ~(value & 0x7ff);
393
        break;
394
    case 0x3c: /* Mask0 */
395
        s->mask[0] = value;
396
        break;
397
    case 0x40: /* Mask1 */
398
        s->mask[1] = value;
399
        break;
400
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
401
    case 0x90: case 0x94: case 0x98: case 0x9c:
402
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
403
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
404
        if (s->datacnt == 0) {
405
            fprintf(stderr, "pl181: Unexpected FIFO write\n");
406
        } else {
407
            pl181_fifo_push(s, value);
408
            pl181_fifo_run(s);
409
        }
410
        break;
411
    default:
412
        hw_error("pl181_write: Bad offset %x\n", (int)offset);
413
    }
414
    pl181_update(s);
415
}
416

    
417
static const MemoryRegionOps pl181_ops = {
418
    .read = pl181_read,
419
    .write = pl181_write,
420
    .endianness = DEVICE_NATIVE_ENDIAN,
421
};
422

    
423
static void pl181_reset(void *opaque)
424
{
425
    pl181_state *s = (pl181_state *)opaque;
426

    
427
    s->power = 0;
428
    s->cmdarg = 0;
429
    s->cmd = 0;
430
    s->datatimer = 0;
431
    s->datalength = 0;
432
    s->respcmd = 0;
433
    s->response[0] = 0;
434
    s->response[1] = 0;
435
    s->response[2] = 0;
436
    s->response[3] = 0;
437
    s->datatimer = 0;
438
    s->datalength = 0;
439
    s->datactrl = 0;
440
    s->datacnt = 0;
441
    s->status = 0;
442
    s->linux_hack = 0;
443
    s->mask[0] = 0;
444
    s->mask[1] = 0;
445

    
446
    /* We can assume our GPIO outputs have been wired up now */
447
    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
448
}
449

    
450
static int pl181_init(SysBusDevice *dev)
451
{
452
    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
453
    DriveInfo *dinfo;
454

    
455
    memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
456
    sysbus_init_mmio(dev, &s->iomem);
457
    sysbus_init_irq(dev, &s->irq[0]);
458
    sysbus_init_irq(dev, &s->irq[1]);
459
    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
460
    dinfo = drive_get_next(IF_SD);
461
    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
462
    qemu_register_reset(pl181_reset, s);
463
    pl181_reset(s);
464
    /* ??? Save/restore.  */
465
    return 0;
466
}
467

    
468
static void pl181_register_devices(void)
469
{
470
    sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
471
}
472

    
473
device_init(pl181_register_devices)