Statistics
| Branch: | Revision:

root / hw / pl181.c @ 8e31bf38

History | View | Annotate | Download (14 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
    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

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

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

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

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

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

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

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

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

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

    
415
static CPUReadMemoryFunc * const pl181_readfn[] = {
416
   pl181_read,
417
   pl181_read,
418
   pl181_read
419
};
420

    
421
static CPUWriteMemoryFunc * const pl181_writefn[] = {
422
   pl181_write,
423
   pl181_write,
424
   pl181_write
425
};
426

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

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

    
474
static void pl181_register_devices(void)
475
{
476
    sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
477
}
478

    
479
device_init(pl181_register_devices)