Statistics
| Branch: | Revision:

root / hw / pl181.c @ bc3b26f5

History | View | Annotate | Download (13.7 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 licenced under the GPL.
8
 */
9

    
10
#include "sysbus.h"
11
#include "sd.h"
12
#include "sysemu.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
} pl181_state;
51

    
52
#define PL181_CMD_INDEX     0x3f
53
#define PL181_CMD_RESPONSE  (1 << 6)
54
#define PL181_CMD_LONGRESP  (1 << 7)
55
#define PL181_CMD_INTERRUPT (1 << 8)
56
#define PL181_CMD_PENDING   (1 << 9)
57
#define PL181_CMD_ENABLE    (1 << 10)
58

    
59
#define PL181_DATA_ENABLE             (1 << 0)
60
#define PL181_DATA_DIRECTION          (1 << 1)
61
#define PL181_DATA_MODE               (1 << 2)
62
#define PL181_DATA_DMAENABLE          (1 << 3)
63

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

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

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

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

    
108
static void pl181_fifo_push(pl181_state *s, uint32_t value)
109
{
110
    int n;
111

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

    
122
static uint32_t pl181_fifo_pop(pl181_state *s)
123
{
124
    uint32_t value;
125

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

    
137
static void pl181_send_command(pl181_state *s)
138
{
139
    SDRequest request;
140
    uint8_t response[16];
141
    int rlen;
142

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

    
173
error:
174
    DPRINTF("Timeout\n");
175
    s->status |= PL181_STATUS_CMDTIMEOUT;
176
}
177

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

    
182
static void pl181_fifo_run(pl181_state *s)
183
{
184
    uint32_t bits;
185
    uint32_t value;
186
    int n;
187
    int is_read;
188

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

    
261
static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
262
{
263
    pl181_state *s = (pl181_state *)opaque;
264
    uint32_t tmp;
265

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

    
343
static void pl181_write(void *opaque, target_phys_addr_t offset,
344
                          uint32_t value)
345
{
346
    pl181_state *s = (pl181_state *)opaque;
347

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

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

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

    
426
static void pl181_reset(void *opaque)
427
{
428
    pl181_state *s = (pl181_state *)opaque;
429

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

    
450
static int pl181_init(SysBusDevice *dev)
451
{
452
    int iomemtype;
453
    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
454
    BlockDriverState *bd;
455

    
456
    iomemtype = cpu_register_io_memory(pl181_readfn,
457
                                       pl181_writefn, s);
458
    sysbus_init_mmio(dev, 0x1000, iomemtype);
459
    sysbus_init_irq(dev, &s->irq[0]);
460
    sysbus_init_irq(dev, &s->irq[1]);
461
    bd = qdev_init_bdrv(&dev->qdev, IF_SD);
462
    s->card = sd_init(bd, 0);
463
    qemu_register_reset(pl181_reset, s);
464
    pl181_reset(s);
465
    /* ??? Save/restore.  */
466
    return 0;
467
}
468

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

    
474
device_init(pl181_register_devices)