diff options
author | Peter Maydell | 2014-06-06 00:05:07 +0200 |
---|---|---|
committer | Peter Maydell | 2014-06-06 00:05:07 +0200 |
commit | 50809c8b9288a9bfe1fdec926b7ef985608a7ea6 (patch) | |
tree | a3110c29be93ca8ffa24b46c53bf046773913764 /hw | |
parent | Merge remote-tracking branch 'remotes/mdroth/qga-pull-2014-06-05' into staging (diff) | |
parent | apb: implement IOMMU translation for PCI host bridge (diff) | |
download | qemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.tar.gz qemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.tar.xz qemu-50809c8b9288a9bfe1fdec926b7ef985608a7ea6.zip |
Merge remote-tracking branch 'remotes/mcayland/qemu-sparc' into staging
* remotes/mcayland/qemu-sparc:
apb: implement IOMMU translation for PCI host bridge
apb: handle reading/writing of IOMMU control registers
apb: fix IOMMU register sizes
apb: Move IOMMU registers into a separate IOMMUState struct
tcx: move initialisation from realizefn to initfn
tcx: move initialisation from SysBusDevice class to TCX class realizefn
cg3: add extra check to prevent CG3 register array overflow
cg3: move initialisation from realizefn to initfn
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/display/cg3.c | 27 | ||||
-rw-r--r-- | hw/display/tcx.c | 64 | ||||
-rw-r--r-- | hw/pci-host/apb.c | 288 | ||||
-rw-r--r-- | hw/sparc/sun4m.c | 10 |
4 files changed, 336 insertions, 53 deletions
diff --git a/hw/display/cg3.c b/hw/display/cg3.c index f5a8299e5e..65ef7a7fe6 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -177,7 +177,7 @@ static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size) /* monitor ID 6, board type = 1 (color) */ val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR; break; - case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE: + case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1: val = s->regs[addr - 0x10]; break; default: @@ -247,7 +247,7 @@ static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val, qemu_irq_lower(s->irq); } break; - case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE: + case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE - 1: s->regs[addr - 0x10] = val; break; default: @@ -274,6 +274,20 @@ static const GraphicHwOps cg3_ops = { .gfx_update = cg3_update_display, }; +static void cg3_initfn(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + CG3State *s = CG3(obj); + + memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); + memory_region_set_readonly(&s->rom, true); + sysbus_init_mmio(sbd, &s->rom); + + memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", + CG3_REG_SIZE); + sysbus_init_mmio(sbd, &s->reg); +} + static void cg3_realizefn(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); @@ -282,11 +296,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) char *fcode_filename; /* FCode ROM */ - memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE); vmstate_register_ram_global(&s->rom); - memory_region_set_readonly(&s->rom, true); - sysbus_init_mmio(sbd, &s->rom); - fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE); if (fcode_filename) { ret = load_image_targphys(fcode_filename, s->prom_addr, @@ -296,10 +306,6 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) } } - memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg", - CG3_REG_SIZE); - sysbus_init_mmio(sbd, &s->reg); - memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size); vmstate_register_ram_global(&s->vram_mem); sysbus_init_mmio(sbd, &s->vram_mem); @@ -374,6 +380,7 @@ static const TypeInfo cg3_info = { .name = TYPE_CG3, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CG3State), + .instance_init = cg3_initfn, .class_init = cg3_class_init, }; diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 2551b677aa..28c742cc24 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -530,8 +530,36 @@ static const GraphicHwOps tcx24_ops = { .gfx_update = tcx24_update_display, }; -static int tcx_init1(SysBusDevice *dev) +static void tcx_initfn(Object *obj) { + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + TCXState *s = TCX(obj); + + memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE); + memory_region_set_readonly(&s->rom, true); + sysbus_init_mmio(sbd, &s->rom); + + /* DAC */ + memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, + "tcx.dac", TCX_DAC_NREGS); + sysbus_init_mmio(sbd, &s->dac); + + /* TEC (dummy) */ + memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, + "tcx.tec", TCX_TEC_NREGS); + sysbus_init_mmio(sbd, &s->tec); + + /* THC: NetBSD writes here even with 8-bit display: dummy */ + memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", + TCX_THC_NREGS_24); + sysbus_init_mmio(sbd, &s->thc24); + + return; +} + +static void tcx_realizefn(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); TCXState *s = TCX(dev); ram_addr_t vram_offset = 0; int size, ret; @@ -544,18 +572,13 @@ static int tcx_init1(SysBusDevice *dev) vram_base = memory_region_get_ram_ptr(&s->vram_mem); /* FCode ROM */ - memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE); vmstate_register_ram_global(&s->rom); - memory_region_set_readonly(&s->rom, true); - sysbus_init_mmio(dev, &s->rom); - fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, TCX_ROM_FILE); if (fcode_filename) { ret = load_image_targphys(fcode_filename, s->prom_addr, FCODE_MAX_ROM_SIZE); if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { - fprintf(stderr, "tcx: could not load prom '%s'\n", TCX_ROM_FILE); - return -1; + error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); } } @@ -564,24 +587,10 @@ static int tcx_init1(SysBusDevice *dev) size = s->vram_size; memory_region_init_alias(&s->vram_8bit, OBJECT(s), "tcx.vram.8bit", &s->vram_mem, vram_offset, size); - sysbus_init_mmio(dev, &s->vram_8bit); + sysbus_init_mmio(sbd, &s->vram_8bit); vram_offset += size; vram_base += size; - /* DAC */ - memory_region_init_io(&s->dac, OBJECT(s), &tcx_dac_ops, s, - "tcx.dac", TCX_DAC_NREGS); - sysbus_init_mmio(dev, &s->dac); - - /* TEC (dummy) */ - memory_region_init_io(&s->tec, OBJECT(s), &dummy_ops, s, - "tcx.tec", TCX_TEC_NREGS); - sysbus_init_mmio(dev, &s->tec); - /* THC: NetBSD writes here even with 8-bit display: dummy */ - memory_region_init_io(&s->thc24, OBJECT(s), &dummy_ops, s, "tcx.thc24", - TCX_THC_NREGS_24); - sysbus_init_mmio(dev, &s->thc24); - if (s->depth == 24) { /* 24-bit plane */ size = s->vram_size * 4; @@ -589,7 +598,7 @@ static int tcx_init1(SysBusDevice *dev) s->vram24_offset = vram_offset; memory_region_init_alias(&s->vram_24bit, OBJECT(s), "tcx.vram.24bit", &s->vram_mem, vram_offset, size); - sysbus_init_mmio(dev, &s->vram_24bit); + sysbus_init_mmio(sbd, &s->vram_24bit); vram_offset += size; vram_base += size; @@ -599,20 +608,19 @@ static int tcx_init1(SysBusDevice *dev) s->cplane_offset = vram_offset; memory_region_init_alias(&s->vram_cplane, OBJECT(s), "tcx.vram.cplane", &s->vram_mem, vram_offset, size); - sysbus_init_mmio(dev, &s->vram_cplane); + sysbus_init_mmio(sbd, &s->vram_cplane); s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); } else { /* THC 8 bit (dummy) */ memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8", TCX_THC_NREGS_8); - sysbus_init_mmio(dev, &s->thc8); + sysbus_init_mmio(sbd, &s->thc8); s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); } qemu_console_resize(s->con, s->width, s->height); - return 0; } static Property tcx_properties[] = { @@ -627,9 +635,8 @@ static Property tcx_properties[] = { static void tcx_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = tcx_init1; + dc->realize = tcx_realizefn; dc->reset = tcx_reset; dc->vmsd = &vmstate_tcx; dc->props = tcx_properties; @@ -639,6 +646,7 @@ static const TypeInfo tcx_info = { .name = TYPE_TCX, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TCXState), + .instance_init = tcx_initfn, .class_init = tcx_class_init, }; diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 252caefda7..1497008258 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -46,6 +46,16 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) #define APB_DPRINTF(fmt, ...) #endif +/* debug IOMMU */ +//#define DEBUG_IOMMU + +#ifdef DEBUG_IOMMU +#define IOMMU_DPRINTF(fmt, ...) \ +do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) +#else +#define IOMMU_DPRINTF(fmt, ...) +#endif + /* * Chipset docs: * PBM: "UltraSPARC IIi User's Manual", @@ -70,6 +80,51 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) #define MAX_IVEC 0x40 #define NO_IRQ_REQUEST (MAX_IVEC + 1) +#define IOMMU_PAGE_SIZE_8K (1ULL << 13) +#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) +#define IOMMU_PAGE_SIZE_64K (1ULL << 16) +#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1)) + +#define IOMMU_NREGS 3 + +#define IOMMU_CTRL 0x0 +#define IOMMU_CTRL_TBW_SIZE (1ULL << 2) +#define IOMMU_CTRL_MMU_EN (1ULL) + +#define IOMMU_CTRL_TSB_SHIFT 16 + +#define IOMMU_BASE 0x8 + +#define IOMMU_TTE_DATA_V (1ULL << 63) +#define IOMMU_TTE_DATA_SIZE (1ULL << 61) +#define IOMMU_TTE_DATA_W (1ULL << 1) + +#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000 +#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000 + +#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL + +#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL + +typedef struct IOMMUState { + AddressSpace iommu_as; + MemoryRegion iommu; + + uint64_t regs[IOMMU_NREGS]; +} IOMMUState; + #define TYPE_APB "pbm" #define APB_DEVICE(obj) \ @@ -83,7 +138,7 @@ typedef struct APBState { MemoryRegion pci_mmio; MemoryRegion pci_ioport; uint64_t pci_irq_in; - uint32_t iommu[4]; + IOMMUState iommu; uint32_t pci_control[16]; uint32_t pci_irq_map[8]; uint32_t obio_irq_map[32]; @@ -141,10 +196,217 @@ static inline void pbm_clear_request(APBState *s, unsigned int irq_num) s->irq_request = NO_IRQ_REQUEST; } +static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + IOMMUState *is = opaque; + + return &is->iommu_as; +} + +static IOMMUTLBEntry pbm_translate_iommu(MemoryRegion *iommu, hwaddr addr) +{ + IOMMUState *is = container_of(iommu, IOMMUState, iommu); + hwaddr baseaddr, offset; + uint64_t tte; + uint32_t tsbsize; + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = 0, + .translated_addr = 0, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE, + }; + + if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) { + /* IOMMU disabled, passthrough using standard 8K page */ + ret.iova = addr & IOMMU_PAGE_MASK_8K; + ret.translated_addr = addr; + ret.addr_mask = IOMMU_PAGE_MASK_8K; + ret.perm = IOMMU_RW; + + return ret; + } + + baseaddr = is->regs[IOMMU_BASE >> 3]; + tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7; + + if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) { + /* 64K */ + switch (tsbsize) { + case 0: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13; + break; + case 1: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13; + break; + case 2: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13; + break; + case 3: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13; + break; + case 4: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13; + break; + case 5: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13; + break; + default: + /* Not implemented, error */ + return ret; + } + } else { + /* 8K */ + switch (tsbsize) { + case 0: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10; + break; + case 1: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10; + break; + case 2: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10; + break; + case 3: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10; + break; + case 4: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10; + break; + case 5: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10; + break; + case 6: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10; + break; + case 7: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10; + break; + } + } + + tte = ldq_be_phys(&address_space_memory, baseaddr + offset); + + if (!(tte & IOMMU_TTE_DATA_V)) { + /* Invalid mapping */ + return ret; + } + + if (tte & IOMMU_TTE_DATA_W) { + /* Writeable */ + ret.perm = IOMMU_RW; + } else { + ret.perm = IOMMU_RO; + } + + /* Extract phys */ + if (tte & IOMMU_TTE_DATA_SIZE) { + /* 64K */ + ret.iova = addr & IOMMU_PAGE_MASK_64K; + ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K; + ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1); + } else { + /* 8K */ + ret.iova = addr & IOMMU_PAGE_MASK_8K; + ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K; + ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1); + } + + return ret; +} + +static MemoryRegionIOMMUOps pbm_iommu_ops = { + .translate = pbm_translate_iommu, +}; + +static void iommu_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + IOMMUState *is = opaque; + + IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64 + " size: %d\n", addr, val, size); + + switch (addr) { + case IOMMU_CTRL: + if (size == 4) { + is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL; + is->regs[IOMMU_CTRL >> 3] |= val << 32; + } else { + is->regs[IOMMU_CTRL] = val; + } + break; + case IOMMU_CTRL + 0x4: + is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL; + is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL; + break; + case IOMMU_BASE: + if (size == 4) { + is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL; + is->regs[IOMMU_BASE >> 3] |= val << 32; + } else { + is->regs[IOMMU_BASE] = val; + } + break; + case IOMMU_BASE + 0x4: + is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL; + is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL; + break; + default: + qemu_log_mask(LOG_UNIMP, + "apb iommu: Unimplemented register write " + "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n", + addr, size, val); + break; + } +} + +static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size) +{ + IOMMUState *is = opaque; + uint64_t val; + + switch (addr) { + case IOMMU_CTRL: + if (size == 4) { + val = is->regs[IOMMU_CTRL >> 3] >> 32; + } else { + val = is->regs[IOMMU_CTRL >> 3]; + } + break; + case IOMMU_CTRL + 0x4: + val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL; + break; + case IOMMU_BASE: + if (size == 4) { + val = is->regs[IOMMU_BASE >> 3] >> 32; + } else { + val = is->regs[IOMMU_BASE >> 3]; + } + break; + case IOMMU_BASE + 0x4: + val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL; + break; + default: + qemu_log_mask(LOG_UNIMP, + "apb iommu: Unimplemented register read " + "reg 0x%" HWADDR_PRIx " size 0x%x\n", + addr, size); + val = 0; + break; + } + + IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64 + " size: %d\n", addr, val, size); + + return val; +} + static void apb_config_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; + IOMMUState *is = &s->iommu; APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val); @@ -152,10 +414,8 @@ static void apb_config_writel (void *opaque, hwaddr addr, case 0x30 ... 0x4f: /* DMA error registers */ /* XXX: not implemented yet */ break; - case 0x200 ... 0x20b: /* IOMMU */ - s->iommu[(addr & 0xf) >> 2] = val; - break; - case 0x20c ... 0x3ff: /* IOMMU flush */ + case 0x200 ... 0x217: /* IOMMU */ + iommu_config_write(is, (addr & 0xf), val, size); break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { @@ -228,6 +488,7 @@ static uint64_t apb_config_readl (void *opaque, hwaddr addr, unsigned size) { APBState *s = opaque; + IOMMUState *is = &s->iommu; uint32_t val; switch (addr & 0xffff) { @@ -235,11 +496,8 @@ static uint64_t apb_config_readl (void *opaque, val = 0; /* XXX: not implemented yet */ break; - case 0x200 ... 0x20b: /* IOMMU */ - val = s->iommu[(addr & 0xf) >> 2]; - break; - case 0x20c ... 0x3ff: /* IOMMU flush */ - val = 0; + case 0x200 ... 0x217: /* IOMMU */ + val = iommu_config_read(is, (addr & 0xf), size); break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { @@ -390,6 +648,7 @@ PCIBus *pci_apb_init(hwaddr special_base, SysBusDevice *s; PCIHostState *phb; APBState *d; + IOMMUState *is; PCIDevice *pci_dev; PCIBridge *br; @@ -420,6 +679,15 @@ PCIBus *pci_apb_init(hwaddr special_base, pci_create_simple(phb->bus, 0, "pbm-pci"); + /* APB IOMMU */ + is = &d->iommu; + memset(is, 0, sizeof(IOMMUState)); + + memory_region_init_iommu(&is->iommu, OBJECT(dev), &pbm_iommu_ops, + "iommu-apb", UINT64_MAX); + address_space_init(&is->iommu_as, &is->iommu, "pbm-as"); + pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); + /* APB secondary busses */ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, "pbm-bridge"); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 4e793c2760..67e3663bfd 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -543,14 +543,14 @@ static void tcx_init(hwaddr addr, int vram_size, int width, s = SYS_BUS_DEVICE(dev); /* FCode ROM */ sysbus_mmio_map(s, 0, addr); - /* 8-bit plane */ - sysbus_mmio_map(s, 1, addr + 0x00800000ULL); /* DAC */ - sysbus_mmio_map(s, 2, addr + 0x00200000ULL); + sysbus_mmio_map(s, 1, addr + 0x00200000ULL); /* TEC (dummy) */ - sysbus_mmio_map(s, 3, addr + 0x00700000ULL); + sysbus_mmio_map(s, 2, addr + 0x00700000ULL); /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */ - sysbus_mmio_map(s, 4, addr + 0x00301000ULL); + sysbus_mmio_map(s, 3, addr + 0x00301000ULL); + /* 8-bit plane */ + sysbus_mmio_map(s, 4, addr + 0x00800000ULL); if (depth == 24) { /* 24-bit plane */ sysbus_mmio_map(s, 5, addr + 0x02000000ULL); |