From patchwork Tue Jun 14 02:37:40 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: 100272 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 14575B6FB1 for ; Tue, 14 Jun 2011 14:53:04 +1000 (EST) Received: from localhost ([::1]:57703 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWLca-0007eB-Ka for incoming@patchwork.ozlabs.org; Tue, 14 Jun 2011 00:53:00 -0400 Received: from eggs.gnu.org ([140.186.70.92]:57348) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWJW9-0006va-Ix for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QWJW0-0006h0-I0 for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:12 -0400 Received: from fmmailgate02.web.de ([217.72.192.227]:57761) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QWJVz-0006gL-3D for qemu-devel@nongnu.org; Mon, 13 Jun 2011 22:38:04 -0400 Received: from smtp03.web.de ( [172.20.0.65]) by fmmailgate02.web.de (Postfix) with ESMTP id 676401A30DD0E; Tue, 14 Jun 2011 04:38:02 +0200 (CEST) Received: from [87.173.124.240] (helo=af.local) by smtp03.web.de with asmtp (WEB.DE 4.110 #2) id 1QWJVx-0000Aw-01; Tue, 14 Jun 2011 04:38:01 +0200 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= To: qemu-devel@nongnu.org Date: Tue, 14 Jun 2011 04:37:40 +0200 Message-Id: <1308019077-61957-7-git-send-email-andreas.faerber@web.de> X-Mailer: git-send-email 1.7.5.3 In-Reply-To: <1308019077-61957-6-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> MIME-Version: 1.0 X-Sender: Andreas.Faerber@web.de X-Provags-ID: V01U2FsdGVkX18knVseZ9wu5ng/MR0oCUe8dkCbRGhWO56E+Fd3 gdsi/Jn2fVJoa4hcxIffTTx8sxdw8J47RYnMcohxlKCHha+enn 8jZj50XUprXCzD+D6GOw== X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-Received-From: 217.72.192.227 Cc: =?UTF-8?q?Andreas=20F=C3=A4rber?= , =?UTF-8?q?Herv=C3=A9=20Poussineau?= , Markus Armbruster Subject: [Qemu-devel] [RFC 06/23] prep: Add i82378 PCI-to-ISA bridge emulation 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 Signed-off-by: Hervé Poussineau Inverse endianness in order to work on x86 and ppc host. Create ISA bus in this device (suggested by Markus). Cc: Markus Armbruster Signed-off-by: Andreas Färber --- Makefile.objs | 1 + default-configs/ppc-softmmu.mak | 2 + hw/i82378.c | 298 +++++++++++++++++++++++++++++++++++++++ hw/pci_ids.h | 1 + 4 files changed, 302 insertions(+), 0 deletions(-) create mode 100644 hw/i82378.c diff --git a/Makefile.objs b/Makefile.objs index b0e4c09..fb57bbf 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -210,6 +210,7 @@ hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o +hw-obj-$(CONFIG_I82378) += i82378.o # Mac shared devices hw-obj-$(CONFIG_MACIO) += macio.o hw-obj-$(CONFIG_CUDA) += cuda.o diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 1d1a7c2..df64ee6 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -14,7 +14,9 @@ CONFIG_DMA=y CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y +CONFIG_I82378=y CONFIG_MACIO=y +CONFIG_PCSPK=y CONFIG_CUDA=y CONFIG_ADB=y CONFIG_MAC_NVRAM=y diff --git a/hw/i82378.c b/hw/i82378.c new file mode 100644 index 0000000..181e441 --- /dev/null +++ b/hw/i82378.c @@ -0,0 +1,298 @@ +/* + * QEMU Intel i82378 emulation (PCI to ISA bridge) + * + * Copyright (c) 2010-2011 Herve Poussineau + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright (c) 2010 Andreas Faerber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "pci.h" +#include "pc.h" + +//#define DEBUG_I82378 + +#ifdef DEBUG_I82378 +#define DPRINTF(fmt, ...) \ +do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ +do {} while (0) +#endif + +#define BADF(fmt, ...) \ +do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0) + +#ifdef HOST_WORDS_BIGENDIAN +#define DEVICE_INVERSE_ENDIAN DEVICE_LITTLE_ENDIAN +#else +#define DEVICE_INVERSE_ENDIAN DEVICE_BIG_ENDIAN +#endif + +typedef struct I82378State { + qemu_irq out[2]; + int s_io; + int s_mem; +} I82378State; + +typedef struct PCIi82378State { + PCIDevice pci_dev; + uint32_t isa_io_base; + uint32_t isa_mem_base; + I82378State state; +} PCIi82378State; + +static inline target_phys_addr_t i82378_io_address(I82378State *state, + target_phys_addr_t addr) +{ + if (true) { + return addr & 0xFFFF; + } else { + return (addr & 0x1F) | ((addr & 0x007FFF000) >> 7); + } +} + +static void i82378_io_writeb(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "=%02x\n", __func__, addr, value); + addr = i82378_io_address(s, addr); + cpu_outb(addr, value); +} + +static void i82378_io_writew(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "=%04x\n", __func__, addr, value); + addr = i82378_io_address(s, addr); + cpu_outw(addr, value); +} + +static void i82378_io_writel(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "=%08x\n", __func__, addr, value); + addr = i82378_io_address(s, addr); + cpu_outl(addr, value); +} + +static uint32_t i82378_io_readb(void *opaque, target_phys_addr_t addr) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + addr = i82378_io_address(s, addr); + return cpu_inb(addr); +} + +static uint32_t i82378_io_readw(void *opaque, target_phys_addr_t addr) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + addr = i82378_io_address(s, addr); + return cpu_inw(addr); +} + +static uint32_t i82378_io_readl(void *opaque, target_phys_addr_t addr) +{ + I82378State *s = opaque; + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + addr = i82378_io_address(s, addr); + return cpu_inl(addr); +} + +static CPUWriteMemoryFunc * const i82378_io_write[] = { + i82378_io_writeb, + i82378_io_writew, + i82378_io_writel, +}; + +static CPUReadMemoryFunc * const i82378_io_read[] = { + i82378_io_readb, + i82378_io_readw, + i82378_io_readl, +}; + +static void i82378_mem_writeb(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + DPRINTF("%s: " TARGET_FMT_plx "=%02x\n", __func__, addr, value); + cpu_outb(addr, value); +} + +static void i82378_mem_writew(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + DPRINTF("%s: " TARGET_FMT_plx "=%04x\n", __func__, addr, value); + cpu_outw(addr, value); +} + +static void i82378_mem_writel(void *opaque, + target_phys_addr_t addr, uint32_t value) +{ + DPRINTF("%s: " TARGET_FMT_plx "=%08x\n", __func__, addr, value); + cpu_outl(addr, value); +} + +static uint32_t i82378_mem_readb(void *opaque, target_phys_addr_t addr) +{ + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + return cpu_inb(addr); +} + +static uint32_t i82378_mem_readw(void *opaque, target_phys_addr_t addr) +{ + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + return cpu_inw(addr); +} + +static uint32_t i82378_mem_readl(void *opaque, target_phys_addr_t addr) +{ + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + return cpu_inl(addr); +} + +static CPUWriteMemoryFunc * const i82378_mem_write[] = { + i82378_mem_writeb, + i82378_mem_writew, + i82378_mem_writel, +}; + +static CPUReadMemoryFunc * const i82378_mem_read[] = { + i82378_mem_readb, + i82378_mem_readw, + i82378_mem_readl, +}; + +static void i82378_init(DeviceState *dev, I82378State *s) +{ + ISADevice *pit; + + isa_bus_new(dev); + + /* This device has: + 2 82C59 (irq) + 1 82C54 (pit) + 2 82C37 (dma) + NMI + Utility Bus Support Registers + + All devices accept byte access only, except timer + */ + + /* 2 82C59 (irq) */ + qdev_init_gpio_out(dev, s->out, 2); + isa_bus_irqs(i8259_init(s->out[0])); + + /* 1 82C54 (pit) */ + pit = pit_init(0x40, 0); + + /* speaker */ + pcspk_init(pit); + + /* 2 82C37 (dma) */ + DMA_init(1, &s->out[1]); + isa_create_simple("i82374"); + + /* timer */ + isa_create_simple("mc146818rtc"); + + s->s_io = cpu_register_io_memory(i82378_io_read, + i82378_io_write, s, DEVICE_INVERSE_ENDIAN); + s->s_mem = cpu_register_io_memory(i82378_mem_read, + i82378_mem_write, s, DEVICE_INVERSE_ENDIAN); +} + +static void pci_i82378_ioport_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + I82378State *s = &DO_UPCAST(PCIi82378State, pci_dev, pci_dev)->state; + + DPRINTF("%s: %s addr=0x%" FMT_PCIBUS " size=0x%" FMT_PCIBUS "\n", + __func__, pci_dev->name, addr, size); + + cpu_register_physical_memory(addr, size, s->s_io); +} + +static void pci_i82378_mmio_map(PCIDevice *pci_dev, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + I82378State *s = &DO_UPCAST(PCIi82378State, pci_dev, pci_dev)->state; + + DPRINTF("%s: %s addr=0x%" FMT_PCIBUS " size=0x%" FMT_PCIBUS "\n", + __func__, pci_dev->name, addr, size); + + cpu_register_physical_memory(addr, size, s->s_mem); + qemu_register_coalesced_mmio(addr, size); +} + +static int pci_i82378_init(PCIDevice *pci_dev) +{ + PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, pci_dev); + I82378State *s = &pci->state; + uint8_t *pci_conf; + + pci_conf = pci_dev->config; + pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); + pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82378); + pci_set_word(pci_conf + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_set_word(pci_conf + PCI_STATUS, + PCI_STATUS_DEVSEL_MEDIUM); + pci_conf[PCI_REVISION_ID] = 0x03; + pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA); + + pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); + pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); + + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */ + + pci_register_bar(pci_dev, 0, 0x00010000, + PCI_BASE_ADDRESS_SPACE_MEMORY, pci_i82378_ioport_map); + + pci_register_bar(pci_dev, 1, 0x01000000, + PCI_BASE_ADDRESS_SPACE_MEMORY, pci_i82378_mmio_map); + + /* Make addresses read only */ + pci_set_word(pci_dev->wmask + PCI_COMMAND, + PCI_COMMAND_SPECIAL); + pci_set_long(pci_conf + PCI_BASE_ADDRESS_0 + 0 * 4, pci->isa_io_base); + pci_set_long(pci_conf + PCI_BASE_ADDRESS_0 + 1 * 4, pci->isa_mem_base); + + isa_mem_base = pci->isa_mem_base; + i82378_init(&pci_dev->qdev, s); + + return 0; +} + +static PCIDeviceInfo pci_i82378_info = { + .init = pci_i82378_init, + .qdev.name = "i82378", + .qdev.size = sizeof(PCIi82378State), + .qdev.props = (Property[]) { + DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000), + DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000), + DEFINE_PROP_END_OF_LIST() + }, +}; + +static void i82378_register_devices(void) +{ + pci_qdev_register(&pci_i82378_info); +} + +device_init(i82378_register_devices) diff --git a/hw/pci_ids.h b/hw/pci_ids.h index d9457ed..d3bef0e 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -98,6 +98,7 @@ #define PCI_DEVICE_ID_MPC8533E 0x0030 #define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 #define PCI_DEVICE_ID_INTEL_82801D 0x24CD