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