From patchwork Tue Jun 14 02:37:56 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 100261 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BC290B6FAB for ; Tue, 14 Jun 2011 14:04:40 +1000 (EST) Received: from localhost ([::1]:50657 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWKrj-0003Ck-LI for incoming@patchwork.ozlabs.org; Tue, 14 Jun 2011 00:04:35 -0400 Received: from eggs.gnu.org ([140.186.70.92]:57415) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWJWE-0006ws-CM for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QWJWA-0006ku-5U for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:17 -0400 Received: from fmmailgate03.web.de ([217.72.192.234]:47372) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWJW8-0006k8-B0 for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:13 -0400 Received: from smtp03.web.de ( [172.20.0.65]) by fmmailgate03.web.de (Postfix) with ESMTP id 5FAF519234833; Tue, 14 Jun 2011 04:38:11 +0200 (CEST) Received: from [87.173.124.240] (helo=af.local) by smtp03.web.de with asmtp (WEB.DE 4.110 #2) id 1QWJW6-0000Aw-01; Tue, 14 Jun 2011 04:38:10 +0200 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= To: qemu-devel@nongnu.org Date: Tue, 14 Jun 2011 04:37:56 +0200 Message-Id: <1308019077-61957-23-git-send-email-andreas.faerber@web.de> X-Mailer: git-send-email 1.7.5.3 In-Reply-To: <1308019077-61957-22-git-send-email-andreas.faerber@web.de> References: <1308019077-61957-1-git-send-email-andreas.faerber@web.de> <1308019077-61957-2-git-send-email-andreas.faerber@web.de> <1308019077-61957-3-git-send-email-andreas.faerber@web.de> <1308019077-61957-4-git-send-email-andreas.faerber@web.de> <1308019077-61957-5-git-send-email-andreas.faerber@web.de> <1308019077-61957-6-git-send-email-andreas.faerber@web.de> <1308019077-61957-7-git-send-email-andreas.faerber@web.de> <1308019077-61957-8-git-send-email-andreas.faerber@web.de> <1308019077-61957-9-git-send-email-andreas.faerber@web.de> <1308019077-61957-10-git-send-email-andreas.faerber@web.de> <1308019077-61957-11-git-send-email-andreas.faerber@web.de> <1308019077-61957-12-git-send-email-andreas.faerber@web.de> <1308019077-61957-13-git-send-email-andreas.faerber@web.de> <1308019077-61957-14-git-send-email-andreas.faerber@web.de> <1308019077-61957-15-git-send-email-andreas.faerber@web.de> <1308019077-61957-16-git-send-email-andreas.faerber@web.de> <1308019077-61957-17-git-send-email-andreas.faerber@web.de> <1308019077-61957-18-git-send-email-andreas.faerber@web.de> <1308019077-61957-19-git-send-email-andreas.faerber@web.de> <1308019077-61957-20-git-send-email-andreas.faerber@web.de> <1308019077-61957-21-git-send-email-andreas.faerber@web.de> <1308019077-61957-22-git-send-email-andreas.faerber@web.de> MIME-Version: 1.0 X-Sender: Andreas.Faerber@web.de X-Provags-ID: V01U2FsdGVkX1+QvTwtX4jKDGqR+PviFTUZJtkjYMh7CHz3KO4+ pmyEMSAJRejecAJ4mbUwg1AzE+SpAoXlnUMc/ubQbeeG+jcGBw vIB5xqzxrn/tCIQ2bztA== X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-Received-From: 217.72.192.234 Cc: =?UTF-8?q?Andreas=20F=C3=A4rber?= , =?UTF-8?q?Herv=C3=A9=20Poussineau?= , Alexander Graf Subject: [Qemu-devel] [RFC 22/23] prep: qdev'ify System I/O (WIP) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org PReP defines a number of 1-byte registers Signed-off-by: Hervé Poussineau v1: * Rebased: Fix I/O port types for ppc64 compatibility. Use Little Endian for parity error register. * Drop iobase property. It was not being set to another value, ignored for reads and writes, and the spec makes no promises about register locations being en bloque. * Generalize this as System I/O rather than I/O 0x800 and integrate Special Port 0x0092. It was implementing the parity error register at 0xBFFFEFF0 anyway. * The v1.1 spec has parity read as 0x0840 rather than 0x841, so cover both. * Turn board identification into a qdev property. * Migrate remaining standard I/O ports from prep machine. * Add some VMState support. Add to 40p machine. Cc: Alexander Graf Signed-off-by: Andreas Färber --- Makefile.target | 1 + hw/ppc_prep.c | 165 ++++++-------------------- hw/ppc_prep.h | 24 ++++ hw/prep_systemio.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 399 insertions(+), 126 deletions(-) create mode 100644 hw/ppc_prep.h create mode 100644 hw/prep_systemio.c diff --git a/Makefile.target b/Makefile.target index b1a0f6d..b67b1f7 100644 --- a/Makefile.target +++ b/Makefile.target @@ -242,6 +242,7 @@ obj-ppc-y = ppc.o obj-ppc-y += vga.o # PREP target obj-ppc-y += i8259.o mc146818rtc.o +obj-ppc-y += prep_systemio.o obj-ppc-y += ppc_prep.o # OldWorld PowerMac obj-ppc-y += ppc_oldworld.o diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 4759a03..6ae1635 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "ppc_prep.h" #include "hw.h" #include "nvram.h" #include "pc.h" @@ -258,117 +259,55 @@ static CPUReadMemoryFunc * const PPC_XCSR_read[] = { #endif /* Fake super-io ports for PREP platform (Intel 82378ZB) */ -typedef struct sysctrl_t { - qemu_irq reset_irq; - M48t59State *nvram; - uint8_t state; - uint8_t syscontrol; - uint8_t fake_io[2]; - int contiguous_map; - int endian; -} sysctrl_t; - -enum { - STATE_HARDFILE = 0x01, -}; - -static sysctrl_t *sysctrl; - static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) { - sysctrl_t *sysctrl = opaque; + uint8_t *fake_io = opaque; PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, val); - sysctrl->fake_io[addr - 0x0398] = val; + fake_io[addr - 0x0398] = val; } static uint32_t PREP_io_read (void *opaque, uint32_t addr) { - sysctrl_t *sysctrl = opaque; + uint8_t *fake_io = opaque; PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, - sysctrl->fake_io[addr - 0x0398]); - return sysctrl->fake_io[addr - 0x0398]; + fake_io[addr - 0x0398]); + return fake_io[addr - 0x0398]; } +#if 0 static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { - sysctrl_t *sysctrl = opaque; - PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, val); switch (addr) { - case 0x0092: - /* Special port 92 */ - /* Check soft reset asked */ - if (val & 0x01) { - qemu_irq_raise(sysctrl->reset_irq); - } else { - qemu_irq_lower(sysctrl->reset_irq); - } - /* Check LE mode */ - if (val & 0x02) { - sysctrl->endian = 1; - } else { - sysctrl->endian = 0; - } - break; - case 0x0800: - /* Motorola CPU configuration register : read-only */ - break; - case 0x0802: - /* Motorola base module feature register : read-only */ - break; - case 0x0803: - /* Motorola base module status register : read-only */ - break; - case 0x0808: - /* Hardfile light register */ - if (val & 1) - sysctrl->state |= STATE_HARDFILE; - else - sysctrl->state &= ~STATE_HARDFILE; - break; case 0x0810: /* Password protect 1 register */ - if (sysctrl->nvram != NULL) - m48t59_toggle_lock(sysctrl->nvram, 1); + // TODO m48t59_toggle_lock(sysctrl->nvram, 1); break; case 0x0812: /* Password protect 2 register */ - if (sysctrl->nvram != NULL) - m48t59_toggle_lock(sysctrl->nvram, 2); + // TODO m48t59_toggle_lock(sysctrl->nvram, 2); break; case 0x0814: /* L2 invalidate register */ // tlb_flush(first_cpu, 1); break; - case 0x081C: - /* system control register */ - sysctrl->syscontrol = val & 0x0F; - break; - case 0x0850: - /* I/O map type register */ - sysctrl->contiguous_map = val & 0x01; - break; default: printf("ERROR: unaffected IO port write: %04" PRIx32 " => %02" PRIx32"\n", addr, val); break; } } +#endif static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) { - sysctrl_t *sysctrl = opaque; uint32_t retval = 0xFF; switch (addr) { - case 0x0092: - /* Special port 92 */ - retval = 0x00; - break; case 0x0800: /* Motorola CPU configuration register */ retval = 0xEF; /* MPC750 */ @@ -377,44 +316,14 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) /* Motorola Base module feature register */ retval = 0xAD; /* No ESCC, PMC slot neither ethernet */ break; - case 0x0803: - /* Motorola base module status register */ - retval = 0xE0; /* Standard MPC750 */ - break; - case 0x080C: - /* Equipment present register: - * no L2 cache - * no upgrade processor - * no cards in PCI slots - * SCSI fuse is bad - */ - retval = 0x3C; - break; case 0x0810: /* Motorola base module extended feature register */ retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */ break; - case 0x0814: - /* L2 invalidate: don't care */ - break; - case 0x0818: - /* Keylock */ - retval = 0x00; - break; - case 0x081C: - /* system control register - * 7 - 6 / 1 - 0: L2 cache enable - */ - retval = sysctrl->syscontrol; - break; case 0x0823: /* */ retval = 0x03; /* no L2 cache */ break; - case 0x0850: - /* I/O map type register */ - retval = sysctrl->contiguous_map; - break; default: printf("ERROR: unaffected IO port: %04" PRIx32 " read\n", addr); break; @@ -425,10 +334,10 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) return retval; } -static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl, +static inline target_phys_addr_t prep_IO_address(ISAPrepSystemIo800State *state, target_phys_addr_t addr) { - if (sysctrl->contiguous_map == 0) { + if (prep_is_iomap_contiguous(state)) { /* 64 KB contiguous space for IOs */ addr &= 0xFFFF; } else { @@ -442,18 +351,18 @@ static inline target_phys_addr_t prep_IO_address(sysctrl_t *sysctrl, static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); cpu_outb(addr, value); } static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; uint32_t ret; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); ret = cpu_inb(addr); return ret; @@ -462,19 +371,19 @@ static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value); cpu_outw(addr, value); } static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; uint32_t ret; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); ret = cpu_inw(addr); PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret); @@ -484,19 +393,19 @@ static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value); cpu_outl(addr, value); } static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) { - sysctrl_t *sysctrl = opaque; + ISAPrepSystemIo800State *dev = opaque; uint32_t ret; - addr = prep_IO_address(sysctrl, addr); + addr = prep_IO_address(dev, addr); ret = cpu_inl(addr); PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret); @@ -566,6 +475,8 @@ static void ppc_prep_init (ram_addr_t ram_size, { CPUState *env = NULL; char *filename; + ISADevice *systemio; + uint8_t *fake_io; nvram_t nvram; M48t59State *m48t59; int PPC_io_memory; @@ -580,8 +491,6 @@ static void ppc_prep_init (ram_addr_t ram_size, DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; - sysctrl = qemu_mallocz(sizeof(sysctrl_t)); - linux_boot = (kernel_filename != NULL); /* init CPUs */ @@ -668,10 +577,11 @@ static void ppc_prep_init (ram_addr_t ram_size, /* Hmm, prep has no pci-isa bridge ??? */ isa_bus_new(NULL); isa_bus_irqs(i8259); + systemio = isa_create_simple("prep-systemio800"); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ PPC_io_memory = cpu_register_io_memory(PPC_prep_io_read, - PPC_prep_io_write, sysctrl, + PPC_prep_io_write, systemio, DEVICE_LITTLE_ENDIAN); cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); @@ -719,14 +629,13 @@ static void ppc_prep_init (ram_addr_t ram_size, register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); /* Register fake IO ports for PREP */ - sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; - register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); - register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); + fake_io = qemu_mallocz(2); + register_ioport_read(0x398, 2, 1, &PREP_io_read, fake_io); + register_ioport_write(0x398, 2, 1, &PREP_io_write, fake_io); /* System control ports */ - register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); - register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); - register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); - register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); + register_ioport_read(0x0800, 2/*3*/, 1, &PREP_io_800_readb, systemio); + //register_ioport_read(0x0810, 1, 1, PREP_io_800_readb, systemio); + register_ioport_read(0x0823, 1, 1, PREP_io_800_readb, systemio); /* PCI intack location */ PPC_io_memory = cpu_register_io_memory(PPC_intack_read, PPC_intack_write, NULL, @@ -746,7 +655,6 @@ static void ppc_prep_init (ram_addr_t ram_size, m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59); if (m48t59 == NULL) return; - sysctrl->nvram = m48t59; /* Initialise NVRAM */ nvram.opaque = m48t59; @@ -834,6 +742,11 @@ static void ibm_40p_init(ram_addr_t ram_size, qdev_connect_gpio_out(&pci->qdev, 0, env->irq_inputs[PPC6xx_INPUT_INT]); qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq); + /* PReP System I/O */ + isa = isa_create("prep-systemio800"); + qdev_prop_set_uint8(&isa->qdev, "board-identification", 0xfc); + qdev_init_nofail(&isa->qdev); + /* Super I/O (parallel + serial ports) */ isa = isa_create("isa-pc87312"); qdev_prop_set_chr(&isa->qdev, "parallel", parallel_hds[0]); diff --git a/hw/ppc_prep.h b/hw/ppc_prep.h new file mode 100644 index 0000000..ad74c29 --- /dev/null +++ b/hw/ppc_prep.h @@ -0,0 +1,24 @@ +#ifndef PPC_PREP_H +#define PPC_PREP_H + +#include "isa.h" + + +typedef struct PrepIo800State { + uint8_t system_control; /* 0x081c */ + uint8_t iomap_type; /* 0x0850 */ + uint32_t mem_parity_error_address; + qemu_irq softreset_irq; +} PrepIo800State; + +typedef struct ISAPrepSystemIo800State { + ISADevice dev; + uint8_t board_identification; /* 0x0852 */ + PrepIo800State state; +} ISAPrepSystemIo800State; + + +int prep_is_iomap_contiguous(ISAPrepSystemIo800State *s); + + +#endif diff --git a/hw/prep_systemio.c b/hw/prep_systemio.c new file mode 100644 index 0000000..edfcfcc --- /dev/null +++ b/hw/prep_systemio.c @@ -0,0 +1,335 @@ +/* + * QEMU PReP System I/O emulation + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright (c) 2010 Herve Poussineau + * Copyright (c) 2010-2011 Andreas Faerber + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "ppc_prep.h" + +//#define DEBUG_PREPIO + +#ifdef DEBUG_PREPIO +#define DPRINTF(fmt, ...) \ +do { \ + fprintf(stderr, "io800: " fmt , ## __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(fmt, ...) \ +do {} while (0) +#endif +#define BADF(fmt, ...) \ +do { fprintf(stderr, "io800 ERROR: " fmt , ## __VA_ARGS__); } while (0) + +/* Bit as defined in PowerPC Reference Plaform v1.1, sect. 6.1.5, p. 132 */ +#define BIT(n) (1 << (7 - (n))) + + +/* PORT 0092 -- Special Port 92 (Read/Write) */ + +enum { + PORT0092_SOFTRESET = BIT(7), + PORT0092_LE_MODE = BIT(6), +}; + +static void prep_port0092_write(void *opaque, uint32_t addr, uint32_t val) +{ + PrepIo800State *s = opaque; + + if ((val & PORT0092_SOFTRESET) != 0) { + qemu_irq_raise(s->softreset_irq); + } else { + qemu_irq_lower(s->softreset_irq); + } + + if ((val & PORT0092_LE_MODE) != 0) { + /* XXX Not supported yet */ + } else { + /* Nothing to do */ + } +} + +static uint32_t prep_port0092_read(void *opaque, uint32_t addr) +{ + /* XXX LE mode unsupported */ + return 0; +} + +/* SIMM ID (32/8 MB) */ + +static uint32_t prep_port0803_read(void *opaque, uint32_t addr) +{ + return 3; // XXX or 0xe0 +} + +/* SIMM Presence */ + +static uint32_t prep_port0804_read(void *opaque, uint32_t addr) +{ + return 0; +} + +/* PORT 0808 -- Hardfile Light Register (Write Only) */ + +enum { + PORT0808_HARDFILE_LIGHT_ON = BIT(7), +}; + +static void prep_port0808_write(void *opaque, uint32_t addr, uint32_t val) +{ +} + +/* PORT 080C -- Equipment Present Register (Read Only) */ + +enum { + PORT080C_L2_CACHE_ABSENT = BIT(7), + PORT080C_UPGRADE_PROCESSOR_ABSENT = BIT(6), + PORT080C_L2_CACHE_256KB_OR_ABSENT = BIT(5), + PORT080C_L2_CACHE_COPYBACK_OR_ABSENT = BIT(4), + PORT080C_PCI_SLOT1_CARD_ABSENT = BIT(3), + PORT080C_PCI_SLOT2_CARD_ABSENT = BIT(2), + PORT080C_SCSI_FUSE_OK = BIT(1), +}; + +static uint32_t prep_port080c_read(void *opaque, uint32_t addr) +{ + /* no L2 cache + * no upgrade processor + * no cards in PCI slots + * SCSI fuse is bad + */ + return PORT080C_L2_CACHE_ABSENT | + PORT080C_L2_CACHE_256KB_OR_ABSENT | + PORT080C_L2_CACHE_COPYBACK_OR_ABSENT | + PORT080C_UPGRADE_PROCESSOR_ABSENT | + PORT080C_PCI_SLOT1_CARD_ABSENT | + PORT080C_PCI_SLOT2_CARD_ABSENT; +} + +/* PORT 0810 -- Password Protect 1 Register (Write Only) */ + +/* reset by port 0x4D in the SIO */ +static void prep_port0810_write(void *opaque, uint32_t addr, uint32_t val) +{ +} + +/* PORT 0812 -- Password Protect 2 Register (Write Only) */ + +/* reset by port 0x4D in the SIO */ +static void prep_port0812_write(void *opaque, uint32_t addr, uint32_t val) +{ +} + +/* PORT 0814 -- L2 Invalidate Register (Write Only) */ + +static void prep_port0814_write(void *opaque, uint32_t addr, uint32_t val) +{ +} + +/* PORT 0818 -- Reserved for Keylock (Read Only) */ + +enum { + PORT0818_KEYLOCK_SIGNAL_HIGH = BIT(7), +}; + +static uint32_t prep_port0818_read(void *opaque, uint32_t addr) +{ + return 0; +} + +/* PORT 081C -- System Control Register (Read/Write) */ + +enum { + PORT081C_FLOPPY_MOTOR_INHIBIT = BIT(3), + PORT081C_MASK_TEA = BIT(2), + PORT081C_L2_UPDATE_INHIBIT = BIT(1), + PORT081C_L2_CACHEMISS_INHIBIT = BIT(0), +}; + +static void prep_port081c_write(void *opaque, uint32_t addr, uint32_t val) +{ + PrepIo800State *s = opaque; + s->system_control = val; +} + +static uint32_t prep_port081c_read(void *opaque, uint32_t addr) +{ + PrepIo800State *s = opaque; + return s->system_control; +} + +/* Memory Controller Size Programming Register */ + +static void prep_port0820_write(void *opaque, uint32_t addr, uint32_t val) +{ + PrepIo800State *s = opaque; + if (val == 0xe3) { + s->mem_parity_error_address = 1; /* HACK */ + } +} + +/* Read Memory Parity Error */ + +static uint32_t prep_port0840_read(void *opaque, uint32_t addr) +{ + PrepIo800State *s = opaque; + return s->mem_parity_error_address != 0 ? 1 : 0; +} + +/* System Board Identification */ + +static uint32_t prep_port0852_read(void *opaque, uint32_t addr) +{ + ISAPrepSystemIo800State *s = opaque; + return s->board_identification; +} + +/* PORT 0850 -- I/O Map Type Register (Read/Write) */ + +enum { + PORT0850_IOMAP_NONCONTIGUOUS = BIT(7), +}; + +static uint32_t prep_port0850_read(void *opaque, uint32_t addr) +{ + PrepIo800State *s = opaque; + return s->iomap_type; +} + +static void prep_port0850_write(void *opaque, uint32_t addr, uint32_t val) +{ + PrepIo800State *s = opaque; + s->iomap_type = val; +} + +int prep_is_iomap_contiguous(ISAPrepSystemIo800State *s) +{ + return (s->state.iomap_type & PORT0850_IOMAP_NONCONTIGUOUS) == 0; +} + + +static uint32_t ppc_parity_error_readl(void *opaque, target_phys_addr_t addr) +{ + PrepIo800State* s = opaque; + uint32_t val = s->mem_parity_error_address; + + DPRINTF("%s: read 0x%08x at [" TARGET_FMT_plx "]\n", __func__, val, addr); + + return val; +} + +static CPUReadMemoryFunc * const ppc_parity_error_read[] = { + NULL, + NULL, + ppc_parity_error_readl, +}; + +static CPUWriteMemoryFunc * const ppc_parity_error_write[] = { + NULL, + NULL, + NULL, +}; + +static void prep_register_ioport(uint16_t start, int length, + IOPortReadFunc *read_func, + IOPortWriteFunc *write_func, + void *opaque) +{ + if (read_func != NULL) { + register_ioport_read(start, length, 1, read_func, opaque); + } + if (write_func != NULL) { + register_ioport_write(start, length, 1, write_func, opaque); + } +} + +static int prep_systemio_isa_init(ISADevice *dev) +{ + ISAPrepSystemIo800State *isa = DO_UPCAST(ISAPrepSystemIo800State, dev, dev); + PrepIo800State *s = &isa->state; + int io; + + s->iomap_type = 0; /* contiguous mode CHECKME 0x1? */ + s->softreset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; + + prep_register_ioport(0x0092, 1, prep_port0092_read, + prep_port0092_write, s); + + prep_register_ioport(0x0803, 1, prep_port0803_read, NULL, s); + prep_register_ioport(0x0804, 1, prep_port0804_read, NULL, s); + prep_register_ioport(0x0808, 4, NULL, + prep_port0808_write, s); + prep_register_ioport(0x080c, 4, prep_port080c_read, NULL, s); + prep_register_ioport(0x0810, 2, NULL, + prep_port0810_write, s); + prep_register_ioport(0x0812, 2, NULL, + prep_port0812_write, s); + prep_register_ioport(0x0814, 4, NULL, + prep_port0814_write, s); + prep_register_ioport(0x0818, 1, prep_port0818_read, NULL, s); + prep_register_ioport(0x081c, 4, prep_port081c_read, + prep_port081c_write, s); + prep_register_ioport(0x0820, 1, NULL, + prep_port0820_write, s); + prep_register_ioport(0x0840, 2, prep_port0840_read, NULL, s); + /* Reference Implementation supposedly uses 0x0850 - 0x0853 */ + prep_register_ioport(0x0850, 2, prep_port0850_read, + prep_port0850_write, s); + prep_register_ioport(0x0852, 1, prep_port0852_read, NULL, isa); + + io = cpu_register_io_memory(ppc_parity_error_read, + ppc_parity_error_write, s, + DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(0xBFFFEFF0, 0x4, io); + return 0; +} + +static const VMStateDescription vmstate_prep_systemio = { + .name = "prep_systemio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(state.system_control, ISAPrepSystemIo800State), + VMSTATE_UINT8(state.iomap_type, ISAPrepSystemIo800State), + VMSTATE_END_OF_LIST() + }, +}; + +static ISADeviceInfo prep_systemio800_info = { + .init = prep_systemio_isa_init, + .qdev.name = "prep-systemio800", + .qdev.size = sizeof(ISAPrepSystemIo800State), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT8("board-identification", ISAPrepSystemIo800State, + board_identification, 0), + DEFINE_PROP_END_OF_LIST() + }, + .qdev.vmsd = &vmstate_prep_systemio, + .qdev.no_user = 1, +}; + +static void prep_systemio_register_devices(void) +{ + isa_qdev_register(&prep_systemio800_info); +} + +device_init(prep_systemio_register_devices)