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