diff options
author | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-04-07 22:03:44 +0000 |
---|---|---|
committer | aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162> | 2009-04-07 22:03:44 +0000 |
commit | 9ea0b7a1395e5580a7c5f5e296870fff9c130256 (patch) | |
tree | f8856e80328c5accbf9ebe5175314b3d095314aa /hw | |
parent | b09d9d4618b936f64a7d42f12858ca12ba661128 (diff) |
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
Diffstat (limited to 'hw')
-rw-r--r-- | hw/rc4030.c | 119 |
1 files changed, 70 insertions, 49 deletions
diff --git a/hw/rc4030.c b/hw/rc4030.c index c86538557d..d83f111c21 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -1,7 +1,7 @@ /* * QEMU JAZZ RC4030 chipset * - * Copyright (c) 2007-2008 Hervé Poussineau + * Copyright (c) 2007-2009 Herve Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -66,6 +66,7 @@ typedef struct dma_pagetable_entry { typedef struct rc4030State { uint32_t config; /* 0x0000: RC4030 config register */ + uint32_t revision; /* 0x0008: RC4030 Revision register */ uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ /* DMA */ @@ -74,17 +75,17 @@ typedef struct rc4030State uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */ /* cache */ + uint32_t cache_maint; /* 0x0030: Cache Maintenance */ uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */ uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */ uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */ uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */ uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ - uint32_t cache_bwin; /* 0x0060: I/O Cache Buffer Window */ + uint32_t nmi_interrupt; /* 0x0200: interrupt source */ uint32_t offset210; uint32_t nvram_protect; /* 0x0220: NV ram protect register */ - uint32_t offset238; - uint32_t rem_speed[15]; + uint32_t rem_speed[16]; uint32_t imr_jazz; /* Local bus int enable mask */ uint32_t isr_jazz; /* Local bus int source */ @@ -118,6 +119,10 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) case 0x0000: val = s->config; break; + /* Revision register */ + case 0x0008: + val = s->revision; + break; /* Invalid Address register */ case 0x0010: val = s->invalid_address_register; @@ -161,6 +166,7 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) case 0x00d0: case 0x00d8: case 0x00e0: + case 0x00e8: val = s->rem_speed[(addr - 0x0070) >> 3]; break; /* DMA channel base address */ @@ -202,7 +208,11 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) val = s->dma_regs[entry][idx]; } break; - /* Offset 0x0208 */ + /* Interrupt source */ + case 0x0200: + val = s->nmi_interrupt; + break; + /* Error type */ case 0x0208: val = 0; break; @@ -219,9 +229,9 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr) val = 0; qemu_irq_lower(s->timer_irq); break; - /* Offset 0x0238 */ + /* EISA interrupt */ case 0x0238: - val = s->offset238; + val = 7; /* FIXME: should be read from EISA controller */ break; default: 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) break; /* Cache Maintenance */ case 0x0030: - RC4030_ERROR("Cache maintenance not handled yet (val 0x%02x)\n", val); + s->cache_maint = val; break; /* I/O Cache Physical Tag */ case 0x0048: @@ -291,16 +301,11 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) break; /* I/O Cache Buffer Window */ case 0x0060: - s->cache_bwin = val; /* HACK */ if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) { - target_phys_addr_t dests[] = { 4, 0, 8, 0x10 }; - static int current = 0; - target_phys_addr_t dest = 0 + dests[current]; - uint8_t buf; - current = (current + 1) % (ARRAY_SIZE(dests)); - buf = s->cache_bwin - 1; - cpu_physical_memory_rw(dest, &buf, 1, 1); + target_phys_addr_t dest = s->cache_ptag & ~0x1; + dest += (s->cache_maint & 0x3) << 3; + cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1); } break; /* Remote Speed Registers */ @@ -319,6 +324,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) case 0x00d0: case 0x00d8: case 0x00e0: + case 0x00e8: s->rem_speed[(addr - 0x0070) >> 3] = val; break; /* DMA channel base address */ @@ -370,6 +376,9 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val) qemu_irq_lower(s->timer_irq); set_next_tick(s); break; + /* EISA interrupt */ + case 0x0238: + break; default: RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr); break; @@ -580,21 +589,23 @@ static void rc4030_reset(void *opaque) int i; s->config = 0x410; /* some boards seem to accept 0x104 too */ + s->revision = 1; s->invalid_address_register = 0; memset(s->dma_regs, 0, sizeof(s->dma_regs)); s->dma_tl_base = s->dma_tl_limit = 0; s->remote_failed_address = s->memory_failed_address = 0; + s->cache_maint = 0; s->cache_ptag = s->cache_ltag = 0; - s->cache_bmask = s->cache_bwin = 0; + s->cache_bmask = 0; s->offset210 = 0x18186; s->nvram_protect = 7; - s->offset238 = 7; for (i = 0; i < 15; i++) s->rem_speed[i] = 7; - s->imr_jazz = s->isr_jazz = 0; + s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */ + s->isr_jazz = 0; s->itr = 0; @@ -607,7 +618,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) rc4030State* s = opaque; int i, j; - if (version_id != 1) + if (version_id != 2) return -EINVAL; s->config = qemu_get_be32(f); @@ -617,15 +628,14 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) s->dma_regs[i][j] = qemu_get_be32(f); s->dma_tl_base = qemu_get_be32(f); s->dma_tl_limit = qemu_get_be32(f); + s->cache_maint = qemu_get_be32(f); s->remote_failed_address = qemu_get_be32(f); s->memory_failed_address = qemu_get_be32(f); s->cache_ptag = qemu_get_be32(f); s->cache_ltag = qemu_get_be32(f); s->cache_bmask = qemu_get_be32(f); - s->cache_bwin = qemu_get_be32(f); s->offset210 = qemu_get_be32(f); s->nvram_protect = qemu_get_be32(f); - s->offset238 = qemu_get_be32(f); for (i = 0; i < 15; i++) s->rem_speed[i] = qemu_get_be32(f); s->imr_jazz = qemu_get_be32(f); @@ -650,15 +660,14 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->dma_regs[i][j]); qemu_put_be32(f, s->dma_tl_base); qemu_put_be32(f, s->dma_tl_limit); + qemu_put_be32(f, s->cache_maint); qemu_put_be32(f, s->remote_failed_address); qemu_put_be32(f, s->memory_failed_address); qemu_put_be32(f, s->cache_ptag); qemu_put_be32(f, s->cache_ltag); qemu_put_be32(f, s->cache_bmask); - qemu_put_be32(f, s->cache_bwin); qemu_put_be32(f, s->offset210); qemu_put_be32(f, s->nvram_protect); - qemu_put_be32(f, s->offset238); for (i = 0; i < 15; i++) qemu_put_be32(f, s->rem_speed[i]); qemu_put_be32(f, s->imr_jazz); @@ -666,44 +675,28 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->itr); } -static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) +static void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; target_phys_addr_t entry_addr; - target_phys_addr_t dma_addr, phys_addr; + target_phys_addr_t phys_addr; dma_pagetable_entry entry; - int index, dev_to_mem; + int index; int ncpy, i; - s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR); - - /* Check DMA channel consistency */ - dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1; - if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) || - (is_write != dev_to_mem)) { - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; - return; - } - - if (len > s->dma_regs[n][DMA_REG_COUNT]) - len = s->dma_regs[n][DMA_REG_COUNT]; - - dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; i = 0; for (;;) { if (i == len) { - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; break; } - ncpy = DMA_PAGESIZE - (dma_addr & (DMA_PAGESIZE - 1)); + ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); if (ncpy > len - i) ncpy = len - i; /* Get DMA translation table entry */ - index = dma_addr / DMA_PAGESIZE; + index = addr / DMA_PAGESIZE; if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) { - s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; break; } 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 cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0); /* Read/write data at right place */ - phys_addr = entry.frame + (dma_addr & (DMA_PAGESIZE - 1)); + phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); i += ncpy; - dma_addr += ncpy; - s->dma_regs[n][DMA_REG_COUNT] -= ncpy; + addr += ncpy; + } +} + +static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) +{ + rc4030State *s = opaque; + target_phys_addr_t dma_addr; + int dev_to_mem; + + s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR); + + /* Check DMA channel consistency */ + dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1; + if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) || + (is_write != dev_to_mem)) { + s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR; + s->nmi_interrupt |= 1 << n; + return; } + /* Get start address and len */ + if (len > s->dma_regs[n][DMA_REG_COUNT]) + len = s->dma_regs[n][DMA_REG_COUNT]; + dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; + + /* Read/write data at right place */ + rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); + + s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; + s->dma_regs[n][DMA_REG_COUNT] -= len; + #ifdef DEBUG_RC4030_DMA { int i, j; @@ -792,7 +813,7 @@ qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, s->jazz_bus_irq = jazz_bus; qemu_register_reset(rc4030_reset, s); - register_savevm("rc4030", 0, 1, rc4030_save, rc4030_load, s); + register_savevm("rc4030", 0, 2, rc4030_save, rc4030_load, s); rc4030_reset(s); s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s); |