Statistics
| Branch: | Revision:

root / hw / pl181.c @ 22ed1d34

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

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

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

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

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

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

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

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

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

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

    
455
    iomemtype = cpu_register_io_memory(pl181_readfn,
456
                                       pl181_writefn, s);
457
    sysbus_init_mmio(dev, 0x1000, iomemtype);
458
    sysbus_init_irq(dev, &s->irq[0]);
459
    sysbus_init_irq(dev, &s->irq[1]);
460
    bd = qdev_init_bdrv(&dev->qdev, IF_SD);
461
    s->card = sd_init(bd, 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)