Statistics
| Branch: | Revision:

root / hw / pl181.c @ 3b46e624

History | View | Annotate | Download (13.5 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 "vl.h"
11
#include "sd.h"
12

    
13
//#define DEBUG_PL181 1
14

    
15
#ifdef DEBUG_PL181
16
#define DPRINTF(fmt, args...) \
17
do { printf("pl181: " fmt , ##args); } while (0)
18
#else
19
#define DPRINTF(fmt, args...) do {} while(0)
20
#endif
21

    
22
#define PL181_FIFO_LEN 16
23

    
24
typedef struct {
25
    SDState *card;
26
    uint32_t base;
27
    uint32_t clock;
28
    uint32_t power;
29
    uint32_t cmdarg;
30
    uint32_t cmd;
31
    uint32_t datatimer;
32
    uint32_t datalength;
33
    uint32_t respcmd;
34
    uint32_t response[4];
35
    uint32_t datactrl;
36
    uint32_t datacnt;
37
    uint32_t status;
38
    uint32_t mask[2];
39
    int fifo_pos;
40
    int fifo_len;
41
    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
42
       while it is reading the FIFO.  We hack around this be defering
43
       subsequent transfers until after the driver polls the status word.
44
       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
45
     */
46
    int linux_hack;
47
    uint32_t fifo[PL181_FIFO_LEN];
48
    qemu_irq irq[2];
49
} pl181_state;
50

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
346
    offset -= s->base;
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
        cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset);
409
    }
410
    pl181_update(s);
411
}
412

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

    
419
static CPUWriteMemoryFunc *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
void pl181_init(uint32_t base, BlockDriverState *bd,
450
                qemu_irq irq0, qemu_irq irq1)
451
{
452
    int iomemtype;
453
    pl181_state *s;
454

    
455
    s = (pl181_state *)qemu_mallocz(sizeof(pl181_state));
456
    iomemtype = cpu_register_io_memory(0, pl181_readfn,
457
                                       pl181_writefn, s);
458
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
459
    s->base = base;
460
    s->card = sd_init(bd);
461
    s->irq[0] = irq0;
462
    s->irq[1] = irq1;
463
    qemu_register_reset(pl181_reset, s);
464
    pl181_reset(s);
465
    /* ??? Save/restore.  */
466
}