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); | ... | ... |