1
2
3
4
5
6
7
8
9
10#include "blockdev.h"
11#include "sysbus.h"
12#include "sd.h"
13
14
15
16#ifdef DEBUG_PL181
17#define DPRINTF(fmt, ...) \
18do { 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
25typedef 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
43
44
45
46
47 int linux_hack;
48 uint32_t fifo[PL181_FIFO_LEN];
49 qemu_irq irq[2];
50
51 qemu_irq cardstatus[2];
52} pl181_state;
53
54#define PL181_CMD_INDEX 0x3f
55#define PL181_CMD_RESPONSE (1 << 6)
56#define PL181_CMD_LONGRESP (1 << 7)
57#define PL181_CMD_INTERRUPT (1 << 8)
58#define PL181_CMD_PENDING (1 << 9)
59#define PL181_CMD_ENABLE (1 << 10)
60
61#define PL181_DATA_ENABLE (1 << 0)
62#define PL181_DATA_DIRECTION (1 << 1)
63#define PL181_DATA_MODE (1 << 2)
64#define PL181_DATA_DMAENABLE (1 << 3)
65
66#define PL181_STATUS_CMDCRCFAIL (1 << 0)
67#define PL181_STATUS_DATACRCFAIL (1 << 1)
68#define PL181_STATUS_CMDTIMEOUT (1 << 2)
69#define PL181_STATUS_DATATIMEOUT (1 << 3)
70#define PL181_STATUS_TXUNDERRUN (1 << 4)
71#define PL181_STATUS_RXOVERRUN (1 << 5)
72#define PL181_STATUS_CMDRESPEND (1 << 6)
73#define PL181_STATUS_CMDSENT (1 << 7)
74#define PL181_STATUS_DATAEND (1 << 8)
75#define PL181_STATUS_DATABLOCKEND (1 << 10)
76#define PL181_STATUS_CMDACTIVE (1 << 11)
77#define PL181_STATUS_TXACTIVE (1 << 12)
78#define PL181_STATUS_RXACTIVE (1 << 13)
79#define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14)
80#define PL181_STATUS_RXFIFOHALFFULL (1 << 15)
81#define PL181_STATUS_TXFIFOFULL (1 << 16)
82#define PL181_STATUS_RXFIFOFULL (1 << 17)
83#define PL181_STATUS_TXFIFOEMPTY (1 << 18)
84#define PL181_STATUS_RXFIFOEMPTY (1 << 19)
85#define PL181_STATUS_TXDATAAVLBL (1 << 20)
86#define PL181_STATUS_RXDATAAVLBL (1 << 21)
87
88#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
89 |PL181_STATUS_TXFIFOHALFEMPTY \
90 |PL181_STATUS_TXFIFOFULL \
91 |PL181_STATUS_TXFIFOEMPTY \
92 |PL181_STATUS_TXDATAAVLBL)
93#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
94 |PL181_STATUS_RXFIFOHALFFULL \
95 |PL181_STATUS_RXFIFOFULL \
96 |PL181_STATUS_RXFIFOEMPTY \
97 |PL181_STATUS_RXDATAAVLBL)
98
99static const unsigned char pl181_id[] =
100{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
101
102static void pl181_update(pl181_state *s)
103{
104 int i;
105 for (i = 0; i < 2; i++) {
106 qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
107 }
108}
109
110static void pl181_fifo_push(pl181_state *s, uint32_t value)
111{
112 int n;
113
114 if (s->fifo_len == PL181_FIFO_LEN) {
115 fprintf(stderr, "pl181: FIFO overflow\n");
116 return;
117 }
118 n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
119 s->fifo_len++;
120 s->fifo[n] = value;
121 DPRINTF("FIFO push %08x\n", (int)value);
122}
123
124static uint32_t pl181_fifo_pop(pl181_state *s)
125{
126 uint32_t value;
127
128 if (s->fifo_len == 0) {
129 fprintf(stderr, "pl181: FIFO underflow\n");
130 return 0;
131 }
132 value = s->fifo[s->fifo_pos];
133 s->fifo_len--;
134 s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
135 DPRINTF("FIFO pop %08x\n", (int)value);
136 return value;
137}
138
139static void pl181_send_command(pl181_state *s)
140{
141 SDRequest request;
142 uint8_t response[16];
143 int rlen;
144
145 request.cmd = s->cmd & PL181_CMD_INDEX;
146 request.arg = s->cmdarg;
147 DPRINTF("Command %d %08x\n", request.cmd, request.arg);
148 rlen = sd_do_command(s->card, &request, response);
149 if (rlen < 0)
150 goto error;
151 if (s->cmd & PL181_CMD_RESPONSE) {
152#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
153 | (response[n + 2] << 8) | response[n + 3])
154 if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
155 goto error;
156 if (rlen != 4 && rlen != 16)
157 goto error;
158 s->response[0] = RWORD(0);
159 if (rlen == 4) {
160 s->response[1] = s->response[2] = s->response[3] = 0;
161 } else {
162 s->response[1] = RWORD(4);
163 s->response[2] = RWORD(8);
164 s->response[3] = RWORD(12) & ~1;
165 }
166 DPRINTF("Response received\n");
167 s->status |= PL181_STATUS_CMDRESPEND;
168#undef RWORD
169 } else {
170 DPRINTF("Command sent\n");
171 s->status |= PL181_STATUS_CMDSENT;
172 }
173 return;
174
175error:
176 DPRINTF("Timeout\n");
177 s->status |= PL181_STATUS_CMDTIMEOUT;
178}
179
180
181
182
183
184static void pl181_fifo_run(pl181_state *s)
185{
186 uint32_t bits;
187 uint32_t value = 0;
188 int n;
189 int is_read;
190
191 is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
192 if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
193 && !s->linux_hack) {
194 if (is_read) {
195 n = 0;
196 while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
197 value |= (uint32_t)sd_read_data(s->card) << (n * 8);
198 s->datacnt--;
199 n++;
200 if (n == 4) {
201 pl181_fifo_push(s, value);
202 n = 0;
203 value = 0;
204 }
205 }
206 if (n != 0) {
207 pl181_fifo_push(s, value);
208 }
209 } else {
210 n = 0;
211 while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
212 if (n == 0) {
213 value = pl181_fifo_pop(s);
214 n = 4;
215 }
216 n--;
217 s->datacnt--;
218 sd_write_data(s->card, value & 0xff);
219 value >>= 8;
220 }
221 }
222 }
223 s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
224 if (s->datacnt == 0) {
225 s->status |= PL181_STATUS_DATAEND;
226
227 s->status |= PL181_STATUS_DATABLOCKEND;
228 DPRINTF("Transfer Complete\n");
229 }
230 if (s->datacnt == 0 && s->fifo_len == 0) {
231 s->datactrl &= ~PL181_DATA_ENABLE;
232 DPRINTF("Data engine idle\n");
233 } else {
234
235 bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
236 if (s->fifo_len == 0) {
237 bits |= PL181_STATUS_TXFIFOEMPTY;
238 bits |= PL181_STATUS_RXFIFOEMPTY;
239 } else {
240 bits |= PL181_STATUS_TXDATAAVLBL;
241 bits |= PL181_STATUS_RXDATAAVLBL;
242 }
243 if (s->fifo_len == 16) {
244 bits |= PL181_STATUS_TXFIFOFULL;
245 bits |= PL181_STATUS_RXFIFOFULL;
246 }
247 if (s->fifo_len <= 8) {
248 bits |= PL181_STATUS_TXFIFOHALFEMPTY;
249 }
250 if (s->fifo_len >= 8) {
251 bits |= PL181_STATUS_RXFIFOHALFFULL;
252 }
253 if (s->datactrl & PL181_DATA_DIRECTION) {
254 bits &= PL181_STATUS_RX_FIFO;
255 } else {
256 bits &= PL181_STATUS_TX_FIFO;
257 }
258 s->status |= bits;
259 }
260}
261
262static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
263{
264 pl181_state *s = (pl181_state *)opaque;
265 uint32_t tmp;
266
267 if (offset >= 0xfe0 && offset < 0x1000) {
268 return pl181_id[(offset - 0xfe0) >> 2];
269 }
270 switch (offset) {
271 case 0x00:
272 return s->power;
273 case 0x04:
274 return s->clock;
275 case 0x08:
276 return s->cmdarg;
277 case 0x0c:
278 return s->cmd;
279 case 0x10:
280 return s->respcmd;
281 case 0x14:
282 return s->response[0];
283 case 0x18:
284 return s->response[1];
285 case 0x1c:
286 return s->response[2];
287 case 0x20:
288 return s->response[3];
289 case 0x24:
290 return s->datatimer;
291 case 0x28:
292 return s->datalength;
293 case 0x2c:
294 return s->datactrl;
295 case 0x30:
296 return s->datacnt;
297 case 0x34:
298 tmp = s->status;
299 if (s->linux_hack) {
300 s->linux_hack = 0;
301 pl181_fifo_run(s);
302 pl181_update(s);
303 }
304 return tmp;
305 case 0x3c:
306 return s->mask[0];
307 case 0x40:
308 return s->mask[1];
309 case 0x48:
310
311
312
313
314
315
316 tmp = (s->datacnt + 3) >> 2;
317 if (s->linux_hack) {
318 s->linux_hack = 0;
319 pl181_fifo_run(s);
320 pl181_update(s);
321 }
322 return tmp;
323 case 0x80: case 0x84: case 0x88: case 0x8c:
324 case 0x90: case 0x94: case 0x98: case 0x9c:
325 case 0xa0: case 0xa4: case 0xa8: case 0xac:
326 case 0xb0: case 0xb4: case 0xb8: case 0xbc:
327 if (s->fifo_len == 0) {
328 fprintf(stderr, "pl181: Unexpected FIFO read\n");
329 return 0;
330 } else {
331 uint32_t value;
332 value = pl181_fifo_pop(s);
333 s->linux_hack = 1;
334 pl181_fifo_run(s);
335 pl181_update(s);
336 return value;
337 }
338 default:
339 hw_error("pl181_read: Bad offset %x\n", (int)offset);
340 return 0;
341 }
342}
343
344static void pl181_write(void *opaque, target_phys_addr_t offset,
345 uint32_t value)
346{
347 pl181_state *s = (pl181_state *)opaque;
348
349 switch (offset) {
350 case 0x00:
351 s->power = value & 0xff;
352 break;
353 case 0x04:
354 s->clock = value & 0xff;
355 break;
356 case 0x08:
357 s->cmdarg = value;
358 break;
359 case 0x0c:
360 s->cmd = value;
361 if (s->cmd & PL181_CMD_ENABLE) {
362 if (s->cmd & PL181_CMD_INTERRUPT) {
363 fprintf(stderr, "pl181: Interrupt mode not implemented\n");
364 abort();
365 } if (s->cmd & PL181_CMD_PENDING) {
366 fprintf(stderr, "pl181: Pending commands not implemented\n");
367 abort();
368 } else {
369 pl181_send_command(s);
370 pl181_fifo_run(s);
371 }
372
373 s->cmd &= ~PL181_CMD_ENABLE;
374 }
375 break;
376 case 0x24:
377 s->datatimer = value;
378 break;
379 case 0x28:
380 s->datalength = value & 0xffff;
381 break;
382 case 0x2c:
383 s->datactrl = value & 0xff;
384 if (value & PL181_DATA_ENABLE) {
385 s->datacnt = s->datalength;
386 pl181_fifo_run(s);
387 }
388 break;
389 case 0x38:
390 s->status &= ~(value & 0x7ff);
391 break;
392 case 0x3c:
393 s->mask[0] = value;
394 break;
395 case 0x40:
396 s->mask[1] = value;
397 break;
398 case 0x80: case 0x84: case 0x88: case 0x8c:
399 case 0x90: case 0x94: case 0x98: case 0x9c:
400 case 0xa0: case 0xa4: case 0xa8: case 0xac:
401 case 0xb0: case 0xb4: case 0xb8: case 0xbc:
402 if (s->datacnt == 0) {
403 fprintf(stderr, "pl181: Unexpected FIFO write\n");
404 } else {
405 pl181_fifo_push(s, value);
406 pl181_fifo_run(s);
407 }
408 break;
409 default:
410 hw_error("pl181_write: Bad offset %x\n", (int)offset);
411 }
412 pl181_update(s);
413}
414
415static CPUReadMemoryFunc * const pl181_readfn[] = {
416 pl181_read,
417 pl181_read,
418 pl181_read
419};
420
421static CPUWriteMemoryFunc * const pl181_writefn[] = {
422 pl181_write,
423 pl181_write,
424 pl181_write
425};
426
427static void pl181_reset(void *opaque)
428{
429 pl181_state *s = (pl181_state *)opaque;
430
431 s->power = 0;
432 s->cmdarg = 0;
433 s->cmd = 0;
434 s->datatimer = 0;
435 s->datalength = 0;
436 s->respcmd = 0;
437 s->response[0] = 0;
438 s->response[1] = 0;
439 s->response[2] = 0;
440 s->response[3] = 0;
441 s->datatimer = 0;
442 s->datalength = 0;
443 s->datactrl = 0;
444 s->datacnt = 0;
445 s->status = 0;
446 s->linux_hack = 0;
447 s->mask[0] = 0;
448 s->mask[1] = 0;
449
450
451 sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
452}
453
454static int pl181_init(SysBusDevice *dev)
455{
456 int iomemtype;
457 pl181_state *s = FROM_SYSBUS(pl181_state, dev);
458 DriveInfo *dinfo;
459
460 iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s,
461 DEVICE_NATIVE_ENDIAN);
462 sysbus_init_mmio(dev, 0x1000, iomemtype);
463 sysbus_init_irq(dev, &s->irq[0]);
464 sysbus_init_irq(dev, &s->irq[1]);
465 qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
466 dinfo = drive_get_next(IF_SD);
467 s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
468 qemu_register_reset(pl181_reset, s);
469 pl181_reset(s);
470
471 return 0;
472}
473
474static void pl181_register_devices(void)
475{
476 sysbus_register_dev("pl181", sizeof(pl181_state), pl181_init);
477}
478
479device_init(pl181_register_devices)
480