1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39#include "hw/hw.h"
40#include "hw/isa/isa.h"
41#include "hw/ppc/mac_dbdma.h"
42#include "qemu/main-loop.h"
43
44
45
46
47#ifdef DEBUG_DBDMA
48#define DBDMA_DPRINTF(fmt, ...) \
49 do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
50#else
51#define DBDMA_DPRINTF(fmt, ...)
52#endif
53
54
55
56
57static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
58{
59 return container_of(ch, DBDMAState, channels[ch->channel]);
60}
61
62#ifdef DEBUG_DBDMA
63static void dump_dbdma_cmd(dbdma_cmd *cmd)
64{
65 printf("dbdma_cmd %p\n", cmd);
66 printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
67 printf(" command 0x%04x\n", le16_to_cpu(cmd->command));
68 printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
69 printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
70 printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
71 printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
72}
73#else
74static void dump_dbdma_cmd(dbdma_cmd *cmd)
75{
76}
77#endif
78static void dbdma_cmdptr_load(DBDMA_channel *ch)
79{
80 DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
81 ch->regs[DBDMA_CMDPTR_LO]);
82 cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
83 &ch->current, sizeof(dbdma_cmd));
84}
85
86static void dbdma_cmdptr_save(DBDMA_channel *ch)
87{
88 DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
89 ch->regs[DBDMA_CMDPTR_LO]);
90 DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
91 le16_to_cpu(ch->current.xfer_status),
92 le16_to_cpu(ch->current.res_count));
93 cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
94 &ch->current, sizeof(dbdma_cmd));
95}
96
97static void kill_channel(DBDMA_channel *ch)
98{
99 DBDMA_DPRINTF("kill_channel\n");
100
101 ch->regs[DBDMA_STATUS] |= DEAD;
102 ch->regs[DBDMA_STATUS] &= ~ACTIVE;
103
104 qemu_irq_raise(ch->irq);
105}
106
107static void conditional_interrupt(DBDMA_channel *ch)
108{
109 dbdma_cmd *current = &ch->current;
110 uint16_t intr;
111 uint16_t sel_mask, sel_value;
112 uint32_t status;
113 int cond;
114
115 DBDMA_DPRINTF("%s\n", __func__);
116
117 intr = le16_to_cpu(current->command) & INTR_MASK;
118
119 switch(intr) {
120 case INTR_NEVER:
121 return;
122 case INTR_ALWAYS:
123 qemu_irq_raise(ch->irq);
124 DBDMA_DPRINTF("%s: raise\n", __func__);
125 return;
126 }
127
128 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
129
130 sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
131 sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
132
133 cond = (status & sel_mask) == (sel_value & sel_mask);
134
135 switch(intr) {
136 case INTR_IFSET:
137 if (cond) {
138 qemu_irq_raise(ch->irq);
139 DBDMA_DPRINTF("%s: raise\n", __func__);
140 }
141 return;
142 case INTR_IFCLR:
143 if (!cond) {
144 qemu_irq_raise(ch->irq);
145 DBDMA_DPRINTF("%s: raise\n", __func__);
146 }
147 return;
148 }
149}
150
151static int conditional_wait(DBDMA_channel *ch)
152{
153 dbdma_cmd *current = &ch->current;
154 uint16_t wait;
155 uint16_t sel_mask, sel_value;
156 uint32_t status;
157 int cond;
158
159 DBDMA_DPRINTF("conditional_wait\n");
160
161 wait = le16_to_cpu(current->command) & WAIT_MASK;
162
163 switch(wait) {
164 case WAIT_NEVER:
165 return 0;
166 case WAIT_ALWAYS:
167 return 1;
168 }
169
170 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
171
172 sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
173 sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
174
175 cond = (status & sel_mask) == (sel_value & sel_mask);
176
177 switch(wait) {
178 case WAIT_IFSET:
179 if (cond)
180 return 1;
181 return 0;
182 case WAIT_IFCLR:
183 if (!cond)
184 return 1;
185 return 0;
186 }
187 return 0;
188}
189
190static void next(DBDMA_channel *ch)
191{
192 uint32_t cp;
193
194 ch->regs[DBDMA_STATUS] &= ~BT;
195
196 cp = ch->regs[DBDMA_CMDPTR_LO];
197 ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
198 dbdma_cmdptr_load(ch);
199}
200
201static void branch(DBDMA_channel *ch)
202{
203 dbdma_cmd *current = &ch->current;
204
205 ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
206 ch->regs[DBDMA_STATUS] |= BT;
207 dbdma_cmdptr_load(ch);
208}
209
210static void conditional_branch(DBDMA_channel *ch)
211{
212 dbdma_cmd *current = &ch->current;
213 uint16_t br;
214 uint16_t sel_mask, sel_value;
215 uint32_t status;
216 int cond;
217
218 DBDMA_DPRINTF("conditional_branch\n");
219
220
221
222 br = le16_to_cpu(current->command) & BR_MASK;
223
224 switch(br) {
225 case BR_NEVER:
226 next(ch);
227 return;
228 case BR_ALWAYS:
229 branch(ch);
230 return;
231 }
232
233 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
234
235 sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
236 sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
237
238 cond = (status & sel_mask) == (sel_value & sel_mask);
239
240 switch(br) {
241 case BR_IFSET:
242 if (cond)
243 branch(ch);
244 else
245 next(ch);
246 return;
247 case BR_IFCLR:
248 if (!cond)
249 branch(ch);
250 else
251 next(ch);
252 return;
253 }
254}
255
256static void channel_run(DBDMA_channel *ch);
257
258static void dbdma_end(DBDMA_io *io)
259{
260 DBDMA_channel *ch = io->channel;
261 dbdma_cmd *current = &ch->current;
262
263 DBDMA_DPRINTF("%s\n", __func__);
264
265 if (conditional_wait(ch))
266 goto wait;
267
268 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
269 current->res_count = cpu_to_le16(io->len);
270 dbdma_cmdptr_save(ch);
271 if (io->is_last)
272 ch->regs[DBDMA_STATUS] &= ~FLUSH;
273
274 conditional_interrupt(ch);
275 conditional_branch(ch);
276
277wait:
278
279 ch->io.processing = false;
280
281 if ((ch->regs[DBDMA_STATUS] & RUN) &&
282 (ch->regs[DBDMA_STATUS] & ACTIVE))
283 channel_run(ch);
284}
285
286static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
287 uint16_t req_count, int is_last)
288{
289 DBDMA_DPRINTF("start_output\n");
290
291
292
293
294
295 DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
296 if (!addr || key > KEY_STREAM3) {
297 kill_channel(ch);
298 return;
299 }
300
301 ch->io.addr = addr;
302 ch->io.len = req_count;
303 ch->io.is_last = is_last;
304 ch->io.dma_end = dbdma_end;
305 ch->io.is_dma_out = 1;
306 ch->io.processing = true;
307 if (ch->rw) {
308 ch->rw(&ch->io);
309 }
310}
311
312static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
313 uint16_t req_count, int is_last)
314{
315 DBDMA_DPRINTF("start_input\n");
316
317
318
319
320
321 DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
322 if (!addr || key > KEY_STREAM3) {
323 kill_channel(ch);
324 return;
325 }
326
327 ch->io.addr = addr;
328 ch->io.len = req_count;
329 ch->io.is_last = is_last;
330 ch->io.dma_end = dbdma_end;
331 ch->io.is_dma_out = 0;
332 ch->io.processing = true;
333 if (ch->rw) {
334 ch->rw(&ch->io);
335 }
336}
337
338static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
339 uint16_t len)
340{
341 dbdma_cmd *current = &ch->current;
342 uint32_t val;
343
344 DBDMA_DPRINTF("load_word\n");
345
346
347
348 if (key != KEY_SYSTEM) {
349 printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
350 kill_channel(ch);
351 return;
352 }
353
354 cpu_physical_memory_read(addr, &val, len);
355
356 if (len == 2)
357 val = (val << 16) | (current->cmd_dep & 0x0000ffff);
358 else if (len == 1)
359 val = (val << 24) | (current->cmd_dep & 0x00ffffff);
360
361 current->cmd_dep = val;
362
363 if (conditional_wait(ch))
364 goto wait;
365
366 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
367 dbdma_cmdptr_save(ch);
368 ch->regs[DBDMA_STATUS] &= ~FLUSH;
369
370 conditional_interrupt(ch);
371 next(ch);
372
373wait:
374 DBDMA_kick(dbdma_from_ch(ch));
375}
376
377static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
378 uint16_t len)
379{
380 dbdma_cmd *current = &ch->current;
381 uint32_t val;
382
383 DBDMA_DPRINTF("store_word\n");
384
385
386
387 if (key != KEY_SYSTEM) {
388 printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
389 kill_channel(ch);
390 return;
391 }
392
393 val = current->cmd_dep;
394 if (len == 2)
395 val >>= 16;
396 else if (len == 1)
397 val >>= 24;
398
399 cpu_physical_memory_write(addr, &val, len);
400
401 if (conditional_wait(ch))
402 goto wait;
403
404 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
405 dbdma_cmdptr_save(ch);
406 ch->regs[DBDMA_STATUS] &= ~FLUSH;
407
408 conditional_interrupt(ch);
409 next(ch);
410
411wait:
412 DBDMA_kick(dbdma_from_ch(ch));
413}
414
415static void nop(DBDMA_channel *ch)
416{
417 dbdma_cmd *current = &ch->current;
418
419 if (conditional_wait(ch))
420 goto wait;
421
422 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
423 dbdma_cmdptr_save(ch);
424
425 conditional_interrupt(ch);
426 conditional_branch(ch);
427
428wait:
429 DBDMA_kick(dbdma_from_ch(ch));
430}
431
432static void stop(DBDMA_channel *ch)
433{
434 ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
435
436
437}
438
439static void channel_run(DBDMA_channel *ch)
440{
441 dbdma_cmd *current = &ch->current;
442 uint16_t cmd, key;
443 uint16_t req_count;
444 uint32_t phy_addr;
445
446 DBDMA_DPRINTF("channel_run\n");
447 dump_dbdma_cmd(current);
448
449
450
451 ch->regs[DBDMA_STATUS] &= ~WAKE;
452
453 cmd = le16_to_cpu(current->command) & COMMAND_MASK;
454
455 switch (cmd) {
456 case DBDMA_NOP:
457 nop(ch);
458 return;
459
460 case DBDMA_STOP:
461 stop(ch);
462 return;
463 }
464
465 key = le16_to_cpu(current->command) & 0x0700;
466 req_count = le16_to_cpu(current->req_count);
467 phy_addr = le32_to_cpu(current->phy_addr);
468
469 if (key == KEY_STREAM4) {
470 printf("command %x, invalid key 4\n", cmd);
471 kill_channel(ch);
472 return;
473 }
474
475 switch (cmd) {
476 case OUTPUT_MORE:
477 start_output(ch, key, phy_addr, req_count, 0);
478 return;
479
480 case OUTPUT_LAST:
481 start_output(ch, key, phy_addr, req_count, 1);
482 return;
483
484 case INPUT_MORE:
485 start_input(ch, key, phy_addr, req_count, 0);
486 return;
487
488 case INPUT_LAST:
489 start_input(ch, key, phy_addr, req_count, 1);
490 return;
491 }
492
493 if (key < KEY_REGS) {
494 printf("command %x, invalid key %x\n", cmd, key);
495 key = KEY_SYSTEM;
496 }
497
498
499
500
501
502 req_count = req_count & 0x0007;
503 if (req_count & 0x4) {
504 req_count = 4;
505 phy_addr &= ~3;
506 } else if (req_count & 0x2) {
507 req_count = 2;
508 phy_addr &= ~1;
509 } else
510 req_count = 1;
511
512 switch (cmd) {
513 case LOAD_WORD:
514 load_word(ch, key, phy_addr, req_count);
515 return;
516
517 case STORE_WORD:
518 store_word(ch, key, phy_addr, req_count);
519 return;
520 }
521}
522
523static void DBDMA_run(DBDMAState *s)
524{
525 int channel;
526
527 for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
528 DBDMA_channel *ch = &s->channels[channel];
529 uint32_t status = ch->regs[DBDMA_STATUS];
530 if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
531 channel_run(ch);
532 }
533 }
534}
535
536static void DBDMA_run_bh(void *opaque)
537{
538 DBDMAState *s = opaque;
539
540 DBDMA_DPRINTF("DBDMA_run_bh\n");
541
542 DBDMA_run(s);
543}
544
545void DBDMA_kick(DBDMAState *dbdma)
546{
547 qemu_bh_schedule(dbdma->bh);
548}
549
550void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
551 DBDMA_rw rw, DBDMA_flush flush,
552 void *opaque)
553{
554 DBDMAState *s = dbdma;
555 DBDMA_channel *ch = &s->channels[nchan];
556
557 DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
558
559 ch->irq = irq;
560 ch->rw = rw;
561 ch->flush = flush;
562 ch->io.opaque = opaque;
563 ch->io.channel = ch;
564}
565
566static void
567dbdma_control_write(DBDMA_channel *ch)
568{
569 uint16_t mask, value;
570 uint32_t status;
571
572 mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
573 value = ch->regs[DBDMA_CONTROL] & 0xffff;
574
575 value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
576
577 status = ch->regs[DBDMA_STATUS];
578
579 status = (value & mask) | (status & ~mask);
580
581 if (status & WAKE)
582 status |= ACTIVE;
583 if (status & RUN) {
584 status |= ACTIVE;
585 status &= ~DEAD;
586 }
587 if (status & PAUSE)
588 status &= ~ACTIVE;
589 if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
590
591 status &= ~(ACTIVE|DEAD);
592 }
593
594 if ((status & FLUSH) && ch->flush) {
595 ch->flush(&ch->io);
596 status &= ~FLUSH;
597 }
598
599 DBDMA_DPRINTF(" status 0x%08x\n", status);
600
601 ch->regs[DBDMA_STATUS] = status;
602
603 if (status & ACTIVE) {
604 DBDMA_kick(dbdma_from_ch(ch));
605 }
606}
607
608static void dbdma_write(void *opaque, hwaddr addr,
609 uint64_t value, unsigned size)
610{
611 int channel = addr >> DBDMA_CHANNEL_SHIFT;
612 DBDMAState *s = opaque;
613 DBDMA_channel *ch = &s->channels[channel];
614 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
615
616 DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
617 addr, value);
618 DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
619 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
620
621
622
623 if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
624 return;
625 }
626
627 ch->regs[reg] = value;
628
629 switch(reg) {
630 case DBDMA_CONTROL:
631 dbdma_control_write(ch);
632 break;
633 case DBDMA_CMDPTR_LO:
634
635 ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
636 dbdma_cmdptr_load(ch);
637 break;
638 case DBDMA_STATUS:
639 case DBDMA_INTR_SEL:
640 case DBDMA_BRANCH_SEL:
641 case DBDMA_WAIT_SEL:
642
643 break;
644 case DBDMA_XFER_MODE:
645 case DBDMA_CMDPTR_HI:
646 case DBDMA_DATA2PTR_HI:
647 case DBDMA_DATA2PTR_LO:
648 case DBDMA_ADDRESS_HI:
649 case DBDMA_BRANCH_ADDR_HI:
650 case DBDMA_RES1:
651 case DBDMA_RES2:
652 case DBDMA_RES3:
653 case DBDMA_RES4:
654
655 break;
656 }
657}
658
659static uint64_t dbdma_read(void *opaque, hwaddr addr,
660 unsigned size)
661{
662 uint32_t value;
663 int channel = addr >> DBDMA_CHANNEL_SHIFT;
664 DBDMAState *s = opaque;
665 DBDMA_channel *ch = &s->channels[channel];
666 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
667
668 value = ch->regs[reg];
669
670 DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
671 DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
672 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
673
674 switch(reg) {
675 case DBDMA_CONTROL:
676 value = 0;
677 break;
678 case DBDMA_STATUS:
679 case DBDMA_CMDPTR_LO:
680 case DBDMA_INTR_SEL:
681 case DBDMA_BRANCH_SEL:
682 case DBDMA_WAIT_SEL:
683
684 break;
685 case DBDMA_XFER_MODE:
686 case DBDMA_CMDPTR_HI:
687 case DBDMA_DATA2PTR_HI:
688 case DBDMA_DATA2PTR_LO:
689 case DBDMA_ADDRESS_HI:
690 case DBDMA_BRANCH_ADDR_HI:
691
692 value = 0;
693 break;
694 case DBDMA_RES1:
695 case DBDMA_RES2:
696 case DBDMA_RES3:
697 case DBDMA_RES4:
698
699 break;
700 }
701
702 return value;
703}
704
705static const MemoryRegionOps dbdma_ops = {
706 .read = dbdma_read,
707 .write = dbdma_write,
708 .endianness = DEVICE_LITTLE_ENDIAN,
709 .valid = {
710 .min_access_size = 4,
711 .max_access_size = 4,
712 },
713};
714
715static const VMStateDescription vmstate_dbdma_channel = {
716 .name = "dbdma_channel",
717 .version_id = 0,
718 .minimum_version_id = 0,
719 .fields = (VMStateField[]) {
720 VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
721 VMSTATE_END_OF_LIST()
722 }
723};
724
725static const VMStateDescription vmstate_dbdma = {
726 .name = "dbdma",
727 .version_id = 2,
728 .minimum_version_id = 2,
729 .fields = (VMStateField[]) {
730 VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
731 vmstate_dbdma_channel, DBDMA_channel),
732 VMSTATE_END_OF_LIST()
733 }
734};
735
736static void dbdma_reset(void *opaque)
737{
738 DBDMAState *s = opaque;
739 int i;
740
741 for (i = 0; i < DBDMA_CHANNELS; i++)
742 memset(s->channels[i].regs, 0, DBDMA_SIZE);
743}
744
745void* DBDMA_init (MemoryRegion **dbdma_mem)
746{
747 DBDMAState *s;
748 int i;
749
750 s = g_malloc0(sizeof(DBDMAState));
751
752 for (i = 0; i < DBDMA_CHANNELS; i++) {
753 DBDMA_io *io = &s->channels[i].io;
754 qemu_iovec_init(&io->iov, 1);
755 s->channels[i].channel = i;
756 }
757
758 memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000);
759 *dbdma_mem = &s->mem;
760 vmstate_register(NULL, -1, &vmstate_dbdma, s);
761 qemu_register_reset(dbdma_reset, s);
762
763 s->bh = qemu_bh_new(DBDMA_run_bh, s);
764
765 return s;
766}
767