xref: /openbmc/qemu/hw/dma/i8257.c (revision 1be82d89)
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/dma/i8257.h"
28 #include "qemu/main-loop.h"
29 #include "qemu/log.h"
30 #include "trace.h"
31 
32 #define I8257(obj) \
33     OBJECT_CHECK(I8257State, (obj), TYPE_I8257)
34 
35 /* #define DEBUG_DMA */
36 
37 #define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
38 #ifdef DEBUG_DMA
39 #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
40 #define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
41 #else
42 #define linfo(...)
43 #define ldebug(...)
44 #endif
45 
46 #define ADDR 0
47 #define COUNT 1
48 
49 enum {
50     CMD_MEMORY_TO_MEMORY = 0x01,
51     CMD_FIXED_ADDRESS    = 0x02,
52     CMD_BLOCK_CONTROLLER = 0x04,
53     CMD_COMPRESSED_TIME  = 0x08,
54     CMD_CYCLIC_PRIORITY  = 0x10,
55     CMD_EXTENDED_WRITE   = 0x20,
56     CMD_LOW_DREQ         = 0x40,
57     CMD_LOW_DACK         = 0x80,
58     CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
59     | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
60     | CMD_LOW_DREQ | CMD_LOW_DACK
61 
62 };
63 
64 static void i8257_dma_run(void *opaque);
65 
66 static const int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
67 
68 static void i8257_write_page(void *opaque, uint32_t nport, uint32_t data)
69 {
70     I8257State *d = opaque;
71     int ichan;
72 
73     ichan = channels[nport & 7];
74     if (-1 == ichan) {
75         dolog ("invalid channel %#x %#x\n", nport, data);
76         return;
77     }
78     d->regs[ichan].page = data;
79 }
80 
81 static void i8257_write_pageh(void *opaque, uint32_t nport, uint32_t data)
82 {
83     I8257State *d = opaque;
84     int ichan;
85 
86     ichan = channels[nport & 7];
87     if (-1 == ichan) {
88         dolog ("invalid channel %#x %#x\n", nport, data);
89         return;
90     }
91     d->regs[ichan].pageh = data;
92 }
93 
94 static uint32_t i8257_read_page(void *opaque, uint32_t nport)
95 {
96     I8257State *d = opaque;
97     int ichan;
98 
99     ichan = channels[nport & 7];
100     if (-1 == ichan) {
101         dolog ("invalid channel read %#x\n", nport);
102         return 0;
103     }
104     return d->regs[ichan].page;
105 }
106 
107 static uint32_t i8257_read_pageh(void *opaque, uint32_t nport)
108 {
109     I8257State *d = opaque;
110     int ichan;
111 
112     ichan = channels[nport & 7];
113     if (-1 == ichan) {
114         dolog ("invalid channel read %#x\n", nport);
115         return 0;
116     }
117     return d->regs[ichan].pageh;
118 }
119 
120 static inline void i8257_init_chan(I8257State *d, int ichan)
121 {
122     I8257Regs *r;
123 
124     r = d->regs + ichan;
125     r->now[ADDR] = r->base[ADDR] << d->dshift;
126     r->now[COUNT] = 0;
127 }
128 
129 static inline int i8257_getff(I8257State *d)
130 {
131     int ff;
132 
133     ff = d->flip_flop;
134     d->flip_flop = !ff;
135     return ff;
136 }
137 
138 static uint64_t i8257_read_chan(void *opaque, hwaddr nport, unsigned size)
139 {
140     I8257State *d = opaque;
141     int ichan, nreg, iport, ff, val, dir;
142     I8257Regs *r;
143 
144     iport = (nport >> d->dshift) & 0x0f;
145     ichan = iport >> 1;
146     nreg = iport & 1;
147     r = d->regs + ichan;
148 
149     dir = ((r->mode >> 5) & 1) ? -1 : 1;
150     ff = i8257_getff(d);
151     if (nreg)
152         val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
153     else
154         val = r->now[ADDR] + r->now[COUNT] * dir;
155 
156     ldebug ("read_chan %#x -> %d\n", iport, val);
157     return (val >> (d->dshift + (ff << 3))) & 0xff;
158 }
159 
160 static void i8257_write_chan(void *opaque, hwaddr nport, uint64_t data,
161                              unsigned int size)
162 {
163     I8257State *d = opaque;
164     int iport, ichan, nreg;
165     I8257Regs *r;
166 
167     iport = (nport >> d->dshift) & 0x0f;
168     ichan = iport >> 1;
169     nreg = iport & 1;
170     r = d->regs + ichan;
171     if (i8257_getff(d)) {
172         r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
173         i8257_init_chan(d, ichan);
174     } else {
175         r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
176     }
177 }
178 
179 static void i8257_write_cont(void *opaque, hwaddr nport, uint64_t data,
180                              unsigned int size)
181 {
182     I8257State *d = opaque;
183     int iport, ichan = 0;
184 
185     iport = (nport >> d->dshift) & 0x0f;
186     switch (iport) {
187     case 0x00:                  /* command */
188         if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
189             qemu_log_mask(LOG_UNIMP, "%s: cmd 0x%02"PRIx64" not supported\n",
190                           __func__, 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 static IsaDmaTransferMode i8257_dma_get_transfer_mode(IsaDma *obj, int nchan)
293 {
294     I8257State *d = I8257(obj);
295     return (d->regs[nchan & 3].mode >> 2) & 3;
296 }
297 
298 static bool i8257_dma_has_autoinitialization(IsaDma *obj, int nchan)
299 {
300     I8257State *d = I8257(obj);
301     return (d->regs[nchan & 3].mode >> 4) & 1;
302 }
303 
304 static void i8257_dma_hold_DREQ(IsaDma *obj, int nchan)
305 {
306     I8257State *d = I8257(obj);
307     int ichan;
308 
309     ichan = nchan & 3;
310     d->status |= 1 << (ichan + 4);
311     i8257_dma_run(d);
312 }
313 
314 static void i8257_dma_release_DREQ(IsaDma *obj, int nchan)
315 {
316     I8257State *d = I8257(obj);
317     int ichan;
318 
319     ichan = nchan & 3;
320     d->status &= ~(1 << (ichan + 4));
321     i8257_dma_run(d);
322 }
323 
324 static void i8257_channel_run(I8257State *d, int ichan)
325 {
326     int ncont = d->dshift;
327     int n;
328     I8257Regs *r = &d->regs[ichan];
329 #ifdef DEBUG_DMA
330     int dir, opmode;
331 
332     dir = (r->mode >> 5) & 1;
333     opmode = (r->mode >> 6) & 3;
334 
335     if (dir) {
336         dolog ("DMA in address decrement mode\n");
337     }
338     if (opmode != 1) {
339         dolog ("DMA not in single mode select %#x\n", opmode);
340     }
341 #endif
342 
343     n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
344                              r->now[COUNT], (r->base[COUNT] + 1) << ncont);
345     r->now[COUNT] = n;
346     ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
347     if (n == (r->base[COUNT] + 1) << ncont) {
348         ldebug("transfer done\n");
349         d->status |= (1 << ichan);
350     }
351 }
352 
353 static void i8257_dma_run(void *opaque)
354 {
355     I8257State *d = opaque;
356     int ichan;
357     int rearm = 0;
358 
359     if (d->running) {
360         rearm = 1;
361         goto out;
362     } else {
363         d->running = 1;
364     }
365 
366     for (ichan = 0; ichan < 4; ichan++) {
367         int mask;
368 
369         mask = 1 << ichan;
370 
371         if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
372             i8257_channel_run(d, ichan);
373             rearm = 1;
374         }
375     }
376 
377     d->running = 0;
378 out:
379     if (rearm) {
380         qemu_bh_schedule_idle(d->dma_bh);
381         d->dma_bh_scheduled = true;
382     }
383 }
384 
385 static void i8257_dma_register_channel(IsaDma *obj, int nchan,
386                                        IsaDmaTransferHandler transfer_handler,
387                                        void *opaque)
388 {
389     I8257State *d = I8257(obj);
390     I8257Regs *r;
391     int ichan;
392 
393     ichan = nchan & 3;
394 
395     r = d->regs + ichan;
396     r->transfer_handler = transfer_handler;
397     r->opaque = opaque;
398 }
399 
400 static int i8257_dma_read_memory(IsaDma *obj, int nchan, void *buf, int pos,
401                                  int len)
402 {
403     I8257State *d = I8257(obj);
404     I8257Regs *r = &d->regs[nchan & 3];
405     hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
406 
407     if (r->mode & 0x20) {
408         int i;
409         uint8_t *p = buf;
410 
411         cpu_physical_memory_read (addr - pos - len, buf, len);
412         /* What about 16bit transfers? */
413         for (i = 0; i < len >> 1; i++) {
414             uint8_t b = p[len - i - 1];
415             p[i] = b;
416         }
417     }
418     else
419         cpu_physical_memory_read (addr + pos, buf, len);
420 
421     return len;
422 }
423 
424 static int i8257_dma_write_memory(IsaDma *obj, int nchan, void *buf, int pos,
425                                  int len)
426 {
427     I8257State *s = I8257(obj);
428     I8257Regs *r = &s->regs[nchan & 3];
429     hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
430 
431     if (r->mode & 0x20) {
432         int i;
433         uint8_t *p = buf;
434 
435         cpu_physical_memory_write (addr - pos - len, buf, len);
436         /* What about 16bit transfers? */
437         for (i = 0; i < len; i++) {
438             uint8_t b = p[len - i - 1];
439             p[i] = b;
440         }
441     }
442     else
443         cpu_physical_memory_write (addr + pos, buf, len);
444 
445     return len;
446 }
447 
448 /* request the emulator to transfer a new DMA memory block ASAP (even
449  * if the idle bottom half would not have exited the iothread yet).
450  */
451 static void i8257_dma_schedule(IsaDma *obj)
452 {
453     I8257State *d = I8257(obj);
454     if (d->dma_bh_scheduled) {
455         qemu_notify_event();
456     }
457 }
458 
459 static void i8257_reset(DeviceState *dev)
460 {
461     I8257State *d = I8257(dev);
462     i8257_write_cont(d, (0x05 << d->dshift), 0, 1);
463 }
464 
465 static int i8257_phony_handler(void *opaque, int nchan, int dma_pos,
466                                int dma_len)
467 {
468     trace_i8257_unregistered_dma(nchan, dma_pos, dma_len);
469     return dma_pos;
470 }
471 
472 
473 static const MemoryRegionOps channel_io_ops = {
474     .read = i8257_read_chan,
475     .write = i8257_write_chan,
476     .endianness = DEVICE_NATIVE_ENDIAN,
477     .impl = {
478         .min_access_size = 1,
479         .max_access_size = 1,
480     },
481 };
482 
483 /* IOport from page_base */
484 static const MemoryRegionPortio page_portio_list[] = {
485     { 0x01, 3, 1, .write = i8257_write_page, .read = i8257_read_page, },
486     { 0x07, 1, 1, .write = i8257_write_page, .read = i8257_read_page, },
487     PORTIO_END_OF_LIST(),
488 };
489 
490 /* IOport from pageh_base */
491 static const MemoryRegionPortio pageh_portio_list[] = {
492     { 0x01, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
493     { 0x07, 3, 1, .write = i8257_write_pageh, .read = i8257_read_pageh, },
494     PORTIO_END_OF_LIST(),
495 };
496 
497 static const MemoryRegionOps cont_io_ops = {
498     .read = i8257_read_cont,
499     .write = i8257_write_cont,
500     .endianness = DEVICE_NATIVE_ENDIAN,
501     .impl = {
502         .min_access_size = 1,
503         .max_access_size = 1,
504     },
505 };
506 
507 static const VMStateDescription vmstate_i8257_regs = {
508     .name = "dma_regs",
509     .version_id = 1,
510     .minimum_version_id = 1,
511     .fields = (VMStateField[]) {
512         VMSTATE_INT32_ARRAY(now, I8257Regs, 2),
513         VMSTATE_UINT16_ARRAY(base, I8257Regs, 2),
514         VMSTATE_UINT8(mode, I8257Regs),
515         VMSTATE_UINT8(page, I8257Regs),
516         VMSTATE_UINT8(pageh, I8257Regs),
517         VMSTATE_UINT8(dack, I8257Regs),
518         VMSTATE_UINT8(eop, I8257Regs),
519         VMSTATE_END_OF_LIST()
520     }
521 };
522 
523 static int i8257_post_load(void *opaque, int version_id)
524 {
525     I8257State *d = opaque;
526     i8257_dma_run(d);
527 
528     return 0;
529 }
530 
531 static const VMStateDescription vmstate_i8257 = {
532     .name = "dma",
533     .version_id = 1,
534     .minimum_version_id = 1,
535     .post_load = i8257_post_load,
536     .fields = (VMStateField[]) {
537         VMSTATE_UINT8(command, I8257State),
538         VMSTATE_UINT8(mask, I8257State),
539         VMSTATE_UINT8(flip_flop, I8257State),
540         VMSTATE_INT32(dshift, I8257State),
541         VMSTATE_STRUCT_ARRAY(regs, I8257State, 4, 1, vmstate_i8257_regs,
542                              I8257Regs),
543         VMSTATE_END_OF_LIST()
544     }
545 };
546 
547 static void i8257_realize(DeviceState *dev, Error **errp)
548 {
549     ISADevice *isa = ISA_DEVICE(dev);
550     I8257State *d = I8257(dev);
551     int i;
552 
553     memory_region_init_io(&d->channel_io, NULL, &channel_io_ops, d,
554                           "dma-chan", 8 << d->dshift);
555     memory_region_add_subregion(isa_address_space_io(isa),
556                                 d->base, &d->channel_io);
557 
558     isa_register_portio_list(isa, &d->portio_page,
559                              d->page_base, page_portio_list, d,
560                              "dma-page");
561     if (d->pageh_base >= 0) {
562         isa_register_portio_list(isa, &d->portio_pageh,
563                                  d->pageh_base, pageh_portio_list, d,
564                                  "dma-pageh");
565     }
566 
567     memory_region_init_io(&d->cont_io, OBJECT(isa), &cont_io_ops, d,
568                           "dma-cont", 8 << d->dshift);
569     memory_region_add_subregion(isa_address_space_io(isa),
570                                 d->base + (8 << d->dshift), &d->cont_io);
571 
572     for (i = 0; i < ARRAY_SIZE(d->regs); ++i) {
573         d->regs[i].transfer_handler = i8257_phony_handler;
574     }
575 
576     d->dma_bh = qemu_bh_new(i8257_dma_run, d);
577 }
578 
579 static Property i8257_properties[] = {
580     DEFINE_PROP_INT32("base", I8257State, base, 0x00),
581     DEFINE_PROP_INT32("page-base", I8257State, page_base, 0x80),
582     DEFINE_PROP_INT32("pageh-base", I8257State, pageh_base, 0x480),
583     DEFINE_PROP_INT32("dshift", I8257State, dshift, 0),
584     DEFINE_PROP_END_OF_LIST()
585 };
586 
587 static void i8257_class_init(ObjectClass *klass, void *data)
588 {
589     DeviceClass *dc = DEVICE_CLASS(klass);
590     IsaDmaClass *idc = ISADMA_CLASS(klass);
591 
592     dc->realize = i8257_realize;
593     dc->reset = i8257_reset;
594     dc->vmsd = &vmstate_i8257;
595     dc->props = i8257_properties;
596 
597     idc->get_transfer_mode = i8257_dma_get_transfer_mode;
598     idc->has_autoinitialization = i8257_dma_has_autoinitialization;
599     idc->read_memory = i8257_dma_read_memory;
600     idc->write_memory = i8257_dma_write_memory;
601     idc->hold_DREQ = i8257_dma_hold_DREQ;
602     idc->release_DREQ = i8257_dma_release_DREQ;
603     idc->schedule = i8257_dma_schedule;
604     idc->register_channel = i8257_dma_register_channel;
605     /* Reason: needs to be wired up by isa_bus_dma() to work */
606     dc->user_creatable = false;
607 }
608 
609 static const TypeInfo i8257_info = {
610     .name = TYPE_I8257,
611     .parent = TYPE_ISA_DEVICE,
612     .instance_size = sizeof(I8257State),
613     .class_init = i8257_class_init,
614     .interfaces = (InterfaceInfo[]) {
615         { TYPE_ISADMA },
616         { }
617     }
618 };
619 
620 static void i8257_register_types(void)
621 {
622     type_register_static(&i8257_info);
623 }
624 
625 type_init(i8257_register_types)
626 
627 void i8257_dma_init(ISABus *bus, bool high_page_enable)
628 {
629     ISADevice *isa1, *isa2;
630     DeviceState *d;
631 
632     isa1 = isa_create(bus, TYPE_I8257);
633     d = DEVICE(isa1);
634     qdev_prop_set_int32(d, "base", 0x00);
635     qdev_prop_set_int32(d, "page-base", 0x80);
636     qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x480 : -1);
637     qdev_prop_set_int32(d, "dshift", 0);
638     qdev_init_nofail(d);
639 
640     isa2 = isa_create(bus, TYPE_I8257);
641     d = DEVICE(isa2);
642     qdev_prop_set_int32(d, "base", 0xc0);
643     qdev_prop_set_int32(d, "page-base", 0x88);
644     qdev_prop_set_int32(d, "pageh-base", high_page_enable ? 0x488 : -1);
645     qdev_prop_set_int32(d, "dshift", 1);
646     qdev_init_nofail(d);
647 
648     isa_bus_dma(bus, ISADMA(isa1), ISADMA(isa2));
649 }
650