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
40#include "qemu/osdep.h"
41#include "hw/hw.h"
42#include "hw/ppc/mac_dbdma.h"
43#include "qemu/main-loop.h"
44#include "qemu/module.h"
45#include "qemu/log.h"
46#include "sysemu/dma.h"
47
48
49#define DEBUG_DBDMA 0
50#define DEBUG_DBDMA_CHANMASK ((1ull << DBDMA_CHANNELS) - 1)
51
52#define DBDMA_DPRINTF(fmt, ...) do { \
53 if (DEBUG_DBDMA) { \
54 printf("DBDMA: " fmt , ## __VA_ARGS__); \
55 } \
56} while (0)
57
58#define DBDMA_DPRINTFCH(ch, fmt, ...) do { \
59 if (DEBUG_DBDMA) { \
60 if ((1ul << (ch)->channel) & DEBUG_DBDMA_CHANMASK) { \
61 printf("DBDMA[%02x]: " fmt , (ch)->channel, ## __VA_ARGS__); \
62 } \
63 } \
64} while (0)
65
66
67
68
69static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
70{
71 return container_of(ch, DBDMAState, channels[ch->channel]);
72}
73
74#if DEBUG_DBDMA
75static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
76{
77 DBDMA_DPRINTFCH(ch, "dbdma_cmd %p\n", cmd);
78 DBDMA_DPRINTFCH(ch, " req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
79 DBDMA_DPRINTFCH(ch, " command 0x%04x\n", le16_to_cpu(cmd->command));
80 DBDMA_DPRINTFCH(ch, " phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
81 DBDMA_DPRINTFCH(ch, " cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
82 DBDMA_DPRINTFCH(ch, " res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
83 DBDMA_DPRINTFCH(ch, " xfer_status 0x%04x\n",
84 le16_to_cpu(cmd->xfer_status));
85}
86#else
87static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
88{
89}
90#endif
91static void dbdma_cmdptr_load(DBDMA_channel *ch)
92{
93 DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n",
94 ch->regs[DBDMA_CMDPTR_LO]);
95 dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
96 &ch->current, sizeof(dbdma_cmd));
97}
98
99static void dbdma_cmdptr_save(DBDMA_channel *ch)
100{
101 DBDMA_DPRINTFCH(ch, "-> update 0x%08x stat=0x%08x, res=0x%04x\n",
102 ch->regs[DBDMA_CMDPTR_LO],
103 le16_to_cpu(ch->current.xfer_status),
104 le16_to_cpu(ch->current.res_count));
105 dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
106 &ch->current, sizeof(dbdma_cmd));
107}
108
109static void kill_channel(DBDMA_channel *ch)
110{
111 DBDMA_DPRINTFCH(ch, "kill_channel\n");
112
113 ch->regs[DBDMA_STATUS] |= DEAD;
114 ch->regs[DBDMA_STATUS] &= ~ACTIVE;
115
116 qemu_irq_raise(ch->irq);
117}
118
119static void conditional_interrupt(DBDMA_channel *ch)
120{
121 dbdma_cmd *current = &ch->current;
122 uint16_t intr;
123 uint16_t sel_mask, sel_value;
124 uint32_t status;
125 int cond;
126
127 DBDMA_DPRINTFCH(ch, "%s\n", __func__);
128
129 intr = le16_to_cpu(current->command) & INTR_MASK;
130
131 switch(intr) {
132 case INTR_NEVER:
133 return;
134 case INTR_ALWAYS:
135 qemu_irq_raise(ch->irq);
136 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
137 return;
138 }
139
140 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
141
142 sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
143 sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
144
145 cond = (status & sel_mask) == (sel_value & sel_mask);
146
147 switch(intr) {
148 case INTR_IFSET:
149 if (cond) {
150 qemu_irq_raise(ch->irq);
151 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
152 }
153 return;
154 case INTR_IFCLR:
155 if (!cond) {
156 qemu_irq_raise(ch->irq);
157 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
158 }
159 return;
160 }
161}
162
163static int conditional_wait(DBDMA_channel *ch)
164{
165 dbdma_cmd *current = &ch->current;
166 uint16_t wait;
167 uint16_t sel_mask, sel_value;
168 uint32_t status;
169 int cond;
170 int res = 0;
171
172 wait = le16_to_cpu(current->command) & WAIT_MASK;
173 switch(wait) {
174 case WAIT_NEVER:
175 return 0;
176 case WAIT_ALWAYS:
177 DBDMA_DPRINTFCH(ch, " [WAIT_ALWAYS]\n");
178 return 1;
179 }
180
181 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
182
183 sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
184 sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
185
186 cond = (status & sel_mask) == (sel_value & sel_mask);
187
188 switch(wait) {
189 case WAIT_IFSET:
190 if (cond) {
191 res = 1;
192 }
193 DBDMA_DPRINTFCH(ch, " [WAIT_IFSET=%d]\n", res);
194 break;
195 case WAIT_IFCLR:
196 if (!cond) {
197 res = 1;
198 }
199 DBDMA_DPRINTFCH(ch, " [WAIT_IFCLR=%d]\n", res);
200 break;
201 }
202 return res;
203}
204
205static void next(DBDMA_channel *ch)
206{
207 uint32_t cp;
208
209 ch->regs[DBDMA_STATUS] &= ~BT;
210
211 cp = ch->regs[DBDMA_CMDPTR_LO];
212 ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
213 dbdma_cmdptr_load(ch);
214}
215
216static void branch(DBDMA_channel *ch)
217{
218 dbdma_cmd *current = &ch->current;
219
220 ch->regs[DBDMA_CMDPTR_LO] = le32_to_cpu(current->cmd_dep);
221 ch->regs[DBDMA_STATUS] |= BT;
222 dbdma_cmdptr_load(ch);
223}
224
225static void conditional_branch(DBDMA_channel *ch)
226{
227 dbdma_cmd *current = &ch->current;
228 uint16_t br;
229 uint16_t sel_mask, sel_value;
230 uint32_t status;
231 int cond;
232
233
234
235 br = le16_to_cpu(current->command) & BR_MASK;
236
237 switch(br) {
238 case BR_NEVER:
239 next(ch);
240 return;
241 case BR_ALWAYS:
242 DBDMA_DPRINTFCH(ch, " [BR_ALWAYS]\n");
243 branch(ch);
244 return;
245 }
246
247 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
248
249 sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
250 sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
251
252 cond = (status & sel_mask) == (sel_value & sel_mask);
253
254 switch(br) {
255 case BR_IFSET:
256 if (cond) {
257 DBDMA_DPRINTFCH(ch, " [BR_IFSET = 1]\n");
258 branch(ch);
259 } else {
260 DBDMA_DPRINTFCH(ch, " [BR_IFSET = 0]\n");
261 next(ch);
262 }
263 return;
264 case BR_IFCLR:
265 if (!cond) {
266 DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 1]\n");
267 branch(ch);
268 } else {
269 DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 0]\n");
270 next(ch);
271 }
272 return;
273 }
274}
275
276static void channel_run(DBDMA_channel *ch);
277
278static void dbdma_end(DBDMA_io *io)
279{
280 DBDMA_channel *ch = io->channel;
281 dbdma_cmd *current = &ch->current;
282
283 DBDMA_DPRINTFCH(ch, "%s\n", __func__);
284
285 if (conditional_wait(ch))
286 goto wait;
287
288 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
289 current->res_count = cpu_to_le16(io->len);
290 dbdma_cmdptr_save(ch);
291 if (io->is_last)
292 ch->regs[DBDMA_STATUS] &= ~FLUSH;
293
294 conditional_interrupt(ch);
295 conditional_branch(ch);
296
297wait:
298
299 ch->io.processing = false;
300
301 if ((ch->regs[DBDMA_STATUS] & RUN) &&
302 (ch->regs[DBDMA_STATUS] & ACTIVE))
303 channel_run(ch);
304}
305
306static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
307 uint16_t req_count, int is_last)
308{
309 DBDMA_DPRINTFCH(ch, "start_output\n");
310
311
312
313
314
315 DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
316 if (!addr || key > KEY_STREAM3) {
317 kill_channel(ch);
318 return;
319 }
320
321 ch->io.addr = addr;
322 ch->io.len = req_count;
323 ch->io.is_last = is_last;
324 ch->io.dma_end = dbdma_end;
325 ch->io.is_dma_out = 1;
326 ch->io.processing = true;
327 if (ch->rw) {
328 ch->rw(&ch->io);
329 }
330}
331
332static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
333 uint16_t req_count, int is_last)
334{
335 DBDMA_DPRINTFCH(ch, "start_input\n");
336
337
338
339
340
341 DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
342 if (!addr || key > KEY_STREAM3) {
343 kill_channel(ch);
344 return;
345 }
346
347 ch->io.addr = addr;
348 ch->io.len = req_count;
349 ch->io.is_last = is_last;
350 ch->io.dma_end = dbdma_end;
351 ch->io.is_dma_out = 0;
352 ch->io.processing = true;
353 if (ch->rw) {
354 ch->rw(&ch->io);
355 }
356}
357
358static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
359 uint16_t len)
360{
361 dbdma_cmd *current = &ch->current;
362
363 DBDMA_DPRINTFCH(ch, "load_word %d bytes, addr=%08x\n", len, addr);
364
365
366
367 if (key != KEY_SYSTEM) {
368 printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
369 kill_channel(ch);
370 return;
371 }
372
373 dma_memory_read(&address_space_memory, addr, ¤t->cmd_dep, len);
374
375 if (conditional_wait(ch))
376 goto wait;
377
378 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
379 dbdma_cmdptr_save(ch);
380 ch->regs[DBDMA_STATUS] &= ~FLUSH;
381
382 conditional_interrupt(ch);
383 next(ch);
384
385wait:
386 DBDMA_kick(dbdma_from_ch(ch));
387}
388
389static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
390 uint16_t len)
391{
392 dbdma_cmd *current = &ch->current;
393
394 DBDMA_DPRINTFCH(ch, "store_word %d bytes, addr=%08x pa=%x\n",
395 len, addr, le32_to_cpu(current->cmd_dep));
396
397
398
399 if (key != KEY_SYSTEM) {
400 printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
401 kill_channel(ch);
402 return;
403 }
404
405 dma_memory_write(&address_space_memory, addr, ¤t->cmd_dep, len);
406
407 if (conditional_wait(ch))
408 goto wait;
409
410 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
411 dbdma_cmdptr_save(ch);
412 ch->regs[DBDMA_STATUS] &= ~FLUSH;
413
414 conditional_interrupt(ch);
415 next(ch);
416
417wait:
418 DBDMA_kick(dbdma_from_ch(ch));
419}
420
421static void nop(DBDMA_channel *ch)
422{
423 dbdma_cmd *current = &ch->current;
424
425 if (conditional_wait(ch))
426 goto wait;
427
428 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
429 dbdma_cmdptr_save(ch);
430
431 conditional_interrupt(ch);
432 conditional_branch(ch);
433
434wait:
435 DBDMA_kick(dbdma_from_ch(ch));
436}
437
438static void stop(DBDMA_channel *ch)
439{
440 ch->regs[DBDMA_STATUS] &= ~(ACTIVE);
441
442
443}
444
445static void channel_run(DBDMA_channel *ch)
446{
447 dbdma_cmd *current = &ch->current;
448 uint16_t cmd, key;
449 uint16_t req_count;
450 uint32_t phy_addr;
451
452 DBDMA_DPRINTFCH(ch, "channel_run\n");
453 dump_dbdma_cmd(ch, current);
454
455
456
457 ch->regs[DBDMA_STATUS] &= ~WAKE;
458
459 cmd = le16_to_cpu(current->command) & COMMAND_MASK;
460
461 switch (cmd) {
462 case DBDMA_NOP:
463 nop(ch);
464 return;
465
466 case DBDMA_STOP:
467 stop(ch);
468 return;
469 }
470
471 key = le16_to_cpu(current->command) & 0x0700;
472 req_count = le16_to_cpu(current->req_count);
473 phy_addr = le32_to_cpu(current->phy_addr);
474
475 if (key == KEY_STREAM4) {
476 printf("command %x, invalid key 4\n", cmd);
477 kill_channel(ch);
478 return;
479 }
480
481 switch (cmd) {
482 case OUTPUT_MORE:
483 DBDMA_DPRINTFCH(ch, "* OUTPUT_MORE *\n");
484 start_output(ch, key, phy_addr, req_count, 0);
485 return;
486
487 case OUTPUT_LAST:
488 DBDMA_DPRINTFCH(ch, "* OUTPUT_LAST *\n");
489 start_output(ch, key, phy_addr, req_count, 1);
490 return;
491
492 case INPUT_MORE:
493 DBDMA_DPRINTFCH(ch, "* INPUT_MORE *\n");
494 start_input(ch, key, phy_addr, req_count, 0);
495 return;
496
497 case INPUT_LAST:
498 DBDMA_DPRINTFCH(ch, "* INPUT_LAST *\n");
499 start_input(ch, key, phy_addr, req_count, 1);
500 return;
501 }
502
503 if (key < KEY_REGS) {
504 printf("command %x, invalid key %x\n", cmd, key);
505 key = KEY_SYSTEM;
506 }
507
508
509
510
511
512 req_count = req_count & 0x0007;
513 if (req_count & 0x4) {
514 req_count = 4;
515 phy_addr &= ~3;
516 } else if (req_count & 0x2) {
517 req_count = 2;
518 phy_addr &= ~1;
519 } else
520 req_count = 1;
521
522 switch (cmd) {
523 case LOAD_WORD:
524 DBDMA_DPRINTFCH(ch, "* LOAD_WORD *\n");
525 load_word(ch, key, phy_addr, req_count);
526 return;
527
528 case STORE_WORD:
529 DBDMA_DPRINTFCH(ch, "* STORE_WORD *\n");
530 store_word(ch, key, phy_addr, req_count);
531 return;
532 }
533}
534
535static void DBDMA_run(DBDMAState *s)
536{
537 int channel;
538
539 for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
540 DBDMA_channel *ch = &s->channels[channel];
541 uint32_t status = ch->regs[DBDMA_STATUS];
542 if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
543 channel_run(ch);
544 }
545 }
546}
547
548static void DBDMA_run_bh(void *opaque)
549{
550 DBDMAState *s = opaque;
551
552 DBDMA_DPRINTF("-> DBDMA_run_bh\n");
553 DBDMA_run(s);
554 DBDMA_DPRINTF("<- DBDMA_run_bh\n");
555}
556
557void DBDMA_kick(DBDMAState *dbdma)
558{
559 qemu_bh_schedule(dbdma->bh);
560}
561
562void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
563 DBDMA_rw rw, DBDMA_flush flush,
564 void *opaque)
565{
566 DBDMAState *s = dbdma;
567 DBDMA_channel *ch = &s->channels[nchan];
568
569 DBDMA_DPRINTFCH(ch, "DBDMA_register_channel 0x%x\n", nchan);
570
571 assert(rw);
572 assert(flush);
573
574 ch->irq = irq;
575 ch->rw = rw;
576 ch->flush = flush;
577 ch->io.opaque = opaque;
578}
579
580static void dbdma_control_write(DBDMA_channel *ch)
581{
582 uint16_t mask, value;
583 uint32_t status;
584 bool do_flush = false;
585
586 mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
587 value = ch->regs[DBDMA_CONTROL] & 0xffff;
588
589
590
591
592 status = ch->regs[DBDMA_STATUS];
593
594
595
596
597
598
599
600
601
602
603
604 if ((mask & RUN) && (value & RUN)) {
605 status |= RUN;
606 DBDMA_DPRINTFCH(ch, " Setting RUN !\n");
607 }
608
609
610 if ((mask & RUN) && !(value & RUN)) {
611
612 status &= ~(DEAD | RUN);
613 DBDMA_DPRINTFCH(ch, " Clearing RUN !\n");
614 }
615
616
617
618
619
620
621
622
623
624
625
626 if ((mask & WAKE) && (value & WAKE) && (status & RUN)) {
627 status |= WAKE;
628 DBDMA_DPRINTFCH(ch, " Setting WAKE !\n");
629 }
630
631
632
633
634
635 if (mask & PAUSE) {
636 status = (status & ~PAUSE) | (value & PAUSE);
637 DBDMA_DPRINTFCH(ch, " %sing PAUSE !\n",
638 (value & PAUSE) ? "sett" : "clear");
639 }
640
641
642 if ((mask & FLUSH) && (value & FLUSH)) {
643 DBDMA_DPRINTFCH(ch, " Setting FLUSH !\n");
644
645
646
647
648
649
650 ch->regs[DBDMA_STATUS] |= FLUSH;
651 do_flush = true;
652 }
653
654
655
656
657
658
659 if ((status & PAUSE) || !(status & RUN)) {
660 status &= ~ACTIVE;
661 DBDMA_DPRINTFCH(ch, " -> ACTIVE down !\n");
662
663
664
665
666
667
668
669 do_flush = true;
670 } else if (mask & (RUN | PAUSE)) {
671 status |= ACTIVE;
672 DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
673 } else if ((mask & WAKE) && (value & WAKE)) {
674 status |= ACTIVE;
675 DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
676 }
677
678 DBDMA_DPRINTFCH(ch, " new status=0x%08x\n", status);
679
680
681
682
683 if (do_flush && ch->flush) {
684 ch->flush(&ch->io);
685 }
686
687
688 ch->regs[DBDMA_STATUS] = status;
689
690
691 if (status & ACTIVE) {
692 DBDMA_kick(dbdma_from_ch(ch));
693 }
694}
695
696static void dbdma_write(void *opaque, hwaddr addr,
697 uint64_t value, unsigned size)
698{
699 int channel = addr >> DBDMA_CHANNEL_SHIFT;
700 DBDMAState *s = opaque;
701 DBDMA_channel *ch = &s->channels[channel];
702 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
703
704 DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
705 addr, value);
706 DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
707 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
708
709
710
711 if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
712 return;
713 }
714
715 ch->regs[reg] = value;
716
717 switch(reg) {
718 case DBDMA_CONTROL:
719 dbdma_control_write(ch);
720 break;
721 case DBDMA_CMDPTR_LO:
722
723 ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
724 dbdma_cmdptr_load(ch);
725 break;
726 case DBDMA_STATUS:
727 case DBDMA_INTR_SEL:
728 case DBDMA_BRANCH_SEL:
729 case DBDMA_WAIT_SEL:
730
731 break;
732 case DBDMA_XFER_MODE:
733 case DBDMA_CMDPTR_HI:
734 case DBDMA_DATA2PTR_HI:
735 case DBDMA_DATA2PTR_LO:
736 case DBDMA_ADDRESS_HI:
737 case DBDMA_BRANCH_ADDR_HI:
738 case DBDMA_RES1:
739 case DBDMA_RES2:
740 case DBDMA_RES3:
741 case DBDMA_RES4:
742
743 break;
744 }
745}
746
747static uint64_t dbdma_read(void *opaque, hwaddr addr,
748 unsigned size)
749{
750 uint32_t value;
751 int channel = addr >> DBDMA_CHANNEL_SHIFT;
752 DBDMAState *s = opaque;
753 DBDMA_channel *ch = &s->channels[channel];
754 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
755
756 value = ch->regs[reg];
757
758 switch(reg) {
759 case DBDMA_CONTROL:
760 value = ch->regs[DBDMA_STATUS];
761 break;
762 case DBDMA_STATUS:
763 case DBDMA_CMDPTR_LO:
764 case DBDMA_INTR_SEL:
765 case DBDMA_BRANCH_SEL:
766 case DBDMA_WAIT_SEL:
767
768 break;
769 case DBDMA_XFER_MODE:
770 case DBDMA_CMDPTR_HI:
771 case DBDMA_DATA2PTR_HI:
772 case DBDMA_DATA2PTR_LO:
773 case DBDMA_ADDRESS_HI:
774 case DBDMA_BRANCH_ADDR_HI:
775
776 value = 0;
777 break;
778 case DBDMA_RES1:
779 case DBDMA_RES2:
780 case DBDMA_RES3:
781 case DBDMA_RES4:
782
783 break;
784 }
785
786 DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
787 DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
788 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
789
790 return value;
791}
792
793static const MemoryRegionOps dbdma_ops = {
794 .read = dbdma_read,
795 .write = dbdma_write,
796 .endianness = DEVICE_LITTLE_ENDIAN,
797 .valid = {
798 .min_access_size = 4,
799 .max_access_size = 4,
800 },
801};
802
803static const VMStateDescription vmstate_dbdma_io = {
804 .name = "dbdma_io",
805 .version_id = 0,
806 .minimum_version_id = 0,
807 .fields = (VMStateField[]) {
808 VMSTATE_UINT64(addr, struct DBDMA_io),
809 VMSTATE_INT32(len, struct DBDMA_io),
810 VMSTATE_INT32(is_last, struct DBDMA_io),
811 VMSTATE_INT32(is_dma_out, struct DBDMA_io),
812 VMSTATE_BOOL(processing, struct DBDMA_io),
813 VMSTATE_END_OF_LIST()
814 }
815};
816
817static const VMStateDescription vmstate_dbdma_cmd = {
818 .name = "dbdma_cmd",
819 .version_id = 0,
820 .minimum_version_id = 0,
821 .fields = (VMStateField[]) {
822 VMSTATE_UINT16(req_count, dbdma_cmd),
823 VMSTATE_UINT16(command, dbdma_cmd),
824 VMSTATE_UINT32(phy_addr, dbdma_cmd),
825 VMSTATE_UINT32(cmd_dep, dbdma_cmd),
826 VMSTATE_UINT16(res_count, dbdma_cmd),
827 VMSTATE_UINT16(xfer_status, dbdma_cmd),
828 VMSTATE_END_OF_LIST()
829 }
830};
831
832static const VMStateDescription vmstate_dbdma_channel = {
833 .name = "dbdma_channel",
834 .version_id = 1,
835 .minimum_version_id = 1,
836 .fields = (VMStateField[]) {
837 VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
838 VMSTATE_STRUCT(io, struct DBDMA_channel, 0, vmstate_dbdma_io, DBDMA_io),
839 VMSTATE_STRUCT(current, struct DBDMA_channel, 0, vmstate_dbdma_cmd,
840 dbdma_cmd),
841 VMSTATE_END_OF_LIST()
842 }
843};
844
845static const VMStateDescription vmstate_dbdma = {
846 .name = "dbdma",
847 .version_id = 3,
848 .minimum_version_id = 3,
849 .fields = (VMStateField[]) {
850 VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
851 vmstate_dbdma_channel, DBDMA_channel),
852 VMSTATE_END_OF_LIST()
853 }
854};
855
856static void mac_dbdma_reset(DeviceState *d)
857{
858 DBDMAState *s = MAC_DBDMA(d);
859 int i;
860
861 for (i = 0; i < DBDMA_CHANNELS; i++) {
862 memset(s->channels[i].regs, 0, DBDMA_SIZE);
863 }
864}
865
866static void dbdma_unassigned_rw(DBDMA_io *io)
867{
868 DBDMA_channel *ch = io->channel;
869 dbdma_cmd *current = &ch->current;
870 uint16_t cmd;
871 qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
872 __func__, ch->channel);
873 ch->io.processing = false;
874
875 cmd = le16_to_cpu(current->command) & COMMAND_MASK;
876 if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST ||
877 cmd == INPUT_MORE || cmd == INPUT_LAST) {
878 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
879 current->res_count = cpu_to_le16(io->len);
880 dbdma_cmdptr_save(ch);
881 }
882}
883
884static void dbdma_unassigned_flush(DBDMA_io *io)
885{
886 DBDMA_channel *ch = io->channel;
887 qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
888 __func__, ch->channel);
889}
890
891static void mac_dbdma_init(Object *obj)
892{
893 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
894 DBDMAState *s = MAC_DBDMA(obj);
895 int i;
896
897 for (i = 0; i < DBDMA_CHANNELS; i++) {
898 DBDMA_channel *ch = &s->channels[i];
899
900 ch->rw = dbdma_unassigned_rw;
901 ch->flush = dbdma_unassigned_flush;
902 ch->channel = i;
903 ch->io.channel = ch;
904 }
905
906 memory_region_init_io(&s->mem, obj, &dbdma_ops, s, "dbdma", 0x1000);
907 sysbus_init_mmio(sbd, &s->mem);
908}
909
910static void mac_dbdma_realize(DeviceState *dev, Error **errp)
911{
912 DBDMAState *s = MAC_DBDMA(dev);
913
914 s->bh = qemu_bh_new(DBDMA_run_bh, s);
915}
916
917static void mac_dbdma_class_init(ObjectClass *oc, void *data)
918{
919 DeviceClass *dc = DEVICE_CLASS(oc);
920
921 dc->realize = mac_dbdma_realize;
922 dc->reset = mac_dbdma_reset;
923 dc->vmsd = &vmstate_dbdma;
924}
925
926static const TypeInfo mac_dbdma_type_info = {
927 .name = TYPE_MAC_DBDMA,
928 .parent = TYPE_SYS_BUS_DEVICE,
929 .instance_size = sizeof(DBDMAState),
930 .instance_init = mac_dbdma_init,
931 .class_init = mac_dbdma_class_init
932};
933
934static void mac_dbdma_register_types(void)
935{
936 type_register_static(&mac_dbdma_type_info);
937}
938
939type_init(mac_dbdma_register_types)
940