Statistics
| Branch: | Revision:

root / hw / pl181.c @ 62ec4832

History | View | Annotate | Download (13.9 kB)

1 5fafdf24 ths
/*
2 a1bb27b1 pbrook
 * Arm PrimeCell PL181 MultiMedia Card Interface
3 a1bb27b1 pbrook
 *
4 a1bb27b1 pbrook
 * Copyright (c) 2007 CodeSourcery.
5 a1bb27b1 pbrook
 * Written by Paul Brook
6 a1bb27b1 pbrook
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL.
8 a1bb27b1 pbrook
 */
9 a1bb27b1 pbrook
10 13839974 Markus Armbruster
#include "blockdev.h"
11 aa9311d8 Paul Brook
#include "sysbus.h"
12 a1bb27b1 pbrook
#include "sd.h"
13 a1bb27b1 pbrook
14 a1bb27b1 pbrook
//#define DEBUG_PL181 1
15 a1bb27b1 pbrook
16 a1bb27b1 pbrook
#ifdef DEBUG_PL181
17 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
18 001faf32 Blue Swirl
do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
19 a1bb27b1 pbrook
#else
20 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
21 a1bb27b1 pbrook
#endif
22 a1bb27b1 pbrook
23 a1bb27b1 pbrook
#define PL181_FIFO_LEN 16
24 a1bb27b1 pbrook
25 a1bb27b1 pbrook
typedef struct {
26 aa9311d8 Paul Brook
    SysBusDevice busdev;
27 ca45842a Avi Kivity
    MemoryRegion iomem;
28 42a10898 pbrook
    SDState *card;
29 a1bb27b1 pbrook
    uint32_t clock;
30 a1bb27b1 pbrook
    uint32_t power;
31 a1bb27b1 pbrook
    uint32_t cmdarg;
32 a1bb27b1 pbrook
    uint32_t cmd;
33 a1bb27b1 pbrook
    uint32_t datatimer;
34 a1bb27b1 pbrook
    uint32_t datalength;
35 a1bb27b1 pbrook
    uint32_t respcmd;
36 a1bb27b1 pbrook
    uint32_t response[4];
37 a1bb27b1 pbrook
    uint32_t datactrl;
38 a1bb27b1 pbrook
    uint32_t datacnt;
39 a1bb27b1 pbrook
    uint32_t status;
40 a1bb27b1 pbrook
    uint32_t mask[2];
41 a1bb27b1 pbrook
    int fifo_pos;
42 a1bb27b1 pbrook
    int fifo_len;
43 6361cdb6 pbrook
    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
44 6361cdb6 pbrook
       while it is reading the FIFO.  We hack around this be defering
45 6361cdb6 pbrook
       subsequent transfers until after the driver polls the status word.
46 6361cdb6 pbrook
       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
47 6361cdb6 pbrook
     */
48 6361cdb6 pbrook
    int linux_hack;
49 a1bb27b1 pbrook
    uint32_t fifo[PL181_FIFO_LEN];
50 d537cf6c pbrook
    qemu_irq irq[2];
51 c31a4724 Peter Maydell
    /* GPIO outputs for 'card is readonly' and 'card inserted' */
52 c31a4724 Peter Maydell
    qemu_irq cardstatus[2];
53 a1bb27b1 pbrook
} pl181_state;
54 a1bb27b1 pbrook
55 a1bb27b1 pbrook
#define PL181_CMD_INDEX     0x3f
56 a1bb27b1 pbrook
#define PL181_CMD_RESPONSE  (1 << 6)
57 a1bb27b1 pbrook
#define PL181_CMD_LONGRESP  (1 << 7)
58 a1bb27b1 pbrook
#define PL181_CMD_INTERRUPT (1 << 8)
59 a1bb27b1 pbrook
#define PL181_CMD_PENDING   (1 << 9)
60 a1bb27b1 pbrook
#define PL181_CMD_ENABLE    (1 << 10)
61 a1bb27b1 pbrook
62 a1bb27b1 pbrook
#define PL181_DATA_ENABLE             (1 << 0)
63 a1bb27b1 pbrook
#define PL181_DATA_DIRECTION          (1 << 1)
64 a1bb27b1 pbrook
#define PL181_DATA_MODE               (1 << 2)
65 a1bb27b1 pbrook
#define PL181_DATA_DMAENABLE          (1 << 3)
66 a1bb27b1 pbrook
67 a1bb27b1 pbrook
#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
68 a1bb27b1 pbrook
#define PL181_STATUS_DATACRCFAIL      (1 << 1)
69 a1bb27b1 pbrook
#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
70 a1bb27b1 pbrook
#define PL181_STATUS_DATATIMEOUT      (1 << 3)
71 a1bb27b1 pbrook
#define PL181_STATUS_TXUNDERRUN       (1 << 4)
72 a1bb27b1 pbrook
#define PL181_STATUS_RXOVERRUN        (1 << 5)
73 a1bb27b1 pbrook
#define PL181_STATUS_CMDRESPEND       (1 << 6)
74 a1bb27b1 pbrook
#define PL181_STATUS_CMDSENT          (1 << 7)
75 a1bb27b1 pbrook
#define PL181_STATUS_DATAEND          (1 << 8)
76 a1bb27b1 pbrook
#define PL181_STATUS_DATABLOCKEND     (1 << 10)
77 a1bb27b1 pbrook
#define PL181_STATUS_CMDACTIVE        (1 << 11)
78 a1bb27b1 pbrook
#define PL181_STATUS_TXACTIVE         (1 << 12)
79 a1bb27b1 pbrook
#define PL181_STATUS_RXACTIVE         (1 << 13)
80 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
81 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
82 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOFULL       (1 << 16)
83 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOFULL       (1 << 17)
84 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
85 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
86 a1bb27b1 pbrook
#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
87 a1bb27b1 pbrook
#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
88 a1bb27b1 pbrook
89 a1bb27b1 pbrook
#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
90 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOHALFEMPTY \
91 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOFULL \
92 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOEMPTY \
93 a1bb27b1 pbrook
                             |PL181_STATUS_TXDATAAVLBL)
94 a1bb27b1 pbrook
#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
95 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOHALFFULL \
96 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOFULL \
97 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOEMPTY \
98 a1bb27b1 pbrook
                             |PL181_STATUS_RXDATAAVLBL)
99 a1bb27b1 pbrook
100 a1bb27b1 pbrook
static const unsigned char pl181_id[] =
101 a1bb27b1 pbrook
{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
102 a1bb27b1 pbrook
103 a1bb27b1 pbrook
static void pl181_update(pl181_state *s)
104 a1bb27b1 pbrook
{
105 a1bb27b1 pbrook
    int i;
106 a1bb27b1 pbrook
    for (i = 0; i < 2; i++) {
107 d537cf6c pbrook
        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
108 a1bb27b1 pbrook
    }
109 a1bb27b1 pbrook
}
110 a1bb27b1 pbrook
111 a1bb27b1 pbrook
static void pl181_fifo_push(pl181_state *s, uint32_t value)
112 a1bb27b1 pbrook
{
113 a1bb27b1 pbrook
    int n;
114 a1bb27b1 pbrook
115 a1bb27b1 pbrook
    if (s->fifo_len == PL181_FIFO_LEN) {
116 a1bb27b1 pbrook
        fprintf(stderr, "pl181: FIFO overflow\n");
117 a1bb27b1 pbrook
        return;
118 a1bb27b1 pbrook
    }
119 a1bb27b1 pbrook
    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
120 a1bb27b1 pbrook
    s->fifo_len++;
121 a1bb27b1 pbrook
    s->fifo[n] = value;
122 a1bb27b1 pbrook
    DPRINTF("FIFO push %08x\n", (int)value);
123 a1bb27b1 pbrook
}
124 a1bb27b1 pbrook
125 a1bb27b1 pbrook
static uint32_t pl181_fifo_pop(pl181_state *s)
126 a1bb27b1 pbrook
{
127 a1bb27b1 pbrook
    uint32_t value;
128 a1bb27b1 pbrook
129 a1bb27b1 pbrook
    if (s->fifo_len == 0) {
130 a1bb27b1 pbrook
        fprintf(stderr, "pl181: FIFO underflow\n");
131 a1bb27b1 pbrook
        return 0;
132 a1bb27b1 pbrook
    }
133 a1bb27b1 pbrook
    value = s->fifo[s->fifo_pos];
134 a1bb27b1 pbrook
    s->fifo_len--;
135 a1bb27b1 pbrook
    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
136 a1bb27b1 pbrook
    DPRINTF("FIFO pop %08x\n", (int)value);
137 a1bb27b1 pbrook
    return value;
138 a1bb27b1 pbrook
}
139 a1bb27b1 pbrook
140 a1bb27b1 pbrook
static void pl181_send_command(pl181_state *s)
141 a1bb27b1 pbrook
{
142 bc24a225 Paul Brook
    SDRequest request;
143 a1bb27b1 pbrook
    uint8_t response[16];
144 a1bb27b1 pbrook
    int rlen;
145 a1bb27b1 pbrook
146 a1bb27b1 pbrook
    request.cmd = s->cmd & PL181_CMD_INDEX;
147 a1bb27b1 pbrook
    request.arg = s->cmdarg;
148 a1bb27b1 pbrook
    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
149 a1bb27b1 pbrook
    rlen = sd_do_command(s->card, &request, response);
150 a1bb27b1 pbrook
    if (rlen < 0)
151 a1bb27b1 pbrook
        goto error;
152 a1bb27b1 pbrook
    if (s->cmd & PL181_CMD_RESPONSE) {
153 a1bb27b1 pbrook
#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
154 a1bb27b1 pbrook
                  | (response[n + 2] << 8) | response[n + 3])
155 a1bb27b1 pbrook
        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
156 a1bb27b1 pbrook
            goto error;
157 a1bb27b1 pbrook
        if (rlen != 4 && rlen != 16)
158 a1bb27b1 pbrook
            goto error;
159 a1bb27b1 pbrook
        s->response[0] = RWORD(0);
160 a1bb27b1 pbrook
        if (rlen == 4) {
161 a1bb27b1 pbrook
            s->response[1] = s->response[2] = s->response[3] = 0;
162 a1bb27b1 pbrook
        } else {
163 a1bb27b1 pbrook
            s->response[1] = RWORD(4);
164 a1bb27b1 pbrook
            s->response[2] = RWORD(8);
165 a1bb27b1 pbrook
            s->response[3] = RWORD(12) & ~1;
166 a1bb27b1 pbrook
        }
167 aa1f17c1 ths
        DPRINTF("Response received\n");
168 a1bb27b1 pbrook
        s->status |= PL181_STATUS_CMDRESPEND;
169 a1bb27b1 pbrook
#undef RWORD
170 a1bb27b1 pbrook
    } else {
171 a1bb27b1 pbrook
        DPRINTF("Command sent\n");
172 a1bb27b1 pbrook
        s->status |= PL181_STATUS_CMDSENT;
173 a1bb27b1 pbrook
    }
174 a1bb27b1 pbrook
    return;
175 a1bb27b1 pbrook
176 a1bb27b1 pbrook
error:
177 a1bb27b1 pbrook
    DPRINTF("Timeout\n");
178 a1bb27b1 pbrook
    s->status |= PL181_STATUS_CMDTIMEOUT;
179 a1bb27b1 pbrook
}
180 a1bb27b1 pbrook
181 aa1f17c1 ths
/* Transfer data between the card and the FIFO.  This is complicated by
182 a1bb27b1 pbrook
   the FIFO holding 32-bit words and the card taking data in single byte
183 a1bb27b1 pbrook
   chunks.  FIFO bytes are transferred in little-endian order.  */
184 3b46e624 ths
185 a1bb27b1 pbrook
static void pl181_fifo_run(pl181_state *s)
186 a1bb27b1 pbrook
{
187 a1bb27b1 pbrook
    uint32_t bits;
188 f21126df Blue Swirl
    uint32_t value = 0;
189 a1bb27b1 pbrook
    int n;
190 a1bb27b1 pbrook
    int is_read;
191 a1bb27b1 pbrook
192 a1bb27b1 pbrook
    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
193 6361cdb6 pbrook
    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
194 6361cdb6 pbrook
            && !s->linux_hack) {
195 bc3b26f5 Paul Brook
        if (is_read) {
196 bc3b26f5 Paul Brook
            n = 0;
197 bc3b26f5 Paul Brook
            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
198 a1bb27b1 pbrook
                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
199 bc3b26f5 Paul Brook
                s->datacnt--;
200 a1bb27b1 pbrook
                n++;
201 a1bb27b1 pbrook
                if (n == 4) {
202 a1bb27b1 pbrook
                    pl181_fifo_push(s, value);
203 a1bb27b1 pbrook
                    n = 0;
204 bc3b26f5 Paul Brook
                    value = 0;
205 a1bb27b1 pbrook
                }
206 bc3b26f5 Paul Brook
            }
207 bc3b26f5 Paul Brook
            if (n != 0) {
208 bc3b26f5 Paul Brook
                pl181_fifo_push(s, value);
209 bc3b26f5 Paul Brook
            }
210 bc3b26f5 Paul Brook
        } else { /* write */
211 bc3b26f5 Paul Brook
            n = 0;
212 bc3b26f5 Paul Brook
            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
213 a1bb27b1 pbrook
                if (n == 0) {
214 a1bb27b1 pbrook
                    value = pl181_fifo_pop(s);
215 a1bb27b1 pbrook
                    n = 4;
216 a1bb27b1 pbrook
                }
217 bc3b26f5 Paul Brook
                n--;
218 bc3b26f5 Paul Brook
                s->datacnt--;
219 a1bb27b1 pbrook
                sd_write_data(s->card, value & 0xff);
220 a1bb27b1 pbrook
                value >>= 8;
221 a1bb27b1 pbrook
            }
222 a1bb27b1 pbrook
        }
223 a1bb27b1 pbrook
    }
224 a1bb27b1 pbrook
    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
225 a1bb27b1 pbrook
    if (s->datacnt == 0) {
226 a1bb27b1 pbrook
        s->status |= PL181_STATUS_DATAEND;
227 a1bb27b1 pbrook
        /* HACK: */
228 a1bb27b1 pbrook
        s->status |= PL181_STATUS_DATABLOCKEND;
229 a1bb27b1 pbrook
        DPRINTF("Transfer Complete\n");
230 a1bb27b1 pbrook
    }
231 6361cdb6 pbrook
    if (s->datacnt == 0 && s->fifo_len == 0) {
232 a1bb27b1 pbrook
        s->datactrl &= ~PL181_DATA_ENABLE;
233 a1bb27b1 pbrook
        DPRINTF("Data engine idle\n");
234 a1bb27b1 pbrook
    } else {
235 a1bb27b1 pbrook
        /* Update FIFO bits.  */
236 a1bb27b1 pbrook
        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
237 a1bb27b1 pbrook
        if (s->fifo_len == 0) {
238 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOEMPTY;
239 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOEMPTY;
240 a1bb27b1 pbrook
        } else {
241 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXDATAAVLBL;
242 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXDATAAVLBL;
243 a1bb27b1 pbrook
        }
244 a1bb27b1 pbrook
        if (s->fifo_len == 16) {
245 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOFULL;
246 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOFULL;
247 a1bb27b1 pbrook
        }
248 a1bb27b1 pbrook
        if (s->fifo_len <= 8) {
249 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
250 a1bb27b1 pbrook
        }
251 a1bb27b1 pbrook
        if (s->fifo_len >= 8) {
252 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOHALFFULL;
253 a1bb27b1 pbrook
        }
254 a1bb27b1 pbrook
        if (s->datactrl & PL181_DATA_DIRECTION) {
255 a1bb27b1 pbrook
            bits &= PL181_STATUS_RX_FIFO;
256 a1bb27b1 pbrook
        } else {
257 a1bb27b1 pbrook
            bits &= PL181_STATUS_TX_FIFO;
258 a1bb27b1 pbrook
        }
259 a1bb27b1 pbrook
        s->status |= bits;
260 a1bb27b1 pbrook
    }
261 a1bb27b1 pbrook
}
262 a1bb27b1 pbrook
263 ca45842a Avi Kivity
static uint64_t pl181_read(void *opaque, target_phys_addr_t offset,
264 ca45842a Avi Kivity
                           unsigned size)
265 a1bb27b1 pbrook
{
266 a1bb27b1 pbrook
    pl181_state *s = (pl181_state *)opaque;
267 6361cdb6 pbrook
    uint32_t tmp;
268 a1bb27b1 pbrook
269 a1bb27b1 pbrook
    if (offset >= 0xfe0 && offset < 0x1000) {
270 a1bb27b1 pbrook
        return pl181_id[(offset - 0xfe0) >> 2];
271 a1bb27b1 pbrook
    }
272 a1bb27b1 pbrook
    switch (offset) {
273 a1bb27b1 pbrook
    case 0x00: /* Power */
274 a1bb27b1 pbrook
        return s->power;
275 a1bb27b1 pbrook
    case 0x04: /* Clock */
276 a1bb27b1 pbrook
        return s->clock;
277 a1bb27b1 pbrook
    case 0x08: /* Argument */
278 a1bb27b1 pbrook
        return s->cmdarg;
279 a1bb27b1 pbrook
    case 0x0c: /* Command */
280 a1bb27b1 pbrook
        return s->cmd;
281 a1bb27b1 pbrook
    case 0x10: /* RespCmd */
282 a1bb27b1 pbrook
        return s->respcmd;
283 a1bb27b1 pbrook
    case 0x14: /* Response0 */
284 a1bb27b1 pbrook
        return s->response[0];
285 a1bb27b1 pbrook
    case 0x18: /* Response1 */
286 a1bb27b1 pbrook
        return s->response[1];
287 a1bb27b1 pbrook
    case 0x1c: /* Response2 */
288 a1bb27b1 pbrook
        return s->response[2];
289 a1bb27b1 pbrook
    case 0x20: /* Response3 */
290 a1bb27b1 pbrook
        return s->response[3];
291 a1bb27b1 pbrook
    case 0x24: /* DataTimer */
292 a1bb27b1 pbrook
        return s->datatimer;
293 a1bb27b1 pbrook
    case 0x28: /* DataLength */
294 a1bb27b1 pbrook
        return s->datalength;
295 a1bb27b1 pbrook
    case 0x2c: /* DataCtrl */
296 a1bb27b1 pbrook
        return s->datactrl;
297 a1bb27b1 pbrook
    case 0x30: /* DataCnt */
298 a1bb27b1 pbrook
        return s->datacnt;
299 a1bb27b1 pbrook
    case 0x34: /* Status */
300 6361cdb6 pbrook
        tmp = s->status;
301 6361cdb6 pbrook
        if (s->linux_hack) {
302 6361cdb6 pbrook
            s->linux_hack = 0;
303 6361cdb6 pbrook
            pl181_fifo_run(s);
304 6361cdb6 pbrook
            pl181_update(s);
305 6361cdb6 pbrook
        }
306 6361cdb6 pbrook
        return tmp;
307 a1bb27b1 pbrook
    case 0x3c: /* Mask0 */
308 a1bb27b1 pbrook
        return s->mask[0];
309 a1bb27b1 pbrook
    case 0x40: /* Mask1 */
310 a1bb27b1 pbrook
        return s->mask[1];
311 a1bb27b1 pbrook
    case 0x48: /* FifoCnt */
312 6361cdb6 pbrook
        /* The documentation is somewhat vague about exactly what FifoCnt
313 6361cdb6 pbrook
           does.  On real hardware it appears to be when decrememnted
314 66a0a2cb Dong Xu Wang
           when a word is transferred between the FIFO and the serial
315 6361cdb6 pbrook
           data engine.  DataCnt is decremented after each byte is
316 66a0a2cb Dong Xu Wang
           transferred between the serial engine and the card.
317 6361cdb6 pbrook
           We don't emulate this level of detail, so both can be the same.  */
318 6361cdb6 pbrook
        tmp = (s->datacnt + 3) >> 2;
319 6361cdb6 pbrook
        if (s->linux_hack) {
320 6361cdb6 pbrook
            s->linux_hack = 0;
321 6361cdb6 pbrook
            pl181_fifo_run(s);
322 6361cdb6 pbrook
            pl181_update(s);
323 6361cdb6 pbrook
        }
324 6361cdb6 pbrook
        return tmp;
325 a1bb27b1 pbrook
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
326 a1bb27b1 pbrook
    case 0x90: case 0x94: case 0x98: case 0x9c:
327 a1bb27b1 pbrook
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
328 a1bb27b1 pbrook
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
329 6361cdb6 pbrook
        if (s->fifo_len == 0) {
330 a1bb27b1 pbrook
            fprintf(stderr, "pl181: Unexpected FIFO read\n");
331 a1bb27b1 pbrook
            return 0;
332 a1bb27b1 pbrook
        } else {
333 a1bb27b1 pbrook
            uint32_t value;
334 a1bb27b1 pbrook
            value = pl181_fifo_pop(s);
335 6361cdb6 pbrook
            s->linux_hack = 1;
336 a1bb27b1 pbrook
            pl181_fifo_run(s);
337 a1bb27b1 pbrook
            pl181_update(s);
338 a1bb27b1 pbrook
            return value;
339 a1bb27b1 pbrook
        }
340 a1bb27b1 pbrook
    default:
341 2ac71179 Paul Brook
        hw_error("pl181_read: Bad offset %x\n", (int)offset);
342 a1bb27b1 pbrook
        return 0;
343 a1bb27b1 pbrook
    }
344 a1bb27b1 pbrook
}
345 a1bb27b1 pbrook
346 c227f099 Anthony Liguori
static void pl181_write(void *opaque, target_phys_addr_t offset,
347 ca45842a Avi Kivity
                        uint64_t value, unsigned size)
348 a1bb27b1 pbrook
{
349 a1bb27b1 pbrook
    pl181_state *s = (pl181_state *)opaque;
350 a1bb27b1 pbrook
351 a1bb27b1 pbrook
    switch (offset) {
352 a1bb27b1 pbrook
    case 0x00: /* Power */
353 a1bb27b1 pbrook
        s->power = value & 0xff;
354 a1bb27b1 pbrook
        break;
355 a1bb27b1 pbrook
    case 0x04: /* Clock */
356 a1bb27b1 pbrook
        s->clock = value & 0xff;
357 a1bb27b1 pbrook
        break;
358 a1bb27b1 pbrook
    case 0x08: /* Argument */
359 a1bb27b1 pbrook
        s->cmdarg = value;
360 a1bb27b1 pbrook
        break;
361 a1bb27b1 pbrook
    case 0x0c: /* Command */
362 a1bb27b1 pbrook
        s->cmd = value;
363 a1bb27b1 pbrook
        if (s->cmd & PL181_CMD_ENABLE) {
364 a1bb27b1 pbrook
            if (s->cmd & PL181_CMD_INTERRUPT) {
365 a1bb27b1 pbrook
                fprintf(stderr, "pl181: Interrupt mode not implemented\n");
366 a1bb27b1 pbrook
                abort();
367 a1bb27b1 pbrook
            } if (s->cmd & PL181_CMD_PENDING) {
368 a1bb27b1 pbrook
                fprintf(stderr, "pl181: Pending commands not implemented\n");
369 a1bb27b1 pbrook
                abort();
370 a1bb27b1 pbrook
            } else {
371 a1bb27b1 pbrook
                pl181_send_command(s);
372 a1bb27b1 pbrook
                pl181_fifo_run(s);
373 a1bb27b1 pbrook
            }
374 a1bb27b1 pbrook
            /* The command has completed one way or the other.  */
375 a1bb27b1 pbrook
            s->cmd &= ~PL181_CMD_ENABLE;
376 a1bb27b1 pbrook
        }
377 a1bb27b1 pbrook
        break;
378 a1bb27b1 pbrook
    case 0x24: /* DataTimer */
379 a1bb27b1 pbrook
        s->datatimer = value;
380 a1bb27b1 pbrook
        break;
381 a1bb27b1 pbrook
    case 0x28: /* DataLength */
382 a1bb27b1 pbrook
        s->datalength = value & 0xffff;
383 a1bb27b1 pbrook
        break;
384 a1bb27b1 pbrook
    case 0x2c: /* DataCtrl */
385 a1bb27b1 pbrook
        s->datactrl = value & 0xff;
386 a1bb27b1 pbrook
        if (value & PL181_DATA_ENABLE) {
387 a1bb27b1 pbrook
            s->datacnt = s->datalength;
388 a1bb27b1 pbrook
            pl181_fifo_run(s);
389 a1bb27b1 pbrook
        }
390 a1bb27b1 pbrook
        break;
391 a1bb27b1 pbrook
    case 0x38: /* Clear */
392 a1bb27b1 pbrook
        s->status &= ~(value & 0x7ff);
393 a1bb27b1 pbrook
        break;
394 a1bb27b1 pbrook
    case 0x3c: /* Mask0 */
395 a1bb27b1 pbrook
        s->mask[0] = value;
396 a1bb27b1 pbrook
        break;
397 a1bb27b1 pbrook
    case 0x40: /* Mask1 */
398 a1bb27b1 pbrook
        s->mask[1] = value;
399 a1bb27b1 pbrook
        break;
400 a1bb27b1 pbrook
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
401 a1bb27b1 pbrook
    case 0x90: case 0x94: case 0x98: case 0x9c:
402 a1bb27b1 pbrook
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
403 a1bb27b1 pbrook
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
404 6361cdb6 pbrook
        if (s->datacnt == 0) {
405 a1bb27b1 pbrook
            fprintf(stderr, "pl181: Unexpected FIFO write\n");
406 a1bb27b1 pbrook
        } else {
407 a1bb27b1 pbrook
            pl181_fifo_push(s, value);
408 a1bb27b1 pbrook
            pl181_fifo_run(s);
409 a1bb27b1 pbrook
        }
410 a1bb27b1 pbrook
        break;
411 a1bb27b1 pbrook
    default:
412 2ac71179 Paul Brook
        hw_error("pl181_write: Bad offset %x\n", (int)offset);
413 a1bb27b1 pbrook
    }
414 a1bb27b1 pbrook
    pl181_update(s);
415 a1bb27b1 pbrook
}
416 a1bb27b1 pbrook
417 ca45842a Avi Kivity
static const MemoryRegionOps pl181_ops = {
418 ca45842a Avi Kivity
    .read = pl181_read,
419 ca45842a Avi Kivity
    .write = pl181_write,
420 ca45842a Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
421 a1bb27b1 pbrook
};
422 a1bb27b1 pbrook
423 a1bb27b1 pbrook
static void pl181_reset(void *opaque)
424 a1bb27b1 pbrook
{
425 a1bb27b1 pbrook
    pl181_state *s = (pl181_state *)opaque;
426 a1bb27b1 pbrook
427 a1bb27b1 pbrook
    s->power = 0;
428 a1bb27b1 pbrook
    s->cmdarg = 0;
429 a1bb27b1 pbrook
    s->cmd = 0;
430 a1bb27b1 pbrook
    s->datatimer = 0;
431 a1bb27b1 pbrook
    s->datalength = 0;
432 a1bb27b1 pbrook
    s->respcmd = 0;
433 a1bb27b1 pbrook
    s->response[0] = 0;
434 a1bb27b1 pbrook
    s->response[1] = 0;
435 a1bb27b1 pbrook
    s->response[2] = 0;
436 a1bb27b1 pbrook
    s->response[3] = 0;
437 a1bb27b1 pbrook
    s->datatimer = 0;
438 a1bb27b1 pbrook
    s->datalength = 0;
439 a1bb27b1 pbrook
    s->datactrl = 0;
440 a1bb27b1 pbrook
    s->datacnt = 0;
441 a1bb27b1 pbrook
    s->status = 0;
442 6361cdb6 pbrook
    s->linux_hack = 0;
443 a1bb27b1 pbrook
    s->mask[0] = 0;
444 a1bb27b1 pbrook
    s->mask[1] = 0;
445 c31a4724 Peter Maydell
446 c31a4724 Peter Maydell
    /* We can assume our GPIO outputs have been wired up now */
447 c31a4724 Peter Maydell
    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
448 a1bb27b1 pbrook
}
449 a1bb27b1 pbrook
450 81a322d4 Gerd Hoffmann
static int pl181_init(SysBusDevice *dev)
451 a1bb27b1 pbrook
{
452 aa9311d8 Paul Brook
    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
453 13839974 Markus Armbruster
    DriveInfo *dinfo;
454 a1bb27b1 pbrook
455 ca45842a Avi Kivity
    memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
456 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
457 aa9311d8 Paul Brook
    sysbus_init_irq(dev, &s->irq[0]);
458 aa9311d8 Paul Brook
    sysbus_init_irq(dev, &s->irq[1]);
459 c31a4724 Peter Maydell
    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
460 13839974 Markus Armbruster
    dinfo = drive_get_next(IF_SD);
461 13839974 Markus Armbruster
    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
462 a08d4367 Jan Kiszka
    qemu_register_reset(pl181_reset, s);
463 a1bb27b1 pbrook
    pl181_reset(s);
464 a1bb27b1 pbrook
    /* ??? Save/restore.  */
465 81a322d4 Gerd Hoffmann
    return 0;
466 a1bb27b1 pbrook
}
467 aa9311d8 Paul Brook
468 aa9311d8 Paul Brook
static void pl181_register_devices(void)
469 aa9311d8 Paul Brook
{
470 aa9311d8 Paul Brook
    sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
471 aa9311d8 Paul Brook
}
472 aa9311d8 Paul Brook
473 aa9311d8 Paul Brook
device_init(pl181_register_devices)