Commit 9ea0b7a1395e5580a7c5f5e296870fff9c130256
1 parent
b09d9d46
rc4030 registers improvements
Attached patch documents some registers and simplifies one hack. Signed-off-by: Hervé Poussineau <hpoussin@reactos.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7030 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
70 additions
and
49 deletions
hw/rc4030.c
1 | 1 | /* |
2 | 2 | * QEMU JAZZ RC4030 chipset |
3 | 3 | * |
4 | - * Copyright (c) 2007-2008 Hervé Poussineau | |
4 | + * Copyright (c) 2007-2009 Herve Poussineau | |
5 | 5 | * |
6 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | 7 | * of this software and associated documentation files (the "Software"), to deal |
... | ... | @@ -66,6 +66,7 @@ typedef struct dma_pagetable_entry { |
66 | 66 | typedef struct rc4030State |
67 | 67 | { |
68 | 68 | uint32_t config; /* 0x0000: RC4030 config register */ |
69 | + uint32_t revision; /* 0x0008: RC4030 Revision register */ | |
69 | 70 | uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ |
70 | 71 | |
71 | 72 | /* DMA */ |
... | ... | @@ -74,17 +75,17 @@ typedef struct rc4030State |
74 | 75 | uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */ |
75 | 76 | |
76 | 77 | /* cache */ |
78 | + uint32_t cache_maint; /* 0x0030: Cache Maintenance */ | |
77 | 79 | uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */ |
78 | 80 | uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */ |
79 | 81 | uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */ |
80 | 82 | uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */ |
81 | 83 | uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ |
82 | - uint32_t cache_bwin; /* 0x0060: I/O Cache Buffer Window */ | |
83 | 84 | |
85 | + uint32_t nmi_interrupt; /* 0x0200: interrupt source */ | |
84 | 86 | uint32_t offset210; |
85 | 87 | uint32_t nvram_protect; /* 0x0220: NV ram protect register */ |
86 | - uint32_t offset238; | |
87 | - uint32_t rem_speed[15]; | |
88 | + uint32_t rem_speed[16]; | |
88 | 89 | uint32_t imr_jazz; /* Local bus int enable mask */ |
89 | 90 | uint32_t isr_jazz; /* Local bus int source */ |
90 | 91 | |
... | ... | @@ -118,6 +119,10 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) |
118 | 119 | case 0x0000: |
119 | 120 | val = s->config; |
120 | 121 | break; |
122 | + /* Revision register */ | |
123 | + case 0x0008: | |
124 | + val = s->revision; | |
125 | + break; | |
121 | 126 | /* Invalid Address register */ |
122 | 127 | case 0x0010: |
123 | 128 | val = s->invalid_address_register; |
... | ... | @@ -161,6 +166,7 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) |
161 | 166 | case 0x00d0: |
162 | 167 | case 0x00d8: |
163 | 168 | case 0x00e0: |
169 | + case 0x00e8: | |
164 | 170 | val = s->rem_speed[(addr - 0x0070) >> 3]; |
165 | 171 | break; |
166 | 172 | /* DMA channel base address */ |
... | ... | @@ -202,7 +208,11 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) |
202 | 208 | val = s->dma_regs[entry][idx]; |
203 | 209 | } |
204 | 210 | break; |
205 | - /* Offset 0x0208 */ | |
211 | + /* Interrupt source */ | |
212 | + case 0x0200: | |
213 | + val = s->nmi_interrupt; | |
214 | + break; | |
215 | + /* Error type */ | |
206 | 216 | case 0x0208: |
207 | 217 | val = 0; |
208 | 218 | break; |
... | ... | @@ -219,9 +229,9 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) |
219 | 229 | val = 0; |
220 | 230 | qemu_irq_lower(s->timer_irq); |
221 | 231 | break; |
222 | - /* Offset 0x0238 */ | |
232 | + /* EISA interrupt */ | |
223 | 233 | case 0x0238: |
224 | - val = s->offset238; | |
234 | + val = 7; /* FIXME: should be read from EISA controller */ | |
225 | 235 | break; |
226 | 236 | default: |
227 | 237 | RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr); |
... | ... | @@ -275,7 +285,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
275 | 285 | break; |
276 | 286 | /* Cache Maintenance */ |
277 | 287 | case 0x0030: |
278 | - RC4030_ERROR("Cache maintenance not handled yet (val 0x%02x)\n", val); | |
288 | + s->cache_maint = val; | |
279 | 289 | break; |
280 | 290 | /* I/O Cache Physical Tag */ |
281 | 291 | case 0x0048: |
... | ... | @@ -291,16 +301,11 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
291 | 301 | break; |
292 | 302 | /* I/O Cache Buffer Window */ |
293 | 303 | case 0x0060: |
294 | - s->cache_bwin = val; | |
295 | 304 | /* HACK */ |
296 | 305 | if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { |
297 | - target_phys_addr_t dests[] = { 4, 0, 8, 0x10 }; | |
298 | - static int current = 0; | |
299 | - target_phys_addr_t dest = 0 + dests[current]; | |
300 | - uint8_t buf; | |
301 | - current = (current + 1) % (ARRAY_SIZE(dests)); | |
302 | - buf = s->cache_bwin - 1; | |
303 | - cpu_physical_memory_rw(dest, &buf, 1, 1); | |
306 | + target_phys_addr_t dest = s->cache_ptag & ~0x1; | |
307 | + dest += (s->cache_maint & 0x3) << 3; | |
308 | + cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1); | |
304 | 309 | } |
305 | 310 | break; |
306 | 311 | /* Remote Speed Registers */ |
... | ... | @@ -319,6 +324,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
319 | 324 | case 0x00d0: |
320 | 325 | case 0x00d8: |
321 | 326 | case 0x00e0: |
327 | + case 0x00e8: | |
322 | 328 | s->rem_speed[(addr - 0x0070) >> 3] = val; |
323 | 329 | break; |
324 | 330 | /* DMA channel base address */ |
... | ... | @@ -370,6 +376,9 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
370 | 376 | qemu_irq_lower(s->timer_irq); |
371 | 377 | set_next_tick(s); |
372 | 378 | break; |
379 | + /* EISA interrupt */ | |
380 | + case 0x0238: | |
381 | + break; | |
373 | 382 | default: |
374 | 383 | RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr); |
375 | 384 | break; |
... | ... | @@ -580,21 +589,23 @@ static void rc4030_reset(void *opaque) |
580 | 589 | int i; |
581 | 590 | |
582 | 591 | s->config = 0x410; /* some boards seem to accept 0x104 too */ |
592 | + s->revision = 1; | |
583 | 593 | s->invalid_address_register = 0; |
584 | 594 | |
585 | 595 | memset(s->dma_regs, 0, sizeof(s->dma_regs)); |
586 | 596 | s->dma_tl_base = s->dma_tl_limit = 0; |
587 | 597 | |
588 | 598 | s->remote_failed_address = s->memory_failed_address = 0; |
599 | + s->cache_maint = 0; | |
589 | 600 | s->cache_ptag = s->cache_ltag = 0; |
590 | - s->cache_bmask = s->cache_bwin = 0; | |
601 | + s->cache_bmask = 0; | |
591 | 602 | |
592 | 603 | s->offset210 = 0x18186; |
593 | 604 | s->nvram_protect = 7; |
594 | - s->offset238 = 7; | |
595 | 605 | for (i = 0; i < 15; i++) |
596 | 606 | s->rem_speed[i] = 7; |
597 | - s->imr_jazz = s->isr_jazz = 0; | |
607 | + s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */ | |
608 | + s->isr_jazz = 0; | |
598 | 609 | |
599 | 610 | s->itr = 0; |
600 | 611 | |
... | ... | @@ -607,7 +618,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) |
607 | 618 | rc4030State* s = opaque; |
608 | 619 | int i, j; |
609 | 620 | |
610 | - if (version_id != 1) | |
621 | + if (version_id != 2) | |
611 | 622 | return -EINVAL; |
612 | 623 | |
613 | 624 | s->config = qemu_get_be32(f); |
... | ... | @@ -617,15 +628,14 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) |
617 | 628 | s->dma_regs[i][j] = qemu_get_be32(f); |
618 | 629 | s->dma_tl_base = qemu_get_be32(f); |
619 | 630 | s->dma_tl_limit = qemu_get_be32(f); |
631 | + s->cache_maint = qemu_get_be32(f); | |
620 | 632 | s->remote_failed_address = qemu_get_be32(f); |
621 | 633 | s->memory_failed_address = qemu_get_be32(f); |
622 | 634 | s->cache_ptag = qemu_get_be32(f); |
623 | 635 | s->cache_ltag = qemu_get_be32(f); |
624 | 636 | s->cache_bmask = qemu_get_be32(f); |
625 | - s->cache_bwin = qemu_get_be32(f); | |
626 | 637 | s->offset210 = qemu_get_be32(f); |
627 | 638 | s->nvram_protect = qemu_get_be32(f); |
628 | - s->offset238 = qemu_get_be32(f); | |
629 | 639 | for (i = 0; i < 15; i++) |
630 | 640 | s->rem_speed[i] = qemu_get_be32(f); |
631 | 641 | s->imr_jazz = qemu_get_be32(f); |
... | ... | @@ -650,15 +660,14 @@ static void rc4030_save(QEMUFile *f, void *opaque) |
650 | 660 | qemu_put_be32(f, s->dma_regs[i][j]); |
651 | 661 | qemu_put_be32(f, s->dma_tl_base); |
652 | 662 | qemu_put_be32(f, s->dma_tl_limit); |
663 | + qemu_put_be32(f, s->cache_maint); | |
653 | 664 | qemu_put_be32(f, s->remote_failed_address); |
654 | 665 | qemu_put_be32(f, s->memory_failed_address); |
655 | 666 | qemu_put_be32(f, s->cache_ptag); |
656 | 667 | qemu_put_be32(f, s->cache_ltag); |
657 | 668 | qemu_put_be32(f, s->cache_bmask); |
658 | - qemu_put_be32(f, s->cache_bwin); | |
659 | 669 | qemu_put_be32(f, s->offset210); |
660 | 670 | qemu_put_be32(f, s->nvram_protect); |
661 | - qemu_put_be32(f, s->offset238); | |
662 | 671 | for (i = 0; i < 15; i++) |
663 | 672 | qemu_put_be32(f, s->rem_speed[i]); |
664 | 673 | qemu_put_be32(f, s->imr_jazz); |
... | ... | @@ -666,44 +675,28 @@ static void rc4030_save(QEMUFile *f, void *opaque) |
666 | 675 | qemu_put_be32(f, s->itr); |
667 | 676 | } |
668 | 677 | |
669 | -static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) | |
678 | +static void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write) | |
670 | 679 | { |
671 | 680 | rc4030State *s = opaque; |
672 | 681 | target_phys_addr_t entry_addr; |
673 | - target_phys_addr_t dma_addr, phys_addr; | |
682 | + target_phys_addr_t phys_addr; | |
674 | 683 | dma_pagetable_entry entry; |
675 | - int index, dev_to_mem; | |
684 | + int index; | |
676 | 685 | int ncpy, i; |
677 | 686 | |
678 | - s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR); | |
679 | - | |
680 | - /* Check DMA channel consistency */ | |
681 | - dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1; | |
682 | - if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) || | |
683 | - (is_write != dev_to_mem)) { | |
684 | - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; | |
685 | - return; | |
686 | - } | |
687 | - | |
688 | - if (len > s->dma_regs[n][DMA_REG_COUNT]) | |
689 | - len = s->dma_regs[n][DMA_REG_COUNT]; | |
690 | - | |
691 | - dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; | |
692 | 687 | i = 0; |
693 | 688 | for (;;) { |
694 | 689 | if (i == len) { |
695 | - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; | |
696 | 690 | break; |
697 | 691 | } |
698 | 692 | |
699 | - ncpy = DMA_PAGESIZE - (dma_addr & (DMA_PAGESIZE - 1)); | |
693 | + ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); | |
700 | 694 | if (ncpy > len - i) |
701 | 695 | ncpy = len - i; |
702 | 696 | |
703 | 697 | /* Get DMA translation table entry */ |
704 | - index = dma_addr / DMA_PAGESIZE; | |
698 | + index = addr / DMA_PAGESIZE; | |
705 | 699 | if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) { |
706 | - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; | |
707 | 700 | break; |
708 | 701 | } |
709 | 702 | entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); |
... | ... | @@ -712,14 +705,42 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri |
712 | 705 | cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0); |
713 | 706 | |
714 | 707 | /* Read/write data at right place */ |
715 | - phys_addr = entry.frame + (dma_addr & (DMA_PAGESIZE - 1)); | |
708 | + phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); | |
716 | 709 | cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); |
717 | 710 | |
718 | 711 | i += ncpy; |
719 | - dma_addr += ncpy; | |
720 | - s->dma_regs[n][DMA_REG_COUNT] -= ncpy; | |
712 | + addr += ncpy; | |
713 | + } | |
714 | +} | |
715 | + | |
716 | +static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) | |
717 | +{ | |
718 | + rc4030State *s = opaque; | |
719 | + target_phys_addr_t dma_addr; | |
720 | + int dev_to_mem; | |
721 | + | |
722 | + s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR); | |
723 | + | |
724 | + /* Check DMA channel consistency */ | |
725 | + dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1; | |
726 | + if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) || | |
727 | + (is_write != dev_to_mem)) { | |
728 | + s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; | |
729 | + s->nmi_interrupt |= 1 << n; | |
730 | + return; | |
721 | 731 | } |
722 | 732 | |
733 | + /* Get start address and len */ | |
734 | + if (len > s->dma_regs[n][DMA_REG_COUNT]) | |
735 | + len = s->dma_regs[n][DMA_REG_COUNT]; | |
736 | + dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; | |
737 | + | |
738 | + /* Read/write data at right place */ | |
739 | + rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); | |
740 | + | |
741 | + s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; | |
742 | + s->dma_regs[n][DMA_REG_COUNT] -= len; | |
743 | + | |
723 | 744 | #ifdef DEBUG_RC4030_DMA |
724 | 745 | { |
725 | 746 | int i, j; |
... | ... | @@ -792,7 +813,7 @@ qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, |
792 | 813 | s->jazz_bus_irq = jazz_bus; |
793 | 814 | |
794 | 815 | qemu_register_reset(rc4030_reset, s); |
795 | - register_savevm("rc4030", 0, 1, rc4030_save, rc4030_load, s); | |
816 | + register_savevm("rc4030", 0, 2, rc4030_save, rc4030_load, s); | |
796 | 817 | rc4030_reset(s); |
797 | 818 | |
798 | 819 | s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s); | ... | ... |