]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/misc/macio/mac_dbdma.c
Include migration/vmstate.h less
[thirdparty/qemu.git] / hw / misc / macio / mac_dbdma.c
CommitLineData
3cbee15b
JM
1/*
2 * PowerMac descriptor-based DMA emulation
3 *
4 * Copyright (c) 2005-2007 Fabrice Bellard
5 * Copyright (c) 2007 Jocelyn Mayer
28ce5ce6
AJ
6 * Copyright (c) 2009 Laurent Vivier
7 *
8 * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
9 *
10 * Definitions for using the Apple Descriptor-Based DMA controller
11 * in Power Macintosh computers.
12 *
13 * Copyright (C) 1996 Paul Mackerras.
14 *
15 * some parts from mol 0.9.71
16 *
17 * Descriptor based DMA emulation
18 *
19 * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
3cbee15b
JM
20 *
21 * Permission is hereby granted, free of charge, to any person obtaining a copy
22 * of this software and associated documentation files (the "Software"), to deal
23 * in the Software without restriction, including without limitation the rights
24 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 * copies of the Software, and to permit persons to whom the Software is
26 * furnished to do so, subject to the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be included in
29 * all copies or substantial portions of the Software.
30 *
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
34 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37 * THE SOFTWARE.
38 */
0b8fa32f 39
0d75590d 40#include "qemu/osdep.h"
83c9f4ca 41#include "hw/hw.h"
64552b6b 42#include "hw/irq.h"
0d09e41a 43#include "hw/ppc/mac_dbdma.h"
d6454270 44#include "migration/vmstate.h"
1de7afc9 45#include "qemu/main-loop.h"
0b8fa32f 46#include "qemu/module.h"
03dd024f 47#include "qemu/log.h"
88655881 48#include "sysemu/dma.h"
3cbee15b 49
ea026b2f 50/* debug DBDMA */
ba0b17dd 51#define DEBUG_DBDMA 0
3e49c439 52#define DEBUG_DBDMA_CHANMASK ((1ull << DBDMA_CHANNELS) - 1)
ea026b2f 53
ba0b17dd
MCA
54#define DBDMA_DPRINTF(fmt, ...) do { \
55 if (DEBUG_DBDMA) { \
56 printf("DBDMA: " fmt , ## __VA_ARGS__); \
57 } \
2562755e 58} while (0)
ea026b2f 59
3e49c439
MCA
60#define DBDMA_DPRINTFCH(ch, fmt, ...) do { \
61 if (DEBUG_DBDMA) { \
62 if ((1ul << (ch)->channel) & DEBUG_DBDMA_CHANMASK) { \
63 printf("DBDMA[%02x]: " fmt , (ch)->channel, ## __VA_ARGS__); \
64 } \
65 } \
2562755e 66} while (0)
3e49c439 67
28ce5ce6
AJ
68/*
69 */
70
d2f0ce21
AG
71static DBDMAState *dbdma_from_ch(DBDMA_channel *ch)
72{
73 return container_of(ch, DBDMAState, channels[ch->channel]);
74}
75
ba0b17dd 76#if DEBUG_DBDMA
b7d67813 77static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
28ce5ce6 78{
b7d67813
MCA
79 DBDMA_DPRINTFCH(ch, "dbdma_cmd %p\n", cmd);
80 DBDMA_DPRINTFCH(ch, " req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
81 DBDMA_DPRINTFCH(ch, " command 0x%04x\n", le16_to_cpu(cmd->command));
82 DBDMA_DPRINTFCH(ch, " phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
83 DBDMA_DPRINTFCH(ch, " cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
84 DBDMA_DPRINTFCH(ch, " res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
85 DBDMA_DPRINTFCH(ch, " xfer_status 0x%04x\n",
86 le16_to_cpu(cmd->xfer_status));
28ce5ce6
AJ
87}
88#else
b7d67813 89static void dump_dbdma_cmd(DBDMA_channel *ch, dbdma_cmd *cmd)
3cbee15b 90{
28ce5ce6
AJ
91}
92#endif
93static void dbdma_cmdptr_load(DBDMA_channel *ch)
94{
3e49c439
MCA
95 DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n",
96 ch->regs[DBDMA_CMDPTR_LO]);
88655881
MCA
97 dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
98 &ch->current, sizeof(dbdma_cmd));
3cbee15b
JM
99}
100
28ce5ce6 101static void dbdma_cmdptr_save(DBDMA_channel *ch)
3cbee15b 102{
77453882
BH
103 DBDMA_DPRINTFCH(ch, "-> update 0x%08x stat=0x%08x, res=0x%04x\n",
104 ch->regs[DBDMA_CMDPTR_LO],
3e49c439
MCA
105 le16_to_cpu(ch->current.xfer_status),
106 le16_to_cpu(ch->current.res_count));
88655881
MCA
107 dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO],
108 &ch->current, sizeof(dbdma_cmd));
3cbee15b
JM
109}
110
28ce5ce6 111static void kill_channel(DBDMA_channel *ch)
3cbee15b 112{
3e49c439 113 DBDMA_DPRINTFCH(ch, "kill_channel\n");
28ce5ce6 114
ad674e53
AJ
115 ch->regs[DBDMA_STATUS] |= DEAD;
116 ch->regs[DBDMA_STATUS] &= ~ACTIVE;
28ce5ce6
AJ
117
118 qemu_irq_raise(ch->irq);
119}
120
121static void conditional_interrupt(DBDMA_channel *ch)
122{
123 dbdma_cmd *current = &ch->current;
124 uint16_t intr;
125 uint16_t sel_mask, sel_value;
126 uint32_t status;
127 int cond;
128
3e49c439 129 DBDMA_DPRINTFCH(ch, "%s\n", __func__);
28ce5ce6 130
b42ec42d 131 intr = le16_to_cpu(current->command) & INTR_MASK;
28ce5ce6
AJ
132
133 switch(intr) {
134 case INTR_NEVER: /* don't interrupt */
135 return;
136 case INTR_ALWAYS: /* always interrupt */
137 qemu_irq_raise(ch->irq);
3e49c439 138 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
28ce5ce6
AJ
139 return;
140 }
141
ad674e53 142 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
28ce5ce6 143
ad674e53
AJ
144 sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
145 sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
28ce5ce6
AJ
146
147 cond = (status & sel_mask) == (sel_value & sel_mask);
148
149 switch(intr) {
150 case INTR_IFSET: /* intr if condition bit is 1 */
33ce36bb 151 if (cond) {
28ce5ce6 152 qemu_irq_raise(ch->irq);
3e49c439 153 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
33ce36bb 154 }
28ce5ce6
AJ
155 return;
156 case INTR_IFCLR: /* intr if condition bit is 0 */
33ce36bb 157 if (!cond) {
28ce5ce6 158 qemu_irq_raise(ch->irq);
3e49c439 159 DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__);
33ce36bb 160 }
28ce5ce6
AJ
161 return;
162 }
163}
164
165static int conditional_wait(DBDMA_channel *ch)
166{
167 dbdma_cmd *current = &ch->current;
168 uint16_t wait;
169 uint16_t sel_mask, sel_value;
170 uint32_t status;
171 int cond;
77453882 172 int res = 0;
28ce5ce6 173
b42ec42d 174 wait = le16_to_cpu(current->command) & WAIT_MASK;
28ce5ce6
AJ
175 switch(wait) {
176 case WAIT_NEVER: /* don't wait */
177 return 0;
178 case WAIT_ALWAYS: /* always wait */
77453882 179 DBDMA_DPRINTFCH(ch, " [WAIT_ALWAYS]\n");
28ce5ce6
AJ
180 return 1;
181 }
182
ad674e53 183 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
28ce5ce6 184
ad674e53
AJ
185 sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
186 sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
28ce5ce6
AJ
187
188 cond = (status & sel_mask) == (sel_value & sel_mask);
189
190 switch(wait) {
191 case WAIT_IFSET: /* wait if condition bit is 1 */
77453882
BH
192 if (cond) {
193 res = 1;
194 }
195 DBDMA_DPRINTFCH(ch, " [WAIT_IFSET=%d]\n", res);
196 break;
28ce5ce6 197 case WAIT_IFCLR: /* wait if condition bit is 0 */
77453882
BH
198 if (!cond) {
199 res = 1;
200 }
201 DBDMA_DPRINTFCH(ch, " [WAIT_IFCLR=%d]\n", res);
202 break;
28ce5ce6 203 }
77453882 204 return res;
28ce5ce6
AJ
205}
206
207static void next(DBDMA_channel *ch)
208{
209 uint32_t cp;
210
ad674e53 211 ch->regs[DBDMA_STATUS] &= ~BT;
28ce5ce6 212
ad674e53
AJ
213 cp = ch->regs[DBDMA_CMDPTR_LO];
214 ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
28ce5ce6
AJ
215 dbdma_cmdptr_load(ch);
216}
217
218static void branch(DBDMA_channel *ch)
219{
220 dbdma_cmd *current = &ch->current;
221
3f0d4128 222 ch->regs[DBDMA_CMDPTR_LO] = le32_to_cpu(current->cmd_dep);
ad674e53 223 ch->regs[DBDMA_STATUS] |= BT;
28ce5ce6
AJ
224 dbdma_cmdptr_load(ch);
225}
226
227static void conditional_branch(DBDMA_channel *ch)
228{
229 dbdma_cmd *current = &ch->current;
230 uint16_t br;
231 uint16_t sel_mask, sel_value;
232 uint32_t status;
233 int cond;
234
28ce5ce6
AJ
235 /* check if we must branch */
236
b42ec42d 237 br = le16_to_cpu(current->command) & BR_MASK;
28ce5ce6
AJ
238
239 switch(br) {
240 case BR_NEVER: /* don't branch */
241 next(ch);
242 return;
243 case BR_ALWAYS: /* always branch */
77453882 244 DBDMA_DPRINTFCH(ch, " [BR_ALWAYS]\n");
28ce5ce6
AJ
245 branch(ch);
246 return;
247 }
248
ad674e53 249 status = ch->regs[DBDMA_STATUS] & DEVSTAT;
28ce5ce6 250
ad674e53
AJ
251 sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
252 sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
28ce5ce6
AJ
253
254 cond = (status & sel_mask) == (sel_value & sel_mask);
255
256 switch(br) {
257 case BR_IFSET: /* branch if condition bit is 1 */
77453882
BH
258 if (cond) {
259 DBDMA_DPRINTFCH(ch, " [BR_IFSET = 1]\n");
28ce5ce6 260 branch(ch);
77453882
BH
261 } else {
262 DBDMA_DPRINTFCH(ch, " [BR_IFSET = 0]\n");
28ce5ce6 263 next(ch);
77453882 264 }
28ce5ce6
AJ
265 return;
266 case BR_IFCLR: /* branch if condition bit is 0 */
77453882
BH
267 if (!cond) {
268 DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 1]\n");
28ce5ce6 269 branch(ch);
77453882
BH
270 } else {
271 DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 0]\n");
28ce5ce6 272 next(ch);
77453882 273 }
28ce5ce6
AJ
274 return;
275 }
276}
277
b42ec42d 278static void channel_run(DBDMA_channel *ch);
28ce5ce6 279
b42ec42d 280static void dbdma_end(DBDMA_io *io)
28ce5ce6
AJ
281{
282 DBDMA_channel *ch = io->channel;
283 dbdma_cmd *current = &ch->current;
284
3e49c439 285 DBDMA_DPRINTFCH(ch, "%s\n", __func__);
33ce36bb 286
b42ec42d
AJ
287 if (conditional_wait(ch))
288 goto wait;
28ce5ce6 289
ad674e53
AJ
290 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
291 current->res_count = cpu_to_le16(io->len);
b42ec42d 292 dbdma_cmdptr_save(ch);
862c9280 293 if (io->is_last)
ad674e53 294 ch->regs[DBDMA_STATUS] &= ~FLUSH;
b42ec42d
AJ
295
296 conditional_interrupt(ch);
297 conditional_branch(ch);
28ce5ce6 298
b42ec42d 299wait:
03ee3b1e
AG
300 /* Indicate that we're ready for a new DMA round */
301 ch->io.processing = false;
302
ad674e53
AJ
303 if ((ch->regs[DBDMA_STATUS] & RUN) &&
304 (ch->regs[DBDMA_STATUS] & ACTIVE))
b42ec42d 305 channel_run(ch);
28ce5ce6
AJ
306}
307
b42ec42d 308static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
28ce5ce6
AJ
309 uint16_t req_count, int is_last)
310{
3e49c439 311 DBDMA_DPRINTFCH(ch, "start_output\n");
28ce5ce6
AJ
312
313 /* KEY_REGS, KEY_DEVICE and KEY_STREAM
314 * are not implemented in the mac-io chip
315 */
316
3e49c439 317 DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
28ce5ce6
AJ
318 if (!addr || key > KEY_STREAM3) {
319 kill_channel(ch);
b42ec42d 320 return;
28ce5ce6
AJ
321 }
322
b42ec42d 323 ch->io.addr = addr;
28ce5ce6
AJ
324 ch->io.len = req_count;
325 ch->io.is_last = is_last;
b42ec42d
AJ
326 ch->io.dma_end = dbdma_end;
327 ch->io.is_dma_out = 1;
03ee3b1e 328 ch->io.processing = true;
a9ceb76d
AG
329 if (ch->rw) {
330 ch->rw(&ch->io);
331 }
28ce5ce6
AJ
332}
333
b42ec42d 334static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
28ce5ce6
AJ
335 uint16_t req_count, int is_last)
336{
3e49c439 337 DBDMA_DPRINTFCH(ch, "start_input\n");
28ce5ce6
AJ
338
339 /* KEY_REGS, KEY_DEVICE and KEY_STREAM
340 * are not implemented in the mac-io chip
341 */
342
3e49c439 343 DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key);
28ce5ce6
AJ
344 if (!addr || key > KEY_STREAM3) {
345 kill_channel(ch);
b42ec42d 346 return;
28ce5ce6
AJ
347 }
348
b42ec42d 349 ch->io.addr = addr;
28ce5ce6
AJ
350 ch->io.len = req_count;
351 ch->io.is_last = is_last;
b42ec42d
AJ
352 ch->io.dma_end = dbdma_end;
353 ch->io.is_dma_out = 0;
03ee3b1e 354 ch->io.processing = true;
a9ceb76d
AG
355 if (ch->rw) {
356 ch->rw(&ch->io);
357 }
28ce5ce6
AJ
358}
359
b42ec42d 360static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
28ce5ce6
AJ
361 uint16_t len)
362{
363 dbdma_cmd *current = &ch->current;
28ce5ce6 364
e12f50b9 365 DBDMA_DPRINTFCH(ch, "load_word %d bytes, addr=%08x\n", len, addr);
28ce5ce6
AJ
366
367 /* only implements KEY_SYSTEM */
368
369 if (key != KEY_SYSTEM) {
370 printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
371 kill_channel(ch);
b42ec42d 372 return;
28ce5ce6
AJ
373 }
374
e12f50b9 375 dma_memory_read(&address_space_memory, addr, &current->cmd_dep, len);
28ce5ce6
AJ
376
377 if (conditional_wait(ch))
b42ec42d 378 goto wait;
28ce5ce6 379
ad674e53 380 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
28ce5ce6 381 dbdma_cmdptr_save(ch);
ad674e53 382 ch->regs[DBDMA_STATUS] &= ~FLUSH;
28ce5ce6
AJ
383
384 conditional_interrupt(ch);
385 next(ch);
386
b42ec42d 387wait:
d2f0ce21 388 DBDMA_kick(dbdma_from_ch(ch));
28ce5ce6
AJ
389}
390
b42ec42d 391static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
28ce5ce6
AJ
392 uint16_t len)
393{
394 dbdma_cmd *current = &ch->current;
28ce5ce6 395
e12f50b9
MCA
396 DBDMA_DPRINTFCH(ch, "store_word %d bytes, addr=%08x pa=%x\n",
397 len, addr, le32_to_cpu(current->cmd_dep));
28ce5ce6
AJ
398
399 /* only implements KEY_SYSTEM */
400
401 if (key != KEY_SYSTEM) {
402 printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
403 kill_channel(ch);
b42ec42d 404 return;
28ce5ce6
AJ
405 }
406
e12f50b9 407 dma_memory_write(&address_space_memory, addr, &current->cmd_dep, len);
28ce5ce6
AJ
408
409 if (conditional_wait(ch))
b42ec42d 410 goto wait;
28ce5ce6 411
ad674e53 412 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
28ce5ce6 413 dbdma_cmdptr_save(ch);
ad674e53 414 ch->regs[DBDMA_STATUS] &= ~FLUSH;
28ce5ce6
AJ
415
416 conditional_interrupt(ch);
417 next(ch);
418
b42ec42d 419wait:
d2f0ce21 420 DBDMA_kick(dbdma_from_ch(ch));
28ce5ce6
AJ
421}
422
b42ec42d 423static void nop(DBDMA_channel *ch)
28ce5ce6
AJ
424{
425 dbdma_cmd *current = &ch->current;
426
427 if (conditional_wait(ch))
b42ec42d 428 goto wait;
28ce5ce6 429
ad674e53 430 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
28ce5ce6
AJ
431 dbdma_cmdptr_save(ch);
432
433 conditional_interrupt(ch);
434 conditional_branch(ch);
435
b42ec42d 436wait:
d2f0ce21 437 DBDMA_kick(dbdma_from_ch(ch));
3cbee15b
JM
438}
439
b42ec42d 440static void stop(DBDMA_channel *ch)
3cbee15b 441{
77453882 442 ch->regs[DBDMA_STATUS] &= ~(ACTIVE);
28ce5ce6
AJ
443
444 /* the stop command does not increment command pointer */
3cbee15b
JM
445}
446
b42ec42d 447static void channel_run(DBDMA_channel *ch)
3cbee15b 448{
28ce5ce6
AJ
449 dbdma_cmd *current = &ch->current;
450 uint16_t cmd, key;
451 uint16_t req_count;
452 uint32_t phy_addr;
453
3e49c439 454 DBDMA_DPRINTFCH(ch, "channel_run\n");
b7d67813 455 dump_dbdma_cmd(ch, current);
28ce5ce6
AJ
456
457 /* clear WAKE flag at command fetch */
458
ad674e53 459 ch->regs[DBDMA_STATUS] &= ~WAKE;
28ce5ce6
AJ
460
461 cmd = le16_to_cpu(current->command) & COMMAND_MASK;
462
463 switch (cmd) {
464 case DBDMA_NOP:
b42ec42d 465 nop(ch);
9e232428 466 return;
28ce5ce6
AJ
467
468 case DBDMA_STOP:
b42ec42d 469 stop(ch);
9e232428 470 return;
28ce5ce6
AJ
471 }
472
473 key = le16_to_cpu(current->command) & 0x0700;
474 req_count = le16_to_cpu(current->req_count);
475 phy_addr = le32_to_cpu(current->phy_addr);
476
477 if (key == KEY_STREAM4) {
478 printf("command %x, invalid key 4\n", cmd);
479 kill_channel(ch);
b42ec42d 480 return;
28ce5ce6
AJ
481 }
482
483 switch (cmd) {
484 case OUTPUT_MORE:
77453882 485 DBDMA_DPRINTFCH(ch, "* OUTPUT_MORE *\n");
b42ec42d 486 start_output(ch, key, phy_addr, req_count, 0);
9e232428 487 return;
28ce5ce6
AJ
488
489 case OUTPUT_LAST:
77453882 490 DBDMA_DPRINTFCH(ch, "* OUTPUT_LAST *\n");
b42ec42d 491 start_output(ch, key, phy_addr, req_count, 1);
9e232428 492 return;
28ce5ce6
AJ
493
494 case INPUT_MORE:
77453882 495 DBDMA_DPRINTFCH(ch, "* INPUT_MORE *\n");
b42ec42d 496 start_input(ch, key, phy_addr, req_count, 0);
9e232428 497 return;
28ce5ce6
AJ
498
499 case INPUT_LAST:
77453882 500 DBDMA_DPRINTFCH(ch, "* INPUT_LAST *\n");
b42ec42d 501 start_input(ch, key, phy_addr, req_count, 1);
9e232428 502 return;
28ce5ce6
AJ
503 }
504
505 if (key < KEY_REGS) {
506 printf("command %x, invalid key %x\n", cmd, key);
507 key = KEY_SYSTEM;
508 }
509
510 /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
511 * and BRANCH is invalid
512 */
513
514 req_count = req_count & 0x0007;
515 if (req_count & 0x4) {
516 req_count = 4;
517 phy_addr &= ~3;
518 } else if (req_count & 0x2) {
519 req_count = 2;
520 phy_addr &= ~1;
521 } else
522 req_count = 1;
523
524 switch (cmd) {
525 case LOAD_WORD:
77453882 526 DBDMA_DPRINTFCH(ch, "* LOAD_WORD *\n");
b42ec42d 527 load_word(ch, key, phy_addr, req_count);
9e232428 528 return;
28ce5ce6
AJ
529
530 case STORE_WORD:
77453882 531 DBDMA_DPRINTFCH(ch, "* STORE_WORD *\n");
b42ec42d 532 store_word(ch, key, phy_addr, req_count);
9e232428 533 return;
28ce5ce6 534 }
3cbee15b
JM
535}
536
c20df14b 537static void DBDMA_run(DBDMAState *s)
28ce5ce6
AJ
538{
539 int channel;
28ce5ce6 540
c20df14b
JQ
541 for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
542 DBDMA_channel *ch = &s->channels[channel];
543 uint32_t status = ch->regs[DBDMA_STATUS];
03ee3b1e 544 if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) {
c20df14b
JQ
545 channel_run(ch);
546 }
28ce5ce6 547 }
28ce5ce6
AJ
548}
549
550static void DBDMA_run_bh(void *opaque)
551{
c20df14b 552 DBDMAState *s = opaque;
28ce5ce6 553
3e49c439 554 DBDMA_DPRINTF("-> DBDMA_run_bh\n");
c20df14b 555 DBDMA_run(s);
3e49c439 556 DBDMA_DPRINTF("<- DBDMA_run_bh\n");
28ce5ce6
AJ
557}
558
d1e562de
AG
559void DBDMA_kick(DBDMAState *dbdma)
560{
d2f0ce21 561 qemu_bh_schedule(dbdma->bh);
d1e562de
AG
562}
563
28ce5ce6 564void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
862c9280 565 DBDMA_rw rw, DBDMA_flush flush,
28ce5ce6
AJ
566 void *opaque)
567{
c20df14b
JQ
568 DBDMAState *s = dbdma;
569 DBDMA_channel *ch = &s->channels[nchan];
28ce5ce6 570
3e49c439 571 DBDMA_DPRINTFCH(ch, "DBDMA_register_channel 0x%x\n", nchan);
28ce5ce6 572
2d7d06d8
HP
573 assert(rw);
574 assert(flush);
575
28ce5ce6 576 ch->irq = irq;
b42ec42d 577 ch->rw = rw;
862c9280 578 ch->flush = flush;
28ce5ce6 579 ch->io.opaque = opaque;
28ce5ce6
AJ
580}
581
77453882 582static void dbdma_control_write(DBDMA_channel *ch)
28ce5ce6
AJ
583{
584 uint16_t mask, value;
585 uint32_t status;
77453882 586 bool do_flush = false;
28ce5ce6 587
ad674e53
AJ
588 mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
589 value = ch->regs[DBDMA_CONTROL] & 0xffff;
28ce5ce6 590
77453882
BH
591 /* This is the status register which we'll update
592 * appropriately and store back
593 */
ad674e53 594 status = ch->regs[DBDMA_STATUS];
28ce5ce6 595
77453882
BH
596 /* RUN and PAUSE are bits under SW control only
597 * FLUSH and WAKE are set by SW and cleared by HW
598 * DEAD, ACTIVE and BT are only under HW control
599 *
600 * We handle ACTIVE separately at the end of the
601 * logic to ensure all cases are covered.
602 */
28ce5ce6 603
77453882
BH
604 /* Setting RUN will tentatively activate the channel
605 */
606 if ((mask & RUN) && (value & RUN)) {
607 status |= RUN;
608 DBDMA_DPRINTFCH(ch, " Setting RUN !\n");
609 }
610
611 /* Clearing RUN 1->0 will stop the channel */
612 if ((mask & RUN) && !(value & RUN)) {
613 /* This has the side effect of clearing the DEAD bit */
614 status &= ~(DEAD | RUN);
615 DBDMA_DPRINTFCH(ch, " Clearing RUN !\n");
616 }
617
618 /* Setting WAKE wakes up an idle channel if it's running
619 *
620 * Note: The doc doesn't say so but assume that only works
621 * on a channel whose RUN bit is set.
622 *
623 * We set WAKE in status, it's not terribly useful as it will
624 * be cleared on the next command fetch but it seems to mimmic
625 * the HW behaviour and is useful for the way we handle
626 * ACTIVE further down.
627 */
628 if ((mask & WAKE) && (value & WAKE) && (status & RUN)) {
629 status |= WAKE;
630 DBDMA_DPRINTFCH(ch, " Setting WAKE !\n");
631 }
632
633 /* PAUSE being set will deactivate (or prevent activation)
634 * of the channel. We just copy it over for now, ACTIVE will
635 * be re-evaluated later.
636 */
637 if (mask & PAUSE) {
638 status = (status & ~PAUSE) | (value & PAUSE);
639 DBDMA_DPRINTFCH(ch, " %sing PAUSE !\n",
640 (value & PAUSE) ? "sett" : "clear");
641 }
642
643 /* FLUSH is its own thing */
644 if ((mask & FLUSH) && (value & FLUSH)) {
645 DBDMA_DPRINTFCH(ch, " Setting FLUSH !\n");
646 /* We set flush directly in the status register, we do *NOT*
647 * set it in "status" so that it gets naturally cleared when
648 * we update the status register further down. That way it
649 * will be set only during the HW flush operation so it is
650 * visible to any completions happening during that time.
651 */
652 ch->regs[DBDMA_STATUS] |= FLUSH;
653 do_flush = true;
28ce5ce6 654 }
77453882
BH
655
656 /* If either RUN or PAUSE is clear, so should ACTIVE be,
657 * otherwise, ACTIVE will be set if we modified RUN, PAUSE or
658 * set WAKE. That means that PAUSE was just cleared, RUN was
659 * just set or WAKE was just set.
660 */
661 if ((status & PAUSE) || !(status & RUN)) {
28ce5ce6 662 status &= ~ACTIVE;
77453882
BH
663 DBDMA_DPRINTFCH(ch, " -> ACTIVE down !\n");
664
665 /* We stopped processing, we want the underlying HW command
666 * to complete *before* we clear the ACTIVE bit. Otherwise
667 * we can get into a situation where the command status will
668 * have RUN or ACTIVE not set which is going to confuse the
669 * MacOS driver.
670 */
671 do_flush = true;
672 } else if (mask & (RUN | PAUSE)) {
673 status |= ACTIVE;
674 DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
675 } else if ((mask & WAKE) && (value & WAKE)) {
676 status |= ACTIVE;
677 DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n");
1cde732d
MCA
678 }
679
77453882
BH
680 DBDMA_DPRINTFCH(ch, " new status=0x%08x\n", status);
681
682 /* If we need to flush the underlying HW, do it now, this happens
683 * both on FLUSH commands and when stopping the channel for safety.
684 */
685 if (do_flush && ch->flush) {
1cde732d 686 ch->flush(&ch->io);
28ce5ce6
AJ
687 }
688
77453882 689 /* Finally update the status register image */
ad674e53 690 ch->regs[DBDMA_STATUS] = status;
28ce5ce6 691
77453882 692 /* If active, make sure the BH gets to run */
d2f0ce21
AG
693 if (status & ACTIVE) {
694 DBDMA_kick(dbdma_from_ch(ch));
695 }
28ce5ce6
AJ
696}
697
a8170e5e 698static void dbdma_write(void *opaque, hwaddr addr,
23c5e4ca 699 uint64_t value, unsigned size)
28ce5ce6
AJ
700{
701 int channel = addr >> DBDMA_CHANNEL_SHIFT;
c20df14b
JQ
702 DBDMAState *s = opaque;
703 DBDMA_channel *ch = &s->channels[channel];
28ce5ce6
AJ
704 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
705
3e49c439
MCA
706 DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n",
707 addr, value);
708 DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
709 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
28ce5ce6 710
7eaba824 711 /* cmdptr cannot be modified if channel is ACTIVE */
28ce5ce6 712
7eaba824 713 if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) {
9e232428 714 return;
7eaba824 715 }
28ce5ce6
AJ
716
717 ch->regs[reg] = value;
718
719 switch(reg) {
720 case DBDMA_CONTROL:
721 dbdma_control_write(ch);
722 break;
723 case DBDMA_CMDPTR_LO:
724 /* 16-byte aligned */
ad674e53 725 ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
28ce5ce6
AJ
726 dbdma_cmdptr_load(ch);
727 break;
728 case DBDMA_STATUS:
729 case DBDMA_INTR_SEL:
730 case DBDMA_BRANCH_SEL:
731 case DBDMA_WAIT_SEL:
732 /* nothing to do */
733 break;
734 case DBDMA_XFER_MODE:
735 case DBDMA_CMDPTR_HI:
736 case DBDMA_DATA2PTR_HI:
737 case DBDMA_DATA2PTR_LO:
738 case DBDMA_ADDRESS_HI:
739 case DBDMA_BRANCH_ADDR_HI:
740 case DBDMA_RES1:
741 case DBDMA_RES2:
742 case DBDMA_RES3:
743 case DBDMA_RES4:
744 /* unused */
745 break;
746 }
747}
748
a8170e5e 749static uint64_t dbdma_read(void *opaque, hwaddr addr,
23c5e4ca 750 unsigned size)
3cbee15b 751{
28ce5ce6
AJ
752 uint32_t value;
753 int channel = addr >> DBDMA_CHANNEL_SHIFT;
c20df14b
JQ
754 DBDMAState *s = opaque;
755 DBDMA_channel *ch = &s->channels[channel];
28ce5ce6 756 int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
ea026b2f 757
28ce5ce6
AJ
758 value = ch->regs[reg];
759
28ce5ce6
AJ
760 switch(reg) {
761 case DBDMA_CONTROL:
77453882 762 value = ch->regs[DBDMA_STATUS];
28ce5ce6
AJ
763 break;
764 case DBDMA_STATUS:
765 case DBDMA_CMDPTR_LO:
766 case DBDMA_INTR_SEL:
767 case DBDMA_BRANCH_SEL:
768 case DBDMA_WAIT_SEL:
769 /* nothing to do */
770 break;
771 case DBDMA_XFER_MODE:
772 case DBDMA_CMDPTR_HI:
773 case DBDMA_DATA2PTR_HI:
774 case DBDMA_DATA2PTR_LO:
775 case DBDMA_ADDRESS_HI:
776 case DBDMA_BRANCH_ADDR_HI:
777 /* unused */
778 value = 0;
779 break;
780 case DBDMA_RES1:
781 case DBDMA_RES2:
782 case DBDMA_RES3:
783 case DBDMA_RES4:
784 /* reserved */
785 break;
786 }
787
77453882
BH
788 DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
789 DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n",
790 (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
791
28ce5ce6 792 return value;
3cbee15b
JM
793}
794
23c5e4ca
AK
795static const MemoryRegionOps dbdma_ops = {
796 .read = dbdma_read,
797 .write = dbdma_write,
798 .endianness = DEVICE_LITTLE_ENDIAN,
799 .valid = {
800 .min_access_size = 4,
801 .max_access_size = 4,
802 },
3cbee15b
JM
803};
804
627be2f2
MCA
805static const VMStateDescription vmstate_dbdma_io = {
806 .name = "dbdma_io",
807 .version_id = 0,
808 .minimum_version_id = 0,
809 .fields = (VMStateField[]) {
810 VMSTATE_UINT64(addr, struct DBDMA_io),
811 VMSTATE_INT32(len, struct DBDMA_io),
812 VMSTATE_INT32(is_last, struct DBDMA_io),
813 VMSTATE_INT32(is_dma_out, struct DBDMA_io),
814 VMSTATE_BOOL(processing, struct DBDMA_io),
815 VMSTATE_END_OF_LIST()
816 }
817};
818
819static const VMStateDescription vmstate_dbdma_cmd = {
820 .name = "dbdma_cmd",
da26fdc3
JQ
821 .version_id = 0,
822 .minimum_version_id = 0,
627be2f2
MCA
823 .fields = (VMStateField[]) {
824 VMSTATE_UINT16(req_count, dbdma_cmd),
825 VMSTATE_UINT16(command, dbdma_cmd),
826 VMSTATE_UINT32(phy_addr, dbdma_cmd),
827 VMSTATE_UINT32(cmd_dep, dbdma_cmd),
828 VMSTATE_UINT16(res_count, dbdma_cmd),
829 VMSTATE_UINT16(xfer_status, dbdma_cmd),
830 VMSTATE_END_OF_LIST()
831 }
832};
833
834static const VMStateDescription vmstate_dbdma_channel = {
835 .name = "dbdma_channel",
836 .version_id = 1,
837 .minimum_version_id = 1,
35d08458 838 .fields = (VMStateField[]) {
da26fdc3 839 VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
627be2f2
MCA
840 VMSTATE_STRUCT(io, struct DBDMA_channel, 0, vmstate_dbdma_io, DBDMA_io),
841 VMSTATE_STRUCT(current, struct DBDMA_channel, 0, vmstate_dbdma_cmd,
842 dbdma_cmd),
da26fdc3
JQ
843 VMSTATE_END_OF_LIST()
844 }
845};
28ce5ce6 846
da26fdc3
JQ
847static const VMStateDescription vmstate_dbdma = {
848 .name = "dbdma",
627be2f2
MCA
849 .version_id = 3,
850 .minimum_version_id = 3,
35d08458 851 .fields = (VMStateField[]) {
da26fdc3
JQ
852 VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
853 vmstate_dbdma_channel, DBDMA_channel),
854 VMSTATE_END_OF_LIST()
855 }
856};
9b64997f 857
1d27f351 858static void mac_dbdma_reset(DeviceState *d)
6e6b7363 859{
1d27f351 860 DBDMAState *s = MAC_DBDMA(d);
28ce5ce6
AJ
861 int i;
862
1d27f351 863 for (i = 0; i < DBDMA_CHANNELS; i++) {
c20df14b 864 memset(s->channels[i].regs, 0, DBDMA_SIZE);
1d27f351 865 }
6e6b7363
BS
866}
867
2d7d06d8 868static void dbdma_unassigned_rw(DBDMA_io *io)
2d7d06d8
HP
869{
870 DBDMA_channel *ch = io->channel;
89499390
MCA
871 dbdma_cmd *current = &ch->current;
872 uint16_t cmd;
2d7d06d8
HP
873 qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
874 __func__, ch->channel);
77453882 875 ch->io.processing = false;
89499390
MCA
876
877 cmd = le16_to_cpu(current->command) & COMMAND_MASK;
878 if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST ||
879 cmd == INPUT_MORE || cmd == INPUT_LAST) {
77453882 880 current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
89499390
MCA
881 current->res_count = cpu_to_le16(io->len);
882 dbdma_cmdptr_save(ch);
883 }
2d7d06d8
HP
884}
885
77453882
BH
886static void dbdma_unassigned_flush(DBDMA_io *io)
887{
888 DBDMA_channel *ch = io->channel;
889 qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n",
890 __func__, ch->channel);
891}
892
1d27f351
MCA
893static void mac_dbdma_init(Object *obj)
894{
895 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
896 DBDMAState *s = MAC_DBDMA(obj);
897 int i;
28ce5ce6 898
3e300fa6 899 for (i = 0; i < DBDMA_CHANNELS; i++) {
2d7d06d8 900 DBDMA_channel *ch = &s->channels[i];
2d7d06d8
HP
901
902 ch->rw = dbdma_unassigned_rw;
903 ch->flush = dbdma_unassigned_flush;
904 ch->channel = i;
905 ch->io.channel = ch;
3e300fa6
AG
906 }
907
1d27f351
MCA
908 memory_region_init_io(&s->mem, obj, &dbdma_ops, s, "dbdma", 0x1000);
909 sysbus_init_mmio(sbd, &s->mem);
910}
911
912static void mac_dbdma_realize(DeviceState *dev, Error **errp)
913{
914 DBDMAState *s = MAC_DBDMA(dev);
28ce5ce6 915
d2f0ce21 916 s->bh = qemu_bh_new(DBDMA_run_bh, s);
1d27f351 917}
28ce5ce6 918
1d27f351
MCA
919static void mac_dbdma_class_init(ObjectClass *oc, void *data)
920{
921 DeviceClass *dc = DEVICE_CLASS(oc);
922
923 dc->realize = mac_dbdma_realize;
924 dc->reset = mac_dbdma_reset;
925 dc->vmsd = &vmstate_dbdma;
3cbee15b 926}
1d27f351
MCA
927
928static const TypeInfo mac_dbdma_type_info = {
929 .name = TYPE_MAC_DBDMA,
930 .parent = TYPE_SYS_BUS_DEVICE,
931 .instance_size = sizeof(DBDMAState),
932 .instance_init = mac_dbdma_init,
933 .class_init = mac_dbdma_class_init
934};
935
936static void mac_dbdma_register_types(void)
937{
938 type_register_static(&mac_dbdma_type_info);
939}
940
941type_init(mac_dbdma_register_types)