@@ -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
@@ -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
new file mode 100644
@@ -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)
@@ -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