Statistics
| Branch: | Revision:

root / hw / pl181.c @ 7830cf78

History | View | Annotate | Download (15.4 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 9c17d615 Paolo Bonzini
#include "sysemu/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 624923be Peter Maydell
    int32_t fifo_pos;
42 624923be Peter Maydell
    int32_t 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 624923be Peter Maydell
    int32_t 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 624923be Peter Maydell
static const VMStateDescription vmstate_pl181 = {
56 624923be Peter Maydell
    .name = "pl181",
57 624923be Peter Maydell
    .version_id = 1,
58 624923be Peter Maydell
    .minimum_version_id = 1,
59 624923be Peter Maydell
    .fields = (VMStateField[]) {
60 624923be Peter Maydell
        VMSTATE_UINT32(clock, pl181_state),
61 624923be Peter Maydell
        VMSTATE_UINT32(power, pl181_state),
62 624923be Peter Maydell
        VMSTATE_UINT32(cmdarg, pl181_state),
63 624923be Peter Maydell
        VMSTATE_UINT32(cmd, pl181_state),
64 624923be Peter Maydell
        VMSTATE_UINT32(datatimer, pl181_state),
65 624923be Peter Maydell
        VMSTATE_UINT32(datalength, pl181_state),
66 624923be Peter Maydell
        VMSTATE_UINT32(respcmd, pl181_state),
67 624923be Peter Maydell
        VMSTATE_UINT32_ARRAY(response, pl181_state, 4),
68 624923be Peter Maydell
        VMSTATE_UINT32(datactrl, pl181_state),
69 624923be Peter Maydell
        VMSTATE_UINT32(datacnt, pl181_state),
70 624923be Peter Maydell
        VMSTATE_UINT32(status, pl181_state),
71 624923be Peter Maydell
        VMSTATE_UINT32_ARRAY(mask, pl181_state, 2),
72 624923be Peter Maydell
        VMSTATE_INT32(fifo_pos, pl181_state),
73 624923be Peter Maydell
        VMSTATE_INT32(fifo_len, pl181_state),
74 624923be Peter Maydell
        VMSTATE_INT32(linux_hack, pl181_state),
75 624923be Peter Maydell
        VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN),
76 624923be Peter Maydell
        VMSTATE_END_OF_LIST()
77 624923be Peter Maydell
    }
78 624923be Peter Maydell
};
79 624923be Peter Maydell
80 a1bb27b1 pbrook
#define PL181_CMD_INDEX     0x3f
81 a1bb27b1 pbrook
#define PL181_CMD_RESPONSE  (1 << 6)
82 a1bb27b1 pbrook
#define PL181_CMD_LONGRESP  (1 << 7)
83 a1bb27b1 pbrook
#define PL181_CMD_INTERRUPT (1 << 8)
84 a1bb27b1 pbrook
#define PL181_CMD_PENDING   (1 << 9)
85 a1bb27b1 pbrook
#define PL181_CMD_ENABLE    (1 << 10)
86 a1bb27b1 pbrook
87 a1bb27b1 pbrook
#define PL181_DATA_ENABLE             (1 << 0)
88 a1bb27b1 pbrook
#define PL181_DATA_DIRECTION          (1 << 1)
89 a1bb27b1 pbrook
#define PL181_DATA_MODE               (1 << 2)
90 a1bb27b1 pbrook
#define PL181_DATA_DMAENABLE          (1 << 3)
91 a1bb27b1 pbrook
92 a1bb27b1 pbrook
#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
93 a1bb27b1 pbrook
#define PL181_STATUS_DATACRCFAIL      (1 << 1)
94 a1bb27b1 pbrook
#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
95 a1bb27b1 pbrook
#define PL181_STATUS_DATATIMEOUT      (1 << 3)
96 a1bb27b1 pbrook
#define PL181_STATUS_TXUNDERRUN       (1 << 4)
97 a1bb27b1 pbrook
#define PL181_STATUS_RXOVERRUN        (1 << 5)
98 a1bb27b1 pbrook
#define PL181_STATUS_CMDRESPEND       (1 << 6)
99 a1bb27b1 pbrook
#define PL181_STATUS_CMDSENT          (1 << 7)
100 a1bb27b1 pbrook
#define PL181_STATUS_DATAEND          (1 << 8)
101 a1bb27b1 pbrook
#define PL181_STATUS_DATABLOCKEND     (1 << 10)
102 a1bb27b1 pbrook
#define PL181_STATUS_CMDACTIVE        (1 << 11)
103 a1bb27b1 pbrook
#define PL181_STATUS_TXACTIVE         (1 << 12)
104 a1bb27b1 pbrook
#define PL181_STATUS_RXACTIVE         (1 << 13)
105 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
106 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
107 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOFULL       (1 << 16)
108 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOFULL       (1 << 17)
109 a1bb27b1 pbrook
#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
110 a1bb27b1 pbrook
#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
111 a1bb27b1 pbrook
#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
112 a1bb27b1 pbrook
#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
113 a1bb27b1 pbrook
114 a1bb27b1 pbrook
#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
115 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOHALFEMPTY \
116 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOFULL \
117 a1bb27b1 pbrook
                             |PL181_STATUS_TXFIFOEMPTY \
118 a1bb27b1 pbrook
                             |PL181_STATUS_TXDATAAVLBL)
119 a1bb27b1 pbrook
#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
120 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOHALFFULL \
121 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOFULL \
122 a1bb27b1 pbrook
                             |PL181_STATUS_RXFIFOEMPTY \
123 a1bb27b1 pbrook
                             |PL181_STATUS_RXDATAAVLBL)
124 a1bb27b1 pbrook
125 a1bb27b1 pbrook
static const unsigned char pl181_id[] =
126 a1bb27b1 pbrook
{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
127 a1bb27b1 pbrook
128 a1bb27b1 pbrook
static void pl181_update(pl181_state *s)
129 a1bb27b1 pbrook
{
130 a1bb27b1 pbrook
    int i;
131 a1bb27b1 pbrook
    for (i = 0; i < 2; i++) {
132 d537cf6c pbrook
        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
133 a1bb27b1 pbrook
    }
134 a1bb27b1 pbrook
}
135 a1bb27b1 pbrook
136 a1bb27b1 pbrook
static void pl181_fifo_push(pl181_state *s, uint32_t value)
137 a1bb27b1 pbrook
{
138 a1bb27b1 pbrook
    int n;
139 a1bb27b1 pbrook
140 a1bb27b1 pbrook
    if (s->fifo_len == PL181_FIFO_LEN) {
141 a1bb27b1 pbrook
        fprintf(stderr, "pl181: FIFO overflow\n");
142 a1bb27b1 pbrook
        return;
143 a1bb27b1 pbrook
    }
144 a1bb27b1 pbrook
    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
145 a1bb27b1 pbrook
    s->fifo_len++;
146 a1bb27b1 pbrook
    s->fifo[n] = value;
147 a1bb27b1 pbrook
    DPRINTF("FIFO push %08x\n", (int)value);
148 a1bb27b1 pbrook
}
149 a1bb27b1 pbrook
150 a1bb27b1 pbrook
static uint32_t pl181_fifo_pop(pl181_state *s)
151 a1bb27b1 pbrook
{
152 a1bb27b1 pbrook
    uint32_t value;
153 a1bb27b1 pbrook
154 a1bb27b1 pbrook
    if (s->fifo_len == 0) {
155 a1bb27b1 pbrook
        fprintf(stderr, "pl181: FIFO underflow\n");
156 a1bb27b1 pbrook
        return 0;
157 a1bb27b1 pbrook
    }
158 a1bb27b1 pbrook
    value = s->fifo[s->fifo_pos];
159 a1bb27b1 pbrook
    s->fifo_len--;
160 a1bb27b1 pbrook
    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
161 a1bb27b1 pbrook
    DPRINTF("FIFO pop %08x\n", (int)value);
162 a1bb27b1 pbrook
    return value;
163 a1bb27b1 pbrook
}
164 a1bb27b1 pbrook
165 a1bb27b1 pbrook
static void pl181_send_command(pl181_state *s)
166 a1bb27b1 pbrook
{
167 bc24a225 Paul Brook
    SDRequest request;
168 a1bb27b1 pbrook
    uint8_t response[16];
169 a1bb27b1 pbrook
    int rlen;
170 a1bb27b1 pbrook
171 a1bb27b1 pbrook
    request.cmd = s->cmd & PL181_CMD_INDEX;
172 a1bb27b1 pbrook
    request.arg = s->cmdarg;
173 a1bb27b1 pbrook
    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
174 a1bb27b1 pbrook
    rlen = sd_do_command(s->card, &request, response);
175 a1bb27b1 pbrook
    if (rlen < 0)
176 a1bb27b1 pbrook
        goto error;
177 a1bb27b1 pbrook
    if (s->cmd & PL181_CMD_RESPONSE) {
178 a1bb27b1 pbrook
#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
179 a1bb27b1 pbrook
                  | (response[n + 2] << 8) | response[n + 3])
180 a1bb27b1 pbrook
        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
181 a1bb27b1 pbrook
            goto error;
182 a1bb27b1 pbrook
        if (rlen != 4 && rlen != 16)
183 a1bb27b1 pbrook
            goto error;
184 a1bb27b1 pbrook
        s->response[0] = RWORD(0);
185 a1bb27b1 pbrook
        if (rlen == 4) {
186 a1bb27b1 pbrook
            s->response[1] = s->response[2] = s->response[3] = 0;
187 a1bb27b1 pbrook
        } else {
188 a1bb27b1 pbrook
            s->response[1] = RWORD(4);
189 a1bb27b1 pbrook
            s->response[2] = RWORD(8);
190 a1bb27b1 pbrook
            s->response[3] = RWORD(12) & ~1;
191 a1bb27b1 pbrook
        }
192 aa1f17c1 ths
        DPRINTF("Response received\n");
193 a1bb27b1 pbrook
        s->status |= PL181_STATUS_CMDRESPEND;
194 a1bb27b1 pbrook
#undef RWORD
195 a1bb27b1 pbrook
    } else {
196 a1bb27b1 pbrook
        DPRINTF("Command sent\n");
197 a1bb27b1 pbrook
        s->status |= PL181_STATUS_CMDSENT;
198 a1bb27b1 pbrook
    }
199 a1bb27b1 pbrook
    return;
200 a1bb27b1 pbrook
201 a1bb27b1 pbrook
error:
202 a1bb27b1 pbrook
    DPRINTF("Timeout\n");
203 a1bb27b1 pbrook
    s->status |= PL181_STATUS_CMDTIMEOUT;
204 a1bb27b1 pbrook
}
205 a1bb27b1 pbrook
206 aa1f17c1 ths
/* Transfer data between the card and the FIFO.  This is complicated by
207 a1bb27b1 pbrook
   the FIFO holding 32-bit words and the card taking data in single byte
208 a1bb27b1 pbrook
   chunks.  FIFO bytes are transferred in little-endian order.  */
209 3b46e624 ths
210 a1bb27b1 pbrook
static void pl181_fifo_run(pl181_state *s)
211 a1bb27b1 pbrook
{
212 a1bb27b1 pbrook
    uint32_t bits;
213 f21126df Blue Swirl
    uint32_t value = 0;
214 a1bb27b1 pbrook
    int n;
215 a1bb27b1 pbrook
    int is_read;
216 a1bb27b1 pbrook
217 a1bb27b1 pbrook
    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
218 6361cdb6 pbrook
    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
219 6361cdb6 pbrook
            && !s->linux_hack) {
220 bc3b26f5 Paul Brook
        if (is_read) {
221 bc3b26f5 Paul Brook
            n = 0;
222 bc3b26f5 Paul Brook
            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
223 a1bb27b1 pbrook
                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
224 bc3b26f5 Paul Brook
                s->datacnt--;
225 a1bb27b1 pbrook
                n++;
226 a1bb27b1 pbrook
                if (n == 4) {
227 a1bb27b1 pbrook
                    pl181_fifo_push(s, value);
228 a1bb27b1 pbrook
                    n = 0;
229 bc3b26f5 Paul Brook
                    value = 0;
230 a1bb27b1 pbrook
                }
231 bc3b26f5 Paul Brook
            }
232 bc3b26f5 Paul Brook
            if (n != 0) {
233 bc3b26f5 Paul Brook
                pl181_fifo_push(s, value);
234 bc3b26f5 Paul Brook
            }
235 bc3b26f5 Paul Brook
        } else { /* write */
236 bc3b26f5 Paul Brook
            n = 0;
237 bc3b26f5 Paul Brook
            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
238 a1bb27b1 pbrook
                if (n == 0) {
239 a1bb27b1 pbrook
                    value = pl181_fifo_pop(s);
240 a1bb27b1 pbrook
                    n = 4;
241 a1bb27b1 pbrook
                }
242 bc3b26f5 Paul Brook
                n--;
243 bc3b26f5 Paul Brook
                s->datacnt--;
244 a1bb27b1 pbrook
                sd_write_data(s->card, value & 0xff);
245 a1bb27b1 pbrook
                value >>= 8;
246 a1bb27b1 pbrook
            }
247 a1bb27b1 pbrook
        }
248 a1bb27b1 pbrook
    }
249 a1bb27b1 pbrook
    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
250 a1bb27b1 pbrook
    if (s->datacnt == 0) {
251 a1bb27b1 pbrook
        s->status |= PL181_STATUS_DATAEND;
252 a1bb27b1 pbrook
        /* HACK: */
253 a1bb27b1 pbrook
        s->status |= PL181_STATUS_DATABLOCKEND;
254 a1bb27b1 pbrook
        DPRINTF("Transfer Complete\n");
255 a1bb27b1 pbrook
    }
256 6361cdb6 pbrook
    if (s->datacnt == 0 && s->fifo_len == 0) {
257 a1bb27b1 pbrook
        s->datactrl &= ~PL181_DATA_ENABLE;
258 a1bb27b1 pbrook
        DPRINTF("Data engine idle\n");
259 a1bb27b1 pbrook
    } else {
260 a1bb27b1 pbrook
        /* Update FIFO bits.  */
261 a1bb27b1 pbrook
        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
262 a1bb27b1 pbrook
        if (s->fifo_len == 0) {
263 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOEMPTY;
264 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOEMPTY;
265 a1bb27b1 pbrook
        } else {
266 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXDATAAVLBL;
267 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXDATAAVLBL;
268 a1bb27b1 pbrook
        }
269 a1bb27b1 pbrook
        if (s->fifo_len == 16) {
270 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOFULL;
271 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOFULL;
272 a1bb27b1 pbrook
        }
273 a1bb27b1 pbrook
        if (s->fifo_len <= 8) {
274 a1bb27b1 pbrook
            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
275 a1bb27b1 pbrook
        }
276 a1bb27b1 pbrook
        if (s->fifo_len >= 8) {
277 a1bb27b1 pbrook
            bits |= PL181_STATUS_RXFIFOHALFFULL;
278 a1bb27b1 pbrook
        }
279 a1bb27b1 pbrook
        if (s->datactrl & PL181_DATA_DIRECTION) {
280 a1bb27b1 pbrook
            bits &= PL181_STATUS_RX_FIFO;
281 a1bb27b1 pbrook
        } else {
282 a1bb27b1 pbrook
            bits &= PL181_STATUS_TX_FIFO;
283 a1bb27b1 pbrook
        }
284 a1bb27b1 pbrook
        s->status |= bits;
285 a1bb27b1 pbrook
    }
286 a1bb27b1 pbrook
}
287 a1bb27b1 pbrook
288 a8170e5e Avi Kivity
static uint64_t pl181_read(void *opaque, hwaddr offset,
289 ca45842a Avi Kivity
                           unsigned size)
290 a1bb27b1 pbrook
{
291 a1bb27b1 pbrook
    pl181_state *s = (pl181_state *)opaque;
292 6361cdb6 pbrook
    uint32_t tmp;
293 a1bb27b1 pbrook
294 a1bb27b1 pbrook
    if (offset >= 0xfe0 && offset < 0x1000) {
295 a1bb27b1 pbrook
        return pl181_id[(offset - 0xfe0) >> 2];
296 a1bb27b1 pbrook
    }
297 a1bb27b1 pbrook
    switch (offset) {
298 a1bb27b1 pbrook
    case 0x00: /* Power */
299 a1bb27b1 pbrook
        return s->power;
300 a1bb27b1 pbrook
    case 0x04: /* Clock */
301 a1bb27b1 pbrook
        return s->clock;
302 a1bb27b1 pbrook
    case 0x08: /* Argument */
303 a1bb27b1 pbrook
        return s->cmdarg;
304 a1bb27b1 pbrook
    case 0x0c: /* Command */
305 a1bb27b1 pbrook
        return s->cmd;
306 a1bb27b1 pbrook
    case 0x10: /* RespCmd */
307 a1bb27b1 pbrook
        return s->respcmd;
308 a1bb27b1 pbrook
    case 0x14: /* Response0 */
309 a1bb27b1 pbrook
        return s->response[0];
310 a1bb27b1 pbrook
    case 0x18: /* Response1 */
311 a1bb27b1 pbrook
        return s->response[1];
312 a1bb27b1 pbrook
    case 0x1c: /* Response2 */
313 a1bb27b1 pbrook
        return s->response[2];
314 a1bb27b1 pbrook
    case 0x20: /* Response3 */
315 a1bb27b1 pbrook
        return s->response[3];
316 a1bb27b1 pbrook
    case 0x24: /* DataTimer */
317 a1bb27b1 pbrook
        return s->datatimer;
318 a1bb27b1 pbrook
    case 0x28: /* DataLength */
319 a1bb27b1 pbrook
        return s->datalength;
320 a1bb27b1 pbrook
    case 0x2c: /* DataCtrl */
321 a1bb27b1 pbrook
        return s->datactrl;
322 a1bb27b1 pbrook
    case 0x30: /* DataCnt */
323 a1bb27b1 pbrook
        return s->datacnt;
324 a1bb27b1 pbrook
    case 0x34: /* Status */
325 6361cdb6 pbrook
        tmp = s->status;
326 6361cdb6 pbrook
        if (s->linux_hack) {
327 6361cdb6 pbrook
            s->linux_hack = 0;
328 6361cdb6 pbrook
            pl181_fifo_run(s);
329 6361cdb6 pbrook
            pl181_update(s);
330 6361cdb6 pbrook
        }
331 6361cdb6 pbrook
        return tmp;
332 a1bb27b1 pbrook
    case 0x3c: /* Mask0 */
333 a1bb27b1 pbrook
        return s->mask[0];
334 a1bb27b1 pbrook
    case 0x40: /* Mask1 */
335 a1bb27b1 pbrook
        return s->mask[1];
336 a1bb27b1 pbrook
    case 0x48: /* FifoCnt */
337 6361cdb6 pbrook
        /* The documentation is somewhat vague about exactly what FifoCnt
338 6361cdb6 pbrook
           does.  On real hardware it appears to be when decrememnted
339 66a0a2cb Dong Xu Wang
           when a word is transferred between the FIFO and the serial
340 6361cdb6 pbrook
           data engine.  DataCnt is decremented after each byte is
341 66a0a2cb Dong Xu Wang
           transferred between the serial engine and the card.
342 6361cdb6 pbrook
           We don't emulate this level of detail, so both can be the same.  */
343 6361cdb6 pbrook
        tmp = (s->datacnt + 3) >> 2;
344 6361cdb6 pbrook
        if (s->linux_hack) {
345 6361cdb6 pbrook
            s->linux_hack = 0;
346 6361cdb6 pbrook
            pl181_fifo_run(s);
347 6361cdb6 pbrook
            pl181_update(s);
348 6361cdb6 pbrook
        }
349 6361cdb6 pbrook
        return tmp;
350 a1bb27b1 pbrook
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
351 a1bb27b1 pbrook
    case 0x90: case 0x94: case 0x98: case 0x9c:
352 a1bb27b1 pbrook
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
353 a1bb27b1 pbrook
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
354 6361cdb6 pbrook
        if (s->fifo_len == 0) {
355 9351d708 Peter Maydell
            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
356 a1bb27b1 pbrook
            return 0;
357 a1bb27b1 pbrook
        } else {
358 a1bb27b1 pbrook
            uint32_t value;
359 a1bb27b1 pbrook
            value = pl181_fifo_pop(s);
360 6361cdb6 pbrook
            s->linux_hack = 1;
361 a1bb27b1 pbrook
            pl181_fifo_run(s);
362 a1bb27b1 pbrook
            pl181_update(s);
363 a1bb27b1 pbrook
            return value;
364 a1bb27b1 pbrook
        }
365 a1bb27b1 pbrook
    default:
366 9351d708 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
367 9351d708 Peter Maydell
                      "pl181_read: Bad offset %x\n", (int)offset);
368 a1bb27b1 pbrook
        return 0;
369 a1bb27b1 pbrook
    }
370 a1bb27b1 pbrook
}
371 a1bb27b1 pbrook
372 a8170e5e Avi Kivity
static void pl181_write(void *opaque, hwaddr offset,
373 ca45842a Avi Kivity
                        uint64_t value, unsigned size)
374 a1bb27b1 pbrook
{
375 a1bb27b1 pbrook
    pl181_state *s = (pl181_state *)opaque;
376 a1bb27b1 pbrook
377 a1bb27b1 pbrook
    switch (offset) {
378 a1bb27b1 pbrook
    case 0x00: /* Power */
379 a1bb27b1 pbrook
        s->power = value & 0xff;
380 a1bb27b1 pbrook
        break;
381 a1bb27b1 pbrook
    case 0x04: /* Clock */
382 a1bb27b1 pbrook
        s->clock = value & 0xff;
383 a1bb27b1 pbrook
        break;
384 a1bb27b1 pbrook
    case 0x08: /* Argument */
385 a1bb27b1 pbrook
        s->cmdarg = value;
386 a1bb27b1 pbrook
        break;
387 a1bb27b1 pbrook
    case 0x0c: /* Command */
388 a1bb27b1 pbrook
        s->cmd = value;
389 a1bb27b1 pbrook
        if (s->cmd & PL181_CMD_ENABLE) {
390 a1bb27b1 pbrook
            if (s->cmd & PL181_CMD_INTERRUPT) {
391 9351d708 Peter Maydell
                qemu_log_mask(LOG_UNIMP,
392 9351d708 Peter Maydell
                              "pl181: Interrupt mode not implemented\n");
393 a1bb27b1 pbrook
            } if (s->cmd & PL181_CMD_PENDING) {
394 9351d708 Peter Maydell
                qemu_log_mask(LOG_UNIMP,
395 9351d708 Peter Maydell
                              "pl181: Pending commands not implemented\n");
396 a1bb27b1 pbrook
            } else {
397 a1bb27b1 pbrook
                pl181_send_command(s);
398 a1bb27b1 pbrook
                pl181_fifo_run(s);
399 a1bb27b1 pbrook
            }
400 a1bb27b1 pbrook
            /* The command has completed one way or the other.  */
401 a1bb27b1 pbrook
            s->cmd &= ~PL181_CMD_ENABLE;
402 a1bb27b1 pbrook
        }
403 a1bb27b1 pbrook
        break;
404 a1bb27b1 pbrook
    case 0x24: /* DataTimer */
405 a1bb27b1 pbrook
        s->datatimer = value;
406 a1bb27b1 pbrook
        break;
407 a1bb27b1 pbrook
    case 0x28: /* DataLength */
408 a1bb27b1 pbrook
        s->datalength = value & 0xffff;
409 a1bb27b1 pbrook
        break;
410 a1bb27b1 pbrook
    case 0x2c: /* DataCtrl */
411 a1bb27b1 pbrook
        s->datactrl = value & 0xff;
412 a1bb27b1 pbrook
        if (value & PL181_DATA_ENABLE) {
413 a1bb27b1 pbrook
            s->datacnt = s->datalength;
414 a1bb27b1 pbrook
            pl181_fifo_run(s);
415 a1bb27b1 pbrook
        }
416 a1bb27b1 pbrook
        break;
417 a1bb27b1 pbrook
    case 0x38: /* Clear */
418 a1bb27b1 pbrook
        s->status &= ~(value & 0x7ff);
419 a1bb27b1 pbrook
        break;
420 a1bb27b1 pbrook
    case 0x3c: /* Mask0 */
421 a1bb27b1 pbrook
        s->mask[0] = value;
422 a1bb27b1 pbrook
        break;
423 a1bb27b1 pbrook
    case 0x40: /* Mask1 */
424 a1bb27b1 pbrook
        s->mask[1] = value;
425 a1bb27b1 pbrook
        break;
426 a1bb27b1 pbrook
    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
427 a1bb27b1 pbrook
    case 0x90: case 0x94: case 0x98: case 0x9c:
428 a1bb27b1 pbrook
    case 0xa0: case 0xa4: case 0xa8: case 0xac:
429 a1bb27b1 pbrook
    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
430 6361cdb6 pbrook
        if (s->datacnt == 0) {
431 9351d708 Peter Maydell
            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
432 a1bb27b1 pbrook
        } else {
433 a1bb27b1 pbrook
            pl181_fifo_push(s, value);
434 a1bb27b1 pbrook
            pl181_fifo_run(s);
435 a1bb27b1 pbrook
        }
436 a1bb27b1 pbrook
        break;
437 a1bb27b1 pbrook
    default:
438 9351d708 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
439 9351d708 Peter Maydell
                      "pl181_write: Bad offset %x\n", (int)offset);
440 a1bb27b1 pbrook
    }
441 a1bb27b1 pbrook
    pl181_update(s);
442 a1bb27b1 pbrook
}
443 a1bb27b1 pbrook
444 ca45842a Avi Kivity
static const MemoryRegionOps pl181_ops = {
445 ca45842a Avi Kivity
    .read = pl181_read,
446 ca45842a Avi Kivity
    .write = pl181_write,
447 ca45842a Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
448 a1bb27b1 pbrook
};
449 a1bb27b1 pbrook
450 624923be Peter Maydell
static void pl181_reset(DeviceState *d)
451 a1bb27b1 pbrook
{
452 624923be Peter Maydell
    pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d);
453 a1bb27b1 pbrook
454 a1bb27b1 pbrook
    s->power = 0;
455 a1bb27b1 pbrook
    s->cmdarg = 0;
456 a1bb27b1 pbrook
    s->cmd = 0;
457 a1bb27b1 pbrook
    s->datatimer = 0;
458 a1bb27b1 pbrook
    s->datalength = 0;
459 a1bb27b1 pbrook
    s->respcmd = 0;
460 a1bb27b1 pbrook
    s->response[0] = 0;
461 a1bb27b1 pbrook
    s->response[1] = 0;
462 a1bb27b1 pbrook
    s->response[2] = 0;
463 a1bb27b1 pbrook
    s->response[3] = 0;
464 a1bb27b1 pbrook
    s->datatimer = 0;
465 a1bb27b1 pbrook
    s->datalength = 0;
466 a1bb27b1 pbrook
    s->datactrl = 0;
467 a1bb27b1 pbrook
    s->datacnt = 0;
468 a1bb27b1 pbrook
    s->status = 0;
469 6361cdb6 pbrook
    s->linux_hack = 0;
470 a1bb27b1 pbrook
    s->mask[0] = 0;
471 a1bb27b1 pbrook
    s->mask[1] = 0;
472 c31a4724 Peter Maydell
473 c31a4724 Peter Maydell
    /* We can assume our GPIO outputs have been wired up now */
474 c31a4724 Peter Maydell
    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
475 a1bb27b1 pbrook
}
476 a1bb27b1 pbrook
477 81a322d4 Gerd Hoffmann
static int pl181_init(SysBusDevice *dev)
478 a1bb27b1 pbrook
{
479 aa9311d8 Paul Brook
    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
480 13839974 Markus Armbruster
    DriveInfo *dinfo;
481 a1bb27b1 pbrook
482 ca45842a Avi Kivity
    memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
483 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
484 aa9311d8 Paul Brook
    sysbus_init_irq(dev, &s->irq[0]);
485 aa9311d8 Paul Brook
    sysbus_init_irq(dev, &s->irq[1]);
486 c31a4724 Peter Maydell
    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
487 13839974 Markus Armbruster
    dinfo = drive_get_next(IF_SD);
488 13839974 Markus Armbruster
    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
489 81a322d4 Gerd Hoffmann
    return 0;
490 a1bb27b1 pbrook
}
491 aa9311d8 Paul Brook
492 999e12bb Anthony Liguori
static void pl181_class_init(ObjectClass *klass, void *data)
493 999e12bb Anthony Liguori
{
494 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
495 39bffca2 Anthony Liguori
    DeviceClass *k = DEVICE_CLASS(klass);
496 999e12bb Anthony Liguori
497 999e12bb Anthony Liguori
    sdc->init = pl181_init;
498 39bffca2 Anthony Liguori
    k->vmsd = &vmstate_pl181;
499 39bffca2 Anthony Liguori
    k->reset = pl181_reset;
500 39bffca2 Anthony Liguori
    k->no_user = 1;
501 999e12bb Anthony Liguori
}
502 999e12bb Anthony Liguori
503 8c43a6f0 Andreas Färber
static const TypeInfo pl181_info = {
504 39bffca2 Anthony Liguori
    .name          = "pl181",
505 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
506 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl181_state),
507 39bffca2 Anthony Liguori
    .class_init    = pl181_class_init,
508 624923be Peter Maydell
};
509 624923be Peter Maydell
510 83f7d43a Andreas Färber
static void pl181_register_types(void)
511 aa9311d8 Paul Brook
{
512 39bffca2 Anthony Liguori
    type_register_static(&pl181_info);
513 aa9311d8 Paul Brook
}
514 aa9311d8 Paul Brook
515 83f7d43a Andreas Färber
type_init(pl181_register_types)