Signed-off-by: Hervé Poussineau <hpous...@reactos.org> Inverse endianness in order to work on x86 and ppc host. Create ISA bus in this device (suggested by Markus).
Cc: Markus Armbruster <arm...@redhat.com> Signed-off-by: Andreas Färber <andreas.faer...@web.de> --- 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 <http://www.gnu.org/licenses/>. + */ + +#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 -- 1.7.5.3