]> git.proxmox.com Git - mirror_qemu.git/blob - hw/dma/i8257.c
35ca8a4e4bc38f8c25bde6adcc25b51b813cd011
[mirror_qemu.git] / hw / dma / i8257.c
1 /*
2 * QEMU DMA emulation
3 *
4 * Copyright (c) 2003-2004 Vassili Karpov (malc)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "qemu/osdep.h"
25 #include "hw/hw.h"
26 #include "hw/isa/isa.h"
27 #include "hw/isa/i8257.h"
28 #include "qemu/main-loop.h"
29 #include "trace.h"
30
31 #define I8257(obj) \
32 OBJECT_CHECK(I8257State, (obj), TYPE_I8257)
33
34 /* #define DEBUG_DMA */
35
36 #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
37 #ifdef DEBUG_DMA
38 #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
39 #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
40 #else
41 #define linfo(...)
42 #define ldebug(...)
43 #endif
44
45 #define ADDR 0
46 #define COUNT 1
47
48 static I8257State *dma_controllers[2];
49
50 enum {
51 CMD_MEMORY_TO_MEMORY = 0x01,
52 CMD_FIXED_ADDRESS = 0x02,
53 CMD_BLOCK_CONTROLLER = 0x04,
54 CMD_COMPRESSED_TIME = 0x08,
55 CMD_CYCLIC_PRIORITY = 0x10,
56 CMD_EXTENDED_WRITE = 0x20,
57 CMD_LOW_DREQ = 0x40,
58 CMD_LOW_DACK = 0x80,
59 CMD_NOT_SUPPORTED = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
60 | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
61 | CMD_LOW_DREQ | CMD_LOW_DACK
62
63 };
64
65 static void i8257_dma_run(void *opaque);
66
67 static const int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
68
69 static void i8257_write_page(void *opaque, uint32_t nport, uint32_t data)
70 {
71 I8257State *d = opaque;
72 int ichan;
73
74 ichan = channels[nport & 7];
75 if (-1 == ichan) {
76 dolog ("invalid channel %#x %#x\n", nport, data);
77 return;
78 }
79 d->regs[ichan].page = data;
80 }
81
82 static void i8257_write_pageh(void *opaque, uint32_t nport, uint32_t data)
83 {
84 I8257State *d = opaque;
85 int ichan;
86
87 ichan = channels[nport & 7];
88 if (-1 == ichan) {
89 dolog ("invalid channel %#x %#x\n", nport, data);
90 return;
91 }
92 d->regs[ichan].pageh = data;
93 }
94
95 static uint32_t i8257_read_page(void *opaque, uint32_t nport)
96 {
97 I8257State *d = opaque;
98 int ichan;
99
100 ichan = channels[nport & 7];
101 if (-1 == ichan) {
102 dolog ("invalid channel read %#x\n", nport);
103 return 0;
104 }
105 return d->regs[ichan].page;
106 }
107
108 static uint32_t i8257_read_pageh(void *opaque, uint32_t nport)
109 {
110 I8257State *d = opaque;
111 int ichan;
112
113 ichan = channels[nport & 7];
114 if (-1 == ichan) {
115 dolog ("invalid channel read %#x\n", nport);
116 return 0;
117 }
118 return d->regs[ichan].pageh;
119 }
120
121 static inline void i8257_init_chan(I8257State *d, int ichan)
122 {
123 I8257Regs *r;
124
125 r = d->regs + ichan;
126 r->now[ADDR] = r->base[ADDR] << d->dshift;
127 r->now[COUNT] = 0;
128 }
129
130 static inline int i8257_getff(I8257State *d)
131 {
132 int ff;
133
134 ff = d->flip_flop;
135 d->flip_flop = !ff;
136 return ff;
137 }
138
139 static uint64_t i8257_read_chan(void *opaque, hwaddr nport, unsigned size)
140 {
141 I8257State *d = opaque;
142 int ichan, nreg, iport, ff, val, dir;
143 I8257Regs *r;
144
145 iport = (nport >> d->dshift) & 0x0f;
146 ichan = iport >> 1;
147 nreg = iport & 1;
148 r = d->regs + ichan;
149
150 dir = ((r->mode >> 5) & 1) ? -1 : 1;
151 ff = i8257_getff(d);
152 if (nreg)
153 val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
154 else
155 val = r->now[ADDR] + r->now[COUNT] * dir;
156
157 ldebug ("read_chan %#x -> %d\n", iport, val);
158 return (val >> (d->dshift + (ff << 3))) & 0xff;
159 }
160
161 static void i8257_write_chan(void *opaque, hwaddr nport, uint64_t data,
162 unsigned int size)
163 {
164 I8257State *d = opaque;
165 int iport, ichan, nreg;
166 I8257Regs *r;
167
168 iport = (nport >> d->dshift) & 0x0f;
169 ichan = iport >> 1;
170 nreg = iport & 1;
171 r = d->regs + ichan;
172 if (i8257_getff(d)) {
173 r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
174 i8257_init_chan(d, ichan);
175 } else {
176 r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
177 }
178 }
179
180 static void i8257_write_cont(void *opaque, hwaddr nport, uint64_t data,
181 unsigned int size)
182 {
183 I8257State *d = opaque;
184 int iport, ichan = 0;
185
186 iport = (nport >> d->dshift) & 0x0f;
187 switch (iport) {
188 case 0x00: /* command */
189 if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
190 dolog("command %"PRIx64" not supported\n", data);
191 return;
192 }
193 d->command = data;
194 break;
195
196 case 0x01:
197 ichan = data & 3;
198 if (data & 4) {
199 d->status |= 1 << (ichan + 4);
200 }
201 else {
202 d->status &= ~(1 << (ichan + 4));
203 }
204 d->status &= ~(1 << ichan);
205 i8257_dma_run(d);
206 break;
207
208 case 0x02: /* single mask */
209 if (data & 4)
210 d->mask |= 1 << (data & 3);
211 else
212 d->mask &= ~(1 << (data & 3));
213 i8257_dma_run(d);
214 break;
215
216 case 0x03: /* mode */
217 {
218 ichan = data & 3;
219 #ifdef DEBUG_DMA
220 {
221 int op, ai, dir, opmode;
222 op = (data >> 2) & 3;
223 ai = (data >> 4) & 1;
224 dir = (data >> 5) & 1;
225 opmode = (data >> 6) & 3;
226
227 linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
228 ichan, op, ai, dir, opmode);
229 }
230 #endif
231 d->regs[ichan].mode = data;
232 break;
233 }
234
235 case 0x04: /* clear flip flop */
236 d->flip_flop = 0;
237 break;
238
239 case 0x05: /* reset */
240 d->flip_flop = 0;
241 d->mask = ~0;
242 d->status = 0;
243 d->command = 0;
244 break;
245
246 case 0x06: /* clear mask for all channels */
247 d->mask = 0;
248 i8257_dma_run(d);
249 break;
250
251 case 0x07: /* write mask for all channels */
252 d->mask = data;
253 i8257_dma_run(d);
254 break;
255
256 default:
257 dolog ("unknown iport %#x\n", iport);
258 break;
259 }
260
261 #ifdef DEBUG_DMA
262 if (0xc != iport) {
263 linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
264 nport, ichan, data);
265 }
266 #endif
267 }
268
269 static uint64_t i8257_read_cont(void *opaque, hwaddr nport, unsigned size)
270 {
271 I8257State *d = opaque;
272 int iport, val;
273
274 iport = (nport >> d->dshift) & 0x0f;
275 switch (iport) {
276 case 0x00: /* status */
277 val = d->status;
278 d->status &= 0xf0;
279 break;
280 case 0x01: /* mask */
281 val = d->mask;
282 break;
283 default:
284 val = 0;
285 break;
286 }
287
288 ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
289 return val;
290 }
291
292 int DMA_get_channel_mode (int nchan)
293 {
294 return dma_controllers[nchan > 3]->regs[nchan & 3].mode;
295 }
296
297 void DMA_hold_DREQ (int nchan)
298 {
299 int ncont, ichan;
300
301 ncont = nchan > 3;
302 ichan = nchan & 3;
303 linfo ("held cont=%d chan=%d\n", ncont, ichan);
304 dma_controllers[ncont]->status |= 1 << (ichan + 4);
305 i8257_dma_run(dma_controllers[ncont]);
306 }
307
308 void DMA_release_DREQ (int nchan)
309 {
310 int ncont, ichan;
311
312 ncont = nchan > 3;
313 ichan = nchan & 3;
314 linfo ("released cont=%d chan=%d\n", ncont, ichan);
315 dma_controllers[ncont]->status &= ~(1 << (ichan + 4));
316 i8257_dma_run(dma_controllers[ncont]);
317 }
318
319 static void i8257_channel_run(I8257State *d, int ichan)
320 {
321 int ncont = d->dshift;
322 int n;
323 I8257Regs *r = &d->regs[ichan];
324 #ifdef DEBUG_DMA
325 int dir, opmode;
326
327 dir = (r->mode >> 5) & 1;
328 opmode = (r->mode >> 6) & 3;
329
330 if (dir) {
331 dolog ("DMA in address decrement mode\n");
332 }
333 if (opmode != 1) {
334 dolog ("DMA not in single mode select %#x\n", opmode);
335 }
336 #endif
337
338 n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
339 r->now[COUNT], (r->base[COUNT] + 1) << ncont);
340 r->now[COUNT] = n;
341 ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
342 }
343
344 static void i8257_dma_run(void *opaque)
345 {
346 I8257State *d = opaque;
347 int ichan;
348 int rearm = 0;
349
350 if (d->running) {
351 rearm = 1;
352 goto out;
353 } else {
354 d->running = 1;
355 }
356
357 for (ichan = 0; ichan < 4; ichan++) {
358 int mask;
359
360 mask = 1 << ichan;
361
362 if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
363 i8257_channel_run(d, ichan);
364 rearm = 1;
365 }
366 }
367
368 d->running = 0;
369 out:
370 if (rearm) {
371 qemu_bh_schedule_idle(d->dma_bh);
372 d->dma_bh_scheduled = true;
373 }
374 }
375
376 void DMA_register_channel (int nchan,
377 DMA_transfer_handler transfer_handler,
378 void *opaque)
379 {
380 I8257Regs *r;
381 int ichan, ncont;
382
383 ncont = nchan > 3;
384 ichan = nchan & 3;
385
386 r = dma_controllers[ncont]->regs + ichan;
387 r->transfer_handler = transfer_handler;
388 r->opaque = opaque;
389 }
390
391 int DMA_read_memory (int nchan, void *buf, int pos, int len)
392 {
393 I8257Regs *r = &dma_controllers[nchan > 3]->regs[nchan & 3];
394 hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
395
396 if (r->mode & 0x20) {
397 int i;
398 uint8_t *p = buf;
399
400 cpu_physical_memory_read (addr - pos - len, buf, len);
401 /* What about 16bit transfers? */
402 for (i = 0; i < len >> 1; i++) {
403 uint8_t b = p[len - i - 1];
404 p[i] = b;
405 }
406 }
407 else
408 cpu_physical_memory_read (addr + pos, buf, len);
409
410 return len;
411 }
412
413 int DMA_write_memory (int nchan, void *buf, int pos, int len)
414 {
415 I8257Regs *r = &dma_controllers[nchan > 3]->regs[nchan & 3];
416 hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
417
418 if (r->mode & 0x20) {
419 int i;
420 uint8_t *p = buf;
421
422 cpu_physical_memory_write (addr - pos - len, buf, len);
423 /* What about 16bit transfers? */
424 for (i = 0; i < len; i++) {
425 uint8_t b = p[len - i - 1];
426 p[i] = b;
427 }
428 }
429 else
430 cpu_physical_memory_write (addr + pos, buf, len);
431
432 return len;
433 }
434
435 /* request the emulator to transfer a new DMA memory block ASAP (even
436 * if the idle bottom half would not have exited the iothread yet).
437 */
438 void DMA_schedule(void)
439 {
440 if (dma_controllers[0]->dma_bh_scheduled ||
441 dma_controllers[1]->dma_bh_scheduled) {
442 qemu_notify_event();
443 }
444 }
445
446 static void i8257_reset(DeviceState *dev)
447 {
448 I8257State *d = I8257(dev);
449 i8257_write_cont(d, (0x05 << d->dshift), 0, 1);
450 }
451
452 static int i8257_phony_handler(void *opaque, int nchan, int dma_pos,
453 int dma_len)
454 {
455 trace_i8257_unregistered_dma(nchan, dma_pos, dma_len);
456 return dma_pos;
457 }
458
459
460 static const MemoryRegionOps channel_io_ops = {
461 .read = i8257_read_chan,
462 .write = i8257_write_chan,
463 .endianness = DEVICE_NATIVE_ENDIAN,
464 .impl = {
465 .min_access_size = 1,
466 .max_access_size = 1,
467 },
468 };
469
470 /* IOport from page_base */
471 static const MemoryRegionPortio page_portio_list[] = {
472 { 0x01, 3, 1, .write = i8257_write_page, .read = i8257_read_page, },
473 { 0x07, 1, 1, .write = i8257_write_page, .read = i8257_read_page, },
474 PORTIO_END_OF_LIST(),
475 };
476
477 /* IOport from pageh_base */
478 static const MemoryRegionPortio pageh_portio_list[] = {
479 { 0x01, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
480 { 0x07, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
481 PORTIO_END_OF_LIST(),
482 };
483
484 static const MemoryRegionOps cont_io_ops = {
485 .read = i8257_read_cont,
486 .write = i8257_write_cont,
487 .endianness = DEVICE_NATIVE_ENDIAN,
488 .impl = {
489 .min_access_size = 1,
490 .max_access_size = 1,
491 },
492 };
493
494 static const VMStateDescription vmstate_i8257_regs = {
495 .name = "dma_regs",
496 .version_id = 1,
497 .minimum_version_id = 1,
498 .fields = (VMStateField[]) {
499 VMSTATE_INT32_ARRAY(now, I8257Regs, 2),
500 VMSTATE_UINT16_ARRAY(base, I8257Regs, 2),
501 VMSTATE_UINT8(mode, I8257Regs),
502 VMSTATE_UINT8(page, I8257Regs),
503 VMSTATE_UINT8(pageh, I8257Regs),
504 VMSTATE_UINT8(dack, I8257Regs),
505 VMSTATE_UINT8(eop, I8257Regs),
506 VMSTATE_END_OF_LIST()
507 }
508 };
509
510 static int i8257_post_load(void *opaque, int version_id)
511 {
512 I8257State *d = opaque;
513 i8257_dma_run(d);
514
515 return 0;
516 }
517
518 static const VMStateDescription vmstate_i8257 = {
519 .name = "dma",
520 .version_id = 1,
521 .minimum_version_id = 1,
522 .post_load = i8257_post_load,
523 .fields = (VMStateField[]) {
524 VMSTATE_UINT8(command, I8257State),
525 VMSTATE_UINT8(mask, I8257State),
526 VMSTATE_UINT8(flip_flop, I8257State),
527 VMSTATE_INT32(dshift, I8257State),
528 VMSTATE_STRUCT_ARRAY(regs, I8257State, 4, 1, vmstate_i8257_regs,
529 I8257Regs),
530 VMSTATE_END_OF_LIST()
531 }
532 };
533
534 static void i8257_realize(DeviceState *dev, Error **errp)
535 {
536 ISADevice *isa = ISA_DEVICE(dev);
537 I8257State *d = I8257(dev);
538 int i;
539
540 memory_region_init_io(&d->channel_io, NULL, &channel_io_ops, d,
541 "dma-chan", 8 << d->dshift);
542 memory_region_add_subregion(isa_address_space_io(isa),
543 d->base, &d->channel_io);
544
545 isa_register_portio_list(isa, d->page_base, page_portio_list, d,
546 "dma-page");
547 if (d->pageh_base >= 0) {
548 isa_register_portio_list(isa, d->pageh_base, pageh_portio_list, d,
549 "dma-pageh");
550 }
551
552 memory_region_init_io(&d->cont_io, OBJECT(isa), &cont_io_ops, d,
553 "dma-cont", 8 << d->dshift);
554 memory_region_add_subregion(isa_address_space_io(isa),
555 d->base + (8 << d->dshift), &d->cont_io);
556
557 for (i = 0; i < ARRAY_SIZE(d->regs); ++i) {
558 d->regs[i].transfer_handler = i8257_phony_handler;
559 }
560
561 d->dma_bh = qemu_bh_new(i8257_dma_run, d);
562 }
563
564 static Property i8257_properties[] = {
565 DEFINE_PROP_INT32("base", I8257State, base, 0x00),
566 DEFINE_PROP_INT32("page-base", I8257State, page_base, 0x80),
567 DEFINE_PROP_INT32("pageh-base", I8257State, pageh_base, 0x480),
568 DEFINE_PROP_INT32("dshift", I8257State, dshift, 0),
569 DEFINE_PROP_END_OF_LIST()
570 };
571
572 static void i8257_class_init(ObjectClass *klass, void *data)
573 {
574 DeviceClass *dc = DEVICE_CLASS(klass);
575
576 dc->realize = i8257_realize;
577 dc->reset = i8257_reset;
578 dc->vmsd = &vmstate_i8257;
579 dc->props = i8257_properties;
580 }
581
582 static const TypeInfo i8257_info = {
583 .name = TYPE_I8257,
584 .parent = TYPE_ISA_DEVICE,
585 .instance_size = sizeof(I8257State),
586 .class_init = i8257_class_init,
587 };
588
589 static void i8257_register_types(void)
590 {
591 type_register_static(&i8257_info);
592 }
593
594 type_init(i8257_register_types)
595
596 void DMA_init(ISABus *bus, int high_page_enable)
597 {
598 ISADevice *isa1, *isa2;
599 DeviceState *d;
600
601 isa1 = isa_create(bus, TYPE_I8257);
602 d = DEVICE(isa1);
603 qdev_prop_set_int32(d, "base", 0x00);
604 qdev_prop_set_int32(d, "page-base", 0x80);
605 qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x480 : -1);
606 qdev_prop_set_int32(d, "dshift", 0);
607 qdev_init_nofail(d);
608 dma_controllers[0] = I8257(d);
609
610 isa2 = isa_create(bus, TYPE_I8257);
611 d = DEVICE(isa2);
612 qdev_prop_set_int32(d, "base", 0xc0);
613 qdev_prop_set_int32(d, "page-base", 0x88);
614 qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x488 : -1);
615 qdev_prop_set_int32(d, "dshift", 1);
616 qdev_init_nofail(d);
617 dma_controllers[1] = I8257(d);
618 }