summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi.c5
-rw-r--r--hw/apb_pci.c232
-rw-r--r--hw/grackle_pci.c156
-rw-r--r--hw/ide.c4
-rw-r--r--hw/pc.c9
-rw-r--r--hw/pci.c1422
-rw-r--r--hw/pci_host.h93
-rw-r--r--hw/piix_pci.c419
-rw-r--r--hw/ppc_chrp.c14
-rw-r--r--hw/prep_pci.c167
-rw-r--r--hw/sun4m.c5
-rw-r--r--hw/sun4u.c2
-rw-r--r--hw/unin_pci.c261
-rw-r--r--hw/usb-uhci.c5
-rw-r--r--hw/usb.h2
-rw-r--r--hw/versatile_pci.c119
-rw-r--r--hw/versatilepb.c206
17 files changed, 1698 insertions, 1423 deletions
diff --git a/hw/acpi.c b/hw/acpi.c
index 3ffdfdddbf..8fb054428d 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -220,7 +220,7 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
/* XXX: we still add it to the PIIX3 and we count on the fact that
OSes are smart enough to accept this strange configuration */
-void piix4_pm_init(PCIBus *bus)
+void piix4_pm_init(PCIBus *bus, int devfn)
{
PIIX4PMState *s;
uint8_t *pci_conf;
@@ -228,8 +228,7 @@ void piix4_pm_init(PCIBus *bus)
s = (PIIX4PMState *)pci_register_device(bus,
"PM", sizeof(PIIX4PMState),
- ((PCIDevice *)piix3_state)->devfn + 3,
- NULL, NULL);
+ devfn, NULL, NULL);
pci_conf = s->dev.config;
pci_conf[0x00] = 0x86;
pci_conf[0x01] = 0x80;
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
new file mode 100644
index 0000000000..02e9824b39
--- /dev/null
+++ b/hw/apb_pci.c
@@ -0,0 +1,232 @@
+/*
+ * QEMU Ultrasparc APB PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState APBState;
+
+static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ APBState *s = opaque;
+ int i;
+
+ for (i = 11; i < 32; i++) {
+ if ((val & (1 << i)) != 0)
+ break;
+ }
+ s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
+}
+
+static uint32_t pci_apb_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ APBState *s = opaque;
+ uint32_t val;
+ int devfn;
+
+ devfn = (s->config_reg >> 8) & 0xFF;
+ val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_apb_config_write[] = {
+ &pci_apb_config_writel,
+ &pci_apb_config_writel,
+ &pci_apb_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_apb_config_read[] = {
+ &pci_apb_config_readl,
+ &pci_apb_config_readl,
+ &pci_apb_config_readl,
+};
+
+static void apb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ //PCIBus *s = opaque;
+
+ switch (addr & 0x3f) {
+ case 0x00: // Control/Status
+ case 0x10: // AFSR
+ case 0x18: // AFAR
+ case 0x20: // Diagnostic
+ case 0x28: // Target address space
+ // XXX
+ default:
+ break;
+ }
+}
+
+static uint32_t apb_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ //PCIBus *s = opaque;
+ uint32_t val;
+
+ switch (addr & 0x3f) {
+ case 0x00: // Control/Status
+ case 0x10: // AFSR
+ case 0x18: // AFAR
+ case 0x20: // Diagnostic
+ case 0x28: // Target address space
+ // XXX
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static CPUWriteMemoryFunc *apb_config_write[] = {
+ &apb_config_writel,
+ &apb_config_writel,
+ &apb_config_writel,
+};
+
+static CPUReadMemoryFunc *apb_config_read[] = {
+ &apb_config_readl,
+ &apb_config_readl,
+ &apb_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_apb_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_apb_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outb(NULL, addr & 0xffff, val);
+}
+
+static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outw(NULL, addr & 0xffff, val);
+}
+
+static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ cpu_outl(NULL, addr & 0xffff, val);
+}
+
+static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inb(NULL, addr & 0xffff);
+ return val;
+}
+
+static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inw(NULL, addr & 0xffff);
+ return val;
+}
+
+static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+
+ val = cpu_inl(NULL, addr & 0xffff);
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
+ &pci_apb_iowriteb,
+ &pci_apb_iowritew,
+ &pci_apb_iowritel,
+};
+
+static CPUReadMemoryFunc *pci_apb_ioread[] = {
+ &pci_apb_ioreadb,
+ &pci_apb_ioreadw,
+ &pci_apb_ioreadl,
+};
+
+/* ??? This is probably wrong. */
+static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
+ void *pic)
+{
+ APBState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
+
+ s = qemu_mallocz(sizeof(APBState));
+ /* Ultrasparc APB main bus */
+ s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
+ pci_apb_config_write, s);
+ apb_config = cpu_register_io_memory(0, apb_config_read,
+ apb_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
+ pci_apb_write, s);
+ pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
+ pci_apb_iowrite, s);
+
+ cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
+ cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
+ cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
+ cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
+
+ d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
+ -1, NULL, NULL);
+ d->config[0x00] = 0x8e; // vendor_id : Sun
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x00; // device_id
+ d->config[0x03] = 0xa0;
+ d->config[0x04] = 0x06; // command = bus master, pci mem
+ d->config[0x05] = 0x00;
+ d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
+ d->config[0x07] = 0x03; // status = medium devsel
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x00; // programming i/f
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ return s->bus;
+}
+
+
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
new file mode 100644
index 0000000000..e3cbceb49a
--- /dev/null
+++ b/hw/grackle_pci.c
@@ -0,0 +1,156 @@
+/*
+ * QEMU Grackle (heathrow PPC) PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState GrackleState;
+
+static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ GrackleState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ s->config_reg = val;
+}
+
+static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
+{
+ GrackleState *s = opaque;
+ uint32_t val;
+
+ val = s->config_reg;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
+ &pci_grackle_config_writel,
+ &pci_grackle_config_writel,
+ &pci_grackle_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_grackle_config_read[] = {
+ &pci_grackle_config_readl,
+ &pci_grackle_config_readl,
+ &pci_grackle_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_grackle_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_grackle_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+/* XXX: we do not simulate the hardware - we rely on the BIOS to
+ set correctly for irq line field */
+static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_grackle_init(uint32_t base, void *pic)
+{
+ GrackleState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data;
+
+ s = qemu_mallocz(sizeof(GrackleState));
+ s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
+ pci_grackle_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
+ pci_grackle_write, s);
+ cpu_register_physical_memory(base, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
+ d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
+ 0, NULL, NULL);
+ d->config[0x00] = 0x57; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x02; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x01;
+ d->config[0x0a] = 0x00; // class_sub = host
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x00; // header_type
+
+ d->config[0x18] = 0x00; // primary_bus
+ d->config[0x19] = 0x01; // secondary_bus
+ d->config[0x1a] = 0x00; // subordinate_bus
+ d->config[0x1c] = 0x00;
+ d->config[0x1d] = 0x00;
+
+ d->config[0x20] = 0x00; // memory_base
+ d->config[0x21] = 0x00;
+ d->config[0x22] = 0x01; // memory_limit
+ d->config[0x23] = 0x00;
+
+ d->config[0x24] = 0x00; // prefetchable_memory_base
+ d->config[0x25] = 0x00;
+ d->config[0x26] = 0x00; // prefetchable_memory_limit
+ d->config[0x27] = 0x00;
+
+#if 0
+ /* PCI2PCI bridge same values as PearPC - check this */
+ d->config[0x00] = 0x11; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x26; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x02; // revision
+ d->config[0x0a] = 0x04; // class_sub = pci2pci
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x01; // header_type
+
+ d->config[0x18] = 0x0; // primary_bus
+ d->config[0x19] = 0x1; // secondary_bus
+ d->config[0x1a] = 0x1; // subordinate_bus
+ d->config[0x1c] = 0x10; // io_base
+ d->config[0x1d] = 0x20; // io_limit
+
+ d->config[0x20] = 0x80; // memory_base
+ d->config[0x21] = 0x80;
+ d->config[0x22] = 0x90; // memory_limit
+ d->config[0x23] = 0x80;
+
+ d->config[0x24] = 0x00; // prefetchable_memory_base
+ d->config[0x25] = 0x84;
+ d->config[0x26] = 0x00; // prefetchable_memory_limit
+ d->config[0x27] = 0x85;
+#endif
+ return s->bus;
+}
+
diff --git a/hw/ide.c b/hw/ide.c
index 64b026d7f3..ed63573628 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -2490,7 +2490,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
{
PCIIDEState *d;
uint8_t *pci_conf;
@@ -2498,7 +2498,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
/* register a function 1 of PIIX3 */
d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
sizeof(PCIIDEState),
- ((PCIDevice *)piix3_state)->devfn + 1,
+ devfn,
NULL, NULL);
d->type = IDE_TYPE_PIIX3;
diff --git a/hw/pc.c b/hw/pc.c
index b9bfd83a57..642af5e2b5 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -611,6 +611,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
+ int piix3_devfn;
CPUState *env;
NICInfo *nd;
@@ -741,7 +742,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
if (pci_enabled) {
pci_bus = i440fx_init();
- piix3_init(pci_bus);
+ piix3_devfn = piix3_init(pci_bus);
} else {
pci_bus = NULL;
}
@@ -813,7 +814,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, bs_table);
+ pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
} else {
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
@@ -832,12 +833,12 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
cmos_init(ram_size, boot_device, bs_table);
if (pci_enabled && usb_enabled) {
- usb_uhci_init(pci_bus, usb_root_ports);
+ usb_uhci_init(pci_bus, usb_root_ports, piix3_devfn + 2);
usb_attach(usb_root_ports[0], vm_usb_hub);
}
if (pci_enabled && acpi_enabled) {
- piix4_pm_init(pci_bus);
+ piix4_pm_init(pci_bus, piix3_devfn + 3);
}
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
diff --git a/hw/pci.c b/hw/pci.c
index 30342d44e6..a287648da1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -25,25 +25,10 @@
//#define DEBUG_PCI
-#define PCI_VENDOR_ID 0x00 /* 16 bits */
-#define PCI_DEVICE_ID 0x02 /* 16 bits */
-#define PCI_COMMAND 0x04 /* 16 bits */
-#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
-#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
-#define PCI_CLASS_DEVICE 0x0a /* Device class */
-#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
-#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
-#define PCI_MIN_GNT 0x3e /* 8 bits */
-#define PCI_MAX_LAT 0x3f /* 8 bits */
-
-/* just used for simpler irq handling. */
-#define PCI_DEVICES_MAX 64
-#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
-
struct PCIBus {
int bus_num;
int devfn_min;
- void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level);
+ pci_set_irq_fn set_irq;
uint32_t config_reg; /* XXX: suppress */
/* low level pic */
SetIRQFunc *low_set_irq;
@@ -53,17 +38,24 @@ struct PCIBus {
target_phys_addr_t pci_mem_base;
static int pci_irq_index;
-static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
static PCIBus *first_bus;
-static PCIBus *pci_register_bus(void)
+PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min)
{
PCIBus *bus;
bus = qemu_mallocz(sizeof(PCIBus));
+ bus->set_irq = set_irq;
+ bus->irq_opaque = pic;
+ bus->devfn_min = devfn_min;
first_bus = bus;
return bus;
}
+int pci_bus_num(PCIBus *s)
+{
+ return s->bus_num;
+}
+
void generic_pci_save(QEMUFile* f, void *opaque)
{
PCIDevice* s=(PCIDevice*)opaque;
@@ -141,16 +133,9 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num,
*(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type);
}
-static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- s->config_reg = val;
-}
-
-static uint32_t pci_addr_readl(void* opaque, uint32_t addr)
+target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
{
- PCIBus *s = opaque;
- return s->config_reg;
+ return addr + pci_mem_base;
}
static void pci_update_mappings(PCIDevice *d)
@@ -218,7 +203,7 @@ static void pci_update_mappings(PCIDevice *d)
isa_unassign_ioport(r->addr, r->size);
}
} else {
- cpu_register_physical_memory(r->addr + pci_mem_base,
+ cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
r->size,
IO_MEM_UNASSIGNED);
}
@@ -346,8 +331,7 @@ void pci_default_write_config(PCIDevice *d,
}
}
-static void pci_data_write(void *opaque, uint32_t addr,
- uint32_t val, int len)
+void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
{
PCIBus *s = opaque;
PCIDevice *pci_dev;
@@ -355,18 +339,15 @@ static void pci_data_write(void *opaque, uint32_t addr,
#if defined(DEBUG_PCI) && 0
printf("pci_data_write: addr=%08x val=%08x len=%d\n",
- s->config_reg, val, len);
+ addr, val, len);
#endif
- if (!(s->config_reg & (1 << 31))) {
- return;
- }
- bus_num = (s->config_reg >> 16) & 0xff;
+ bus_num = (addr >> 16) & 0xff;
if (bus_num != 0)
return;
- pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+ pci_dev = s->devices[(addr >> 8) & 0xff];
if (!pci_dev)
return;
- config_addr = (s->config_reg & 0xfc) | (addr & 3);
+ config_addr = addr & 0xff;
#if defined(DEBUG_PCI)
printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
pci_dev->name, config_addr, val, len);
@@ -374,20 +355,17 @@ static void pci_data_write(void *opaque, uint32_t addr,
pci_dev->config_write(pci_dev, config_addr, val, len);
}
-static uint32_t pci_data_read(void *opaque, uint32_t addr,
- int len)
+uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
{
PCIBus *s = opaque;
PCIDevice *pci_dev;
int config_addr, bus_num;
uint32_t val;
- if (!(s->config_reg & (1 << 31)))
- goto fail;
- bus_num = (s->config_reg >> 16) & 0xff;
+ bus_num = (addr >> 16) & 0xff;
if (bus_num != 0)
goto fail;
- pci_dev = s->devices[(s->config_reg >> 8) & 0xff];
+ pci_dev = s->devices[(addr >> 8) & 0xff];
if (!pci_dev) {
fail:
switch(len) {
@@ -404,7 +382,7 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr,
}
goto the_end;
}
- config_addr = (s->config_reg & 0xfc) | (addr & 3);
+ config_addr = addr & 0xff;
val = pci_dev->config_read(pci_dev, config_addr, len);
#if defined(DEBUG_PCI)
printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
@@ -413,1133 +391,11 @@ static uint32_t pci_data_read(void *opaque, uint32_t addr,
the_end:
#if defined(DEBUG_PCI) && 0
printf("pci_data_read: addr=%08x val=%08x len=%d\n",
- s->config_reg, val, len);
-#endif
- return val;
-}
-
-static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 1);
-}
-
-static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 2);
-}
-
-static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- pci_data_write(opaque, addr, val, 4);
-}
-
-static uint32_t pci_data_readb(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 1);
-}
-
-static uint32_t pci_data_readw(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 2);
-}
-
-static uint32_t pci_data_readl(void* opaque, uint32_t addr)
-{
- return pci_data_read(opaque, addr, 4);
-}
-
-/* i440FX PCI bridge */
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level);
-
-PCIBus *i440fx_init(void)
-{
- PCIBus *s;
- PCIDevice *d;
-
- s = pci_register_bus();
- s->set_irq = piix3_set_irq;
-
- register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
- d = pci_register_device(s, "i440FX", sizeof(PCIDevice), 0,
- NULL, NULL);
-
- d->config[0x00] = 0x86; // vendor_id
- d->config[0x01] = 0x80;
- d->config[0x02] = 0x37; // device_id
- d->config[0x03] = 0x12;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x00; // class_sub = host2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
- return s;
-}
-
-/* PIIX3 PCI to ISA bridge */
-
-typedef struct PIIX3State {
- PCIDevice dev;
-} PIIX3State;
-
-PIIX3State *piix3_state;
-
-/* return the global irq number corresponding to a given device irq
- pin. We could also use the bus number to have a more precise
- mapping. */
-static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
-{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (irq_num + slot_addend) & 3;
-}
-
-static inline int get_pci_irq_level(int irq_num)
-{
- int pic_level;
-#if (PCI_IRQ_WORDS == 2)
- pic_level = ((pci_irq_levels[irq_num][0] |
- pci_irq_levels[irq_num][1]) != 0);
-#else
- {
- int i;
- pic_level = 0;
- for(i = 0; i < PCI_IRQ_WORDS; i++) {
- if (pci_irq_levels[irq_num][i]) {
- pic_level = 1;
- break;
- }
- }
- }
-#endif
- return pic_level;
-}
-
-static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level)
-{
- int irq_index, shift, pic_irq, pic_level;
- uint32_t *p;
-
- irq_num = pci_slot_get_pirq(pci_dev, irq_num);
- irq_index = pci_dev->irq_index;
- p = &pci_irq_levels[irq_num][irq_index >> 5];
- shift = (irq_index & 0x1f);
- *p = (*p & ~(1 << shift)) | (level << shift);
-
- /* now we change the pic irq level according to the piix irq mappings */
- /* XXX: optimize */
- pic_irq = piix3_state->dev.config[0x60 + irq_num];
- if (pic_irq < 16) {
- /* the pic level is the logical OR of all the PCI irqs mapped
- to it */
- pic_level = 0;
- if (pic_irq == piix3_state->dev.config[0x60])
- pic_level |= get_pci_irq_level(0);
- if (pic_irq == piix3_state->dev.config[0x61])
- pic_level |= get_pci_irq_level(1);
- if (pic_irq == piix3_state->dev.config[0x62])
- pic_level |= get_pci_irq_level(2);
- if (pic_irq == piix3_state->dev.config[0x63])
- pic_level |= get_pci_irq_level(3);
- pic_set_irq(pic_irq, pic_level);
- }
-}
-
-static void piix3_reset(PIIX3State *d)
-{
- uint8_t *pci_conf = d->dev.config;
-
- pci_conf[0x04] = 0x07; // master, memory and I/O
- pci_conf[0x05] = 0x00;
- pci_conf[0x06] = 0x00;
- pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
- pci_conf[0x4c] = 0x4d;
- pci_conf[0x4e] = 0x03;
- pci_conf[0x4f] = 0x00;
- pci_conf[0x60] = 0x80;
- pci_conf[0x69] = 0x02;
- pci_conf[0x70] = 0x80;
- pci_conf[0x76] = 0x0c;
- pci_conf[0x77] = 0x0c;
- pci_conf[0x78] = 0x02;
- pci_conf[0x79] = 0x00;
- pci_conf[0x80] = 0x00;
- pci_conf[0x82] = 0x00;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa0] = 0x08;
- pci_conf[0xa2] = 0x00;
- pci_conf[0xa3] = 0x00;
- pci_conf[0xa4] = 0x00;
- pci_conf[0xa5] = 0x00;
- pci_conf[0xa6] = 0x00;
- pci_conf[0xa7] = 0x00;
- pci_conf[0xa8] = 0x0f;
- pci_conf[0xaa] = 0x00;
- pci_conf[0xab] = 0x00;
- pci_conf[0xac] = 0x00;
- pci_conf[0xae] = 0x00;
-}
-
-void piix3_init(PCIBus *bus)
-{
- PIIX3State *d;
- uint8_t *pci_conf;
-
- d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State),
- -1, NULL, NULL);
- register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
-
- piix3_state = d;
- pci_conf = d->dev.config;
-
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- pci_conf[0x03] = 0x70;
- pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
- pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
- pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
-
- piix3_reset(d);
-}
-
-/* PREP pci init */
-
-static inline void set_config(PCIBus *s, target_phys_addr_t addr)
-{
- int devfn, i;
-
- for(i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0)
- break;
- }
- devfn = ((addr >> 8) & 7) | (i << 3);
- s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8);
-}
-
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
- pci_data_write(s, addr, val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr, val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCIBus *s = opaque;
- set_config(s, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 1);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- set_config(s, addr);
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
- &PPC_PCIIO_writeb,
- &PPC_PCIIO_writew,
- &PPC_PCIIO_writel,
-};
-
-static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
- &PPC_PCIIO_readb,
- &PPC_PCIIO_readw,
- &PPC_PCIIO_readl,
-};
-
-static void prep_set_irq(PCIDevice *d, int irq_num, int level)
-{
- /* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
- pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_prep_init(void)
-{
- PCIBus *s;
- PCIDevice *d;
- int PPC_io_memory;
-
- s = pci_register_bus();
- s->set_irq = prep_set_irq;
-
- register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_data_readl, s);
-
- PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
- PPC_PCIIO_write, s);
- cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
-
- /* PCI host bridge */
- d = pci_register_device(s, "PREP Host Bridge - Motorola Raven",
- sizeof(PCIDevice), 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id : Motorola
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x01; // device_id : Raven
- d->config[0x03] = 0x48;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
- return s;
-}
-
-
-/* Grackle PCI host */
-static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = val;
-}
-
-static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = s->config_reg;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_config_read[] = {
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
-};
-
-static void pci_grackle_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- pci_data_write(s, addr, val, 1);
-}
-
-static void pci_grackle_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr, val, 2);
-}
-
-static void pci_grackle_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr, val, 4);
-}
-
-static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- val = pci_data_read(s, addr, 1);
- return val;
-}
-
-static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- val = pci_data_read(s, addr, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_write[] = {
- &pci_grackle_writeb,
- &pci_grackle_writew,
- &pci_grackle_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_read[] = {
- &pci_grackle_readb,
- &pci_grackle_readw,
- &pci_grackle_readl,
-};
-
-void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque)
-{
- bus->low_set_irq = set_irq;
- bus->irq_opaque = irq_opaque;
-}
-
-/* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
-static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level)
-{
- PCIBus *s = d->bus;
- s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_grackle_init(uint32_t base)
-{
- PCIBus *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
- pci_grackle_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
- pci_grackle_write, s);
- cpu_register_physical_memory(base, 0x1000, pci_mem_config);
- cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
- d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice),
- 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x02; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x01;
- d->config[0x0a] = 0x00; // class_sub = host
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
-
- d->config[0x18] = 0x00; // primary_bus
- d->config[0x19] = 0x01; // secondary_bus
- d->config[0x1a] = 0x00; // subordinate_bus
- d->config[0x1c] = 0x00;
- d->config[0x1d] = 0x00;
-
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x00;
- d->config[0x22] = 0x01; // memory_limit
- d->config[0x23] = 0x00;
-
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x00;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x00;
-
-#if 0
- /* PCI2PCI bridge same values as PearPC - check this */
- d->config[0x00] = 0x11; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x04; // class_sub = pci2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x01; // header_type
-
- d->config[0x18] = 0x0; // primary_bus
- d->config[0x19] = 0x1; // secondary_bus
- d->config[0x1a] = 0x1; // subordinate_bus
- d->config[0x1c] = 0x10; // io_base
- d->config[0x1d] = 0x20; // io_limit
-
- d->config[0x20] = 0x80; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x90; // memory_limit
- d->config[0x23] = 0x80;
-
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x84;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x85;
-#endif
- return s;
-}
-
-/* Uninorth PCI host (for all Mac99 and newer machines */
-static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- int i;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
- }
-#if 0
- s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-#else
- s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
-#endif
-}
-
-static uint32_t pci_unin_main_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
-};
-
-static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 1);
-
- return val;
-}
-
-static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
-
- return val;
-}
-
-static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_write[] = {
- &pci_unin_main_writeb,
- &pci_unin_main_writew,
- &pci_unin_main_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_read[] = {
- &pci_unin_main_readb,
- &pci_unin_main_readw,
- &pci_unin_main_readl,
-};
-
-#if 0
-
-static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = 0x80000000 | (val & ~0x00000001);
-}
-
-static uint32_t pci_unin_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = (s->config_reg | 0x00000001) & ~0x80000000;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_config_write[] = {
- &pci_unin_config_writel,
- &pci_unin_config_writel,
- &pci_unin_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_config_read[] = {
- &pci_unin_config_readl,
- &pci_unin_config_readl,
- &pci_unin_config_readl,
-};
-
-static void pci_unin_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- pci_data_write(s, addr & 3, val, 1);
-}
-
-static void pci_unin_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_unin_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s, addr & 3, val, 4);
-}
-
-static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 1);
-
- return val;
-}
-
-static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
-
- return val;
-}
-
-static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 3, 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_write[] = {
- &pci_unin_writeb,
- &pci_unin_writew,
- &pci_unin_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_read[] = {
- &pci_unin_readb,
- &pci_unin_readw,
- &pci_unin_readl,
-};
-#endif
-
-PCIBus *pci_pmac_init(void)
-{
- PCIBus *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- /* Use values found on a real PowerMac */
- /* Uninorth main bus */
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
- pci_unin_main_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
- pci_unin_main_write, s);
- cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
- s->devfn_min = 11 << 3;
- d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice),
- 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1F; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
-#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
- /* pci-to-pci bridge */
- d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
- NULL, NULL);
- d->config[0x00] = 0x11; // vendor_id : TI
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x05; // revision
- d->config[0x0A] = 0x04; // class_sub = pci2pci
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x20; // latency_timer
- d->config[0x0E] = 0x01; // header_type
-
- d->config[0x18] = 0x01; // primary_bus
- d->config[0x19] = 0x02; // secondary_bus
- d->config[0x1A] = 0x02; // subordinate_bus
- d->config[0x1B] = 0x20; // secondary_latency_timer
- d->config[0x1C] = 0x11; // io_base
- d->config[0x1D] = 0x01; // io_limit
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x00; // memory_limit
- d->config[0x23] = 0x80;
- d->config[0x24] = 0x01; // prefetchable_memory_base
- d->config[0x25] = 0x80;
- d->config[0x26] = 0xF1; // prefectchable_memory_limit
- d->config[0x27] = 0x7F;
- // d->config[0x34] = 0xdc // capabilities_pointer
+ addr, val, len);
#endif
-#if 0 // XXX: not needed for now
- /* Uninorth AGP bus */
- s = &pci_bridge[1];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
- NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x20; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- // d->config[0x34] = 0x80; // capabilities_pointer
-#endif
-
-#if 0 // XXX: not needed for now
- /* Uninorth internal bus */
- s = &pci_bridge[2];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
- 3, 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1E; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-#endif
- return s;
-}
-
-/* Ultrasparc APB PCI host */
-static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
- int i;
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
- }
- s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-}
-
-static uint32_t pci_apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_config_write[] = {
- &pci_apb_config_writel,
- &pci_apb_config_writel,
- &pci_apb_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_config_read[] = {
- &pci_apb_config_readl,
- &pci_apb_config_readl,
- &pci_apb_config_readl,
-};
-
-static void apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- //PCIBus *s = opaque;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- break;
- }
-}
-
-static uint32_t apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- //PCIBus *s = opaque;
- uint32_t val;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- val = 0;
- break;
- }
return val;
}
-static CPUWriteMemoryFunc *apb_config_write[] = {
- &apb_config_writel,
- &apb_config_writel,
- &apb_config_writel,
-};
-
-static CPUReadMemoryFunc *apb_config_read[] = {
- &apb_config_readl,
- &apb_config_readl,
- &apb_config_readl,
-};
-
-static void pci_apb_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 1);
-}
-
-static void pci_apb_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 2);
-}
-
-static void pci_apb_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- PCIBus *s = opaque;
-
- pci_data_write(s, addr & 7, val, 4);
-}
-
-static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 1);
- return val;
-}
-
-static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr & 7, 2);
- return val;
-}
-
-static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr)
-{
- PCIBus *s = opaque;
- uint32_t val;
-
- val = pci_data_read(s, addr, 4);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_write[] = {
- &pci_apb_writeb,
- &pci_apb_writew,
- &pci_apb_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_read[] = {
- &pci_apb_readb,
- &pci_apb_readw,
- &pci_apb_readl,
-};
-
-static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outb(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outw(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outl(NULL, addr & 0xffff, val);
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inb(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inw(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inl(NULL, addr & 0xffff);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
- &pci_apb_iowriteb,
- &pci_apb_iowritew,
- &pci_apb_iowritel,
-};
-
-static CPUReadMemoryFunc *pci_apb_ioread[] = {
- &pci_apb_ioreadb,
- &pci_apb_ioreadw,
- &pci_apb_ioreadl,
-};
-
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
-{
- PCIBus *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
-
- /* Ultrasparc APB main bus */
- s = pci_register_bus();
- s->set_irq = pci_set_irq_simple;
-
- pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
- pci_apb_config_write, s);
- apb_config = cpu_register_io_memory(0, apb_config_read,
- apb_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
- pci_apb_write, s);
- pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
- pci_apb_iowrite, s);
-
- cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
- cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
- cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
- cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
-
- d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice),
- -1, NULL, NULL);
- d->config[0x00] = 0x8e; // vendor_id : Sun
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0xa0;
- d->config[0x04] = 0x06; // command = bus master, pci mem
- d->config[0x05] = 0x00;
- d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
- d->config[0x07] = 0x03; // status = medium devsel
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- return s;
-}
-
/***********************************************************/
/* generic PCI irq support */
@@ -1547,7 +403,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base)
void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
{
PCIBus *bus = pci_dev->bus;
- bus->set_irq(pci_dev, irq_num, level);
+ bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level);
}
/***********************************************************/
@@ -1598,7 +454,7 @@ static void pci_info_device(PCIDevice *d)
}
}
-void pci_info(void)
+void pci_for_each_device(void (*fn)(PCIDevice *d))
{
PCIBus *bus = first_bus;
PCIDevice *d;
@@ -1608,236 +464,14 @@ void pci_info(void)
for(devfn = 0; devfn < 256; devfn++) {
d = bus->devices[devfn];
if (d)
- pci_info_device(d);
+ fn(d);
}
}
}
-/***********************************************************/
-/* XXX: the following should be moved to the PC BIOS */
-
-static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
-{
- return cpu_inb(NULL, addr);
-}
-
-static void isa_outb(uint32_t val, uint32_t addr)
-{
- cpu_outb(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
-{
- return cpu_inw(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
-{
- cpu_outw(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
-{
- return cpu_inl(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
-{
- cpu_outl(NULL, addr, val);
-}
-
-static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | addr;
- pci_data_write(s, 0, val, 4);
-}
-
-static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- pci_data_write(s, addr & 3, val, 2);
-}
-
-static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- pci_data_write(s, addr & 3, val, 1);
-}
-
-static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | addr;
- return pci_data_read(s, 0, 4);
-}
-
-static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- return pci_data_read(s, addr & 3, 2);
-}
-
-static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- s->config_reg = 0x80000000 | (s->bus_num << 16) |
- (d->devfn << 8) | (addr & ~3);
- return pci_data_read(s, addr & 3, 1);
-}
-
-static uint32_t pci_bios_io_addr;
-static uint32_t pci_bios_mem_addr;
-/* host irqs corresponding to PCI irqs A-D */
-static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
-
-static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
-{
- PCIIORegion *r;
- uint16_t cmd;
- uint32_t ofs;
-
- if ( region_num == PCI_ROM_SLOT ) {
- ofs = 0x30;
- }else{
- ofs = 0x10 + region_num * 4;
- }
-
- pci_config_writel(d, ofs, addr);
- r = &d->io_regions[region_num];
-
- /* enable memory mappings */
- cmd = pci_config_readw(d, PCI_COMMAND);
- if ( region_num == PCI_ROM_SLOT )
- cmd |= 2;
- else if (r->type & PCI_ADDRESS_SPACE_IO)
- cmd |= 1;
- else
- cmd |= 2;
- pci_config_writew(d, PCI_COMMAND, cmd);
-}
-
-static void pci_bios_init_device(PCIDevice *d)
-{
- int class;
- PCIIORegion *r;
- uint32_t *paddr;
- int i, pin, pic_irq, vendor_id, device_id;
-
- class = pci_config_readw(d, PCI_CLASS_DEVICE);
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- switch(class) {
- case 0x0101:
- if (vendor_id == 0x8086 && device_id == 0x7010) {
- /* PIIX3 IDE */
- pci_config_writew(d, 0x40, 0x8000); // enable IDE0
- pci_config_writew(d, 0x42, 0x8000); // enable IDE1
- goto default_map;
- } else {
- /* IDE: we map it as in ISA mode */
- pci_set_io_region_addr(d, 0, 0x1f0);
- pci_set_io_region_addr(d, 1, 0x3f4);
- pci_set_io_region_addr(d, 2, 0x170);
- pci_set_io_region_addr(d, 3, 0x374);
- }
- break;
- case 0x0300:
- if (vendor_id != 0x1234)
- goto default_map;
- /* VGA: map frame buffer to default Bochs VBE address */
- pci_set_io_region_addr(d, 0, 0xE0000000);
- break;
- case 0x0800:
- /* PIC */
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- if (vendor_id == 0x1014) {
- /* IBM */
- if (device_id == 0x0046 || device_id == 0xFFFF) {
- /* MPIC & MPIC2 */
- pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
- }
- }
- break;
- case 0xff00:
- if (vendor_id == 0x0106b &&
- (device_id == 0x0017 || device_id == 0x0022)) {
- /* macio bridge */
- pci_set_io_region_addr(d, 0, 0x80800000);
- }
- break;
- default:
- default_map:
- /* default memory mappings */
- for(i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (r->size) {
- if (r->type & PCI_ADDRESS_SPACE_IO)
- paddr = &pci_bios_io_addr;
- else
- paddr = &pci_bios_mem_addr;
- *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
- pci_set_io_region_addr(d, i, *paddr);
- *paddr += r->size;
- }
- }
- break;
- }
-
- /* map the interrupt */
- pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
- if (pin != 0) {
- pin = pci_slot_get_pirq(d, pin - 1);
- pic_irq = pci_irqs[pin];
- pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
- }
-}
-
-/*
- * This function initializes the PCI devices as a normal PCI BIOS
- * would do. It is provided just in case the BIOS has no support for
- * PCI.
- */
-void pci_bios_init(void)
+void pci_info(void)
{
- PCIBus *bus;
- PCIDevice *d;
- int devfn, i, irq;
- uint8_t elcr[2];
-
- pci_bios_io_addr = 0xc000;
- pci_bios_mem_addr = 0xf0000000;
-
- /* activate IRQ mappings */
- elcr[0] = 0x00;
- elcr[1] = 0x00;
- for(i = 0; i < 4; i++) {
- irq = pci_irqs[i];
- /* set to trigger level */
- elcr[irq >> 3] |= (1 << (irq & 7));
- /* activate irq remapping in PIIX */
- pci_config_writeb((PCIDevice *)piix3_state, 0x60 + i, irq);
- }
- isa_outb(elcr[0], 0x4d0);
- isa_outb(elcr[1], 0x4d1);
-
- bus = first_bus;
- if (bus) {
- for(devfn = 0; devfn < 256; devfn++) {
- d = bus->devices[devfn];
- if (d)
- pci_bios_init_device(d);
- }
- }
+ pci_for_each_device(pci_info_device);
}
/* Initialize a PCI NIC. */
diff --git a/hw/pci_host.h b/hw/pci_host.h
new file mode 100644
index 0000000000..708dae25e2
--- /dev/null
+++ b/hw/pci_host.h
@@ -0,0 +1,93 @@
+/*
+ * QEMU Common PCI Host bridge configuration data space access routines.
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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.
+ */
+
+/* Worker routines for a PCI host controller that uses an {address,data}
+ register pair to access PCI configuration space. */
+
+typedef struct {
+ uint32_t config_reg;
+ PCIBus *bus;
+} PCIHostState;
+
+static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
+}
+
+static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
+}
+
+static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val)
+{
+ PCIHostState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ if (s->config_reg & (1u << 31))
+ pci_data_write(s->bus, s->config_reg, val, 4);
+}
+
+static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xff;
+ return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
+}
+
+static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xffff;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ if (!(s->config_reg & (1 << 31)))
+ return 0xffffffff;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
new file mode 100644
index 0000000000..1f7ad94c65
--- /dev/null
+++ b/hw/piix_pci.c
@@ -0,0 +1,419 @@
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState I440FXState;
+
+static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ I440FXState *s = opaque;
+ s->config_reg = val;
+}
+
+static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
+{
+ I440FXState *s = opaque;
+ return s->config_reg;
+}
+
+static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
+
+PCIBus *i440fx_init(void)
+{
+ PCIBus *b;
+ PCIDevice *d;
+ I440FXState *s;
+
+ s = qemu_mallocz(sizeof(I440FXState));
+ b = pci_register_bus(piix3_set_irq, NULL, 0);
+ s->bus = b;
+
+ register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
+ register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
+
+ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+ d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
+ NULL, NULL);
+
+ d->config[0x00] = 0x86; // vendor_id
+ d->config[0x01] = 0x80;
+ d->config[0x02] = 0x37; // device_id
+ d->config[0x03] = 0x12;
+ d->config[0x08] = 0x02; // revision
+ d->config[0x0a] = 0x00; // class_sub = host2pci
+ d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ d->config[0x0e] = 0x00; // header_type
+ return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+
+static PCIDevice *piix3_dev;
+
+/* just used for simpler irq handling. */
+#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
+
+static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
+
+/* return the global irq number corresponding to a given device irq
+ pin. We could also use the bus number to have a more precise
+ mapping. */
+static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (irq_num + slot_addend) & 3;
+}
+
+static inline int get_pci_irq_level(int irq_num)
+{
+ int pic_level;
+#if (PCI_IRQ_WORDS == 2)
+ pic_level = ((pci_irq_levels[irq_num][0] |
+ pci_irq_levels[irq_num][1]) != 0);
+#else
+ {
+ int i;
+ pic_level = 0;
+ for(i = 0; i < PCI_IRQ_WORDS; i++) {
+ if (pci_irq_levels[irq_num][i]) {
+ pic_level = 1;
+ break;
+ }
+ }
+ }
+#endif
+ return pic_level;
+}
+
+static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level)
+{
+ int irq_index, shift, pic_irq, pic_level;
+ uint32_t *p;
+
+ irq_num = pci_slot_get_pirq(pci_dev, irq_num);
+ irq_index = pci_dev->irq_index;
+ p = &pci_irq_levels[irq_num][irq_index >> 5];
+ shift = (irq_index & 0x1f);
+ *p = (*p & ~(1 << shift)) | (level << shift);
+
+ /* now we change the pic irq level according to the piix irq mappings */
+ /* XXX: optimize */
+ pic_irq = piix3_dev->config[0x60 + irq_num];
+ if (pic_irq < 16) {
+ /* the pic level is the logical OR of all the PCI irqs mapped
+ to it */
+ pic_level = 0;
+ if (pic_irq == piix3_dev->config[0x60])
+ pic_level |= get_pci_irq_level(0);
+ if (pic_irq == piix3_dev->config[0x61])
+ pic_level |= get_pci_irq_level(1);
+ if (pic_irq == piix3_dev->config[0x62])
+ pic_level |= get_pci_irq_level(2);
+ if (pic_irq == piix3_dev->config[0x63])
+ pic_level |= get_pci_irq_level(3);
+ pic_set_irq(pic_irq, pic_level);
+ }
+}
+
+static void piix3_reset(PCIDevice *d)
+{
+ uint8_t *pci_conf = d->config;
+
+ pci_conf[0x04] = 0x07; // master, memory and I/O
+ pci_conf[0x05] = 0x00;
+ pci_conf[0x06] = 0x00;
+ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+ pci_conf[0x4c] = 0x4d;
+ pci_conf[0x4e] = 0x03;
+ pci_conf[0x4f] = 0x00;
+ pci_conf[0x60] = 0x80;
+ pci_conf[0x69] = 0x02;
+ pci_conf[0x70] = 0x80;
+ pci_conf[0x76] = 0x0c;
+ pci_conf[0x77] = 0x0c;
+ pci_conf[0x78] = 0x02;
+ pci_conf[0x79] = 0x00;
+ pci_conf[0x80] = 0x00;
+ pci_conf[0x82] = 0x00;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa0] = 0x08;
+ pci_conf[0xa2] = 0x00;
+ pci_conf[0xa3] = 0x00;
+ pci_conf[0xa4] = 0x00;
+ pci_conf[0xa5] = 0x00;
+ pci_conf[0xa6] = 0x00;
+ pci_conf[0xa7] = 0x00;
+ pci_conf[0xa8] = 0x0f;
+ pci_conf[0xaa] = 0x00;
+ pci_conf[0xab] = 0x00;
+ pci_conf[0xac] = 0x00;
+ pci_conf[0xae] = 0x00;
+}
+
+int piix3_init(PCIBus *bus)
+{
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
+ d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
+ -1, NULL, NULL);
+ register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
+
+ piix3_dev = d;
+ pci_conf = d->config;
+
+ pci_conf[0x00] = 0x86; // Intel
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ pci_conf[0x03] = 0x70;
+ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+ piix3_reset(d);
+ return d->devfn;
+}
+
+/***********************************************************/
+/* XXX: the following should be moved to the PC BIOS */
+
+static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
+{
+ return cpu_inb(NULL, addr);
+}
+
+static void isa_outb(uint32_t val, uint32_t addr)
+{
+ cpu_outb(NULL, addr, val);
+}
+
+static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
+{
+ return cpu_inw(NULL, addr);
+}
+
+static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
+{
+ cpu_outw(NULL, addr, val);
+}
+
+static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
+{
+ return cpu_inl(NULL, addr);
+}
+
+static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
+{
+ cpu_outl(NULL, addr, val);
+}
+
+static uint32_t pci_bios_io_addr;
+static uint32_t pci_bios_mem_addr;
+/* host irqs corresponding to PCI irqs A-D */
+static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
+
+static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 4);
+}
+
+static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 2);
+}
+
+static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ pci_data_write(s, addr, val, 1);
+}
+
+static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 4);
+}
+
+static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 2);
+}
+
+static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
+{
+ PCIBus *s = d->bus;
+ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
+ return pci_data_read(s, addr, 1);
+}
+
+static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
+{
+ PCIIORegion *r;
+ uint16_t cmd;
+ uint32_t ofs;
+
+ if ( region_num == PCI_ROM_SLOT ) {
+ ofs = 0x30;
+ }else{
+ ofs = 0x10 + region_num * 4;
+ }
+
+ pci_config_writel(d, ofs, addr);
+ r = &d->io_regions[region_num];
+
+ /* enable memory mappings */
+ cmd = pci_config_readw(d, PCI_COMMAND);
+ if ( region_num == PCI_ROM_SLOT )
+ cmd |= 2;
+ else if (r->type & PCI_ADDRESS_SPACE_IO)
+ cmd |= 1;
+ else
+ cmd |= 2;
+ pci_config_writew(d, PCI_COMMAND, cmd);
+}
+
+static void pci_bios_init_device(PCIDevice *d)
+{
+ int class;
+ PCIIORegion *r;
+ uint32_t *paddr;
+ int i, pin, pic_irq, vendor_id, device_id;
+
+ class = pci_config_readw(d, PCI_CLASS_DEVICE);
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ switch(class) {
+ case 0x0101:
+ if (vendor_id == 0x8086 && device_id == 0x7010) {
+ /* PIIX3 IDE */
+ pci_config_writew(d, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(d, 0x42, 0x8000); // enable IDE1
+ goto default_map;
+ } else {
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(d, 0, 0x1f0);
+ pci_set_io_region_addr(d, 1, 0x3f4);
+ pci_set_io_region_addr(d, 2, 0x170);
+ pci_set_io_region_addr(d, 3, 0x374);
+ }
+ break;
+ case 0x0300:
+ if (vendor_id != 0x1234)
+ goto default_map;
+ /* VGA: map frame buffer to default Bochs VBE address */
+ pci_set_io_region_addr(d, 0, 0xE0000000);
+ break;
+ case 0x0800:
+ /* PIC */
+ vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
+ device_id = pci_config_readw(d, PCI_DEVICE_ID);
+ if (vendor_id == 0x1014) {
+ /* IBM */
+ if (device_id == 0x0046 || device_id == 0xFFFF) {
+ /* MPIC & MPIC2 */
+ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
+ }
+ }
+ break;
+ case 0xff00:
+ if (vendor_id == 0x0106b &&
+ (device_id == 0x0017 || device_id == 0x0022)) {
+ /* macio bridge */
+ pci_set_io_region_addr(d, 0, 0x80800000);
+ }
+ break;
+ default:
+ default_map:
+ /* default memory mappings */
+ for(i = 0; i < PCI_NUM_REGIONS; i++) {
+ r = &d->io_regions[i];
+ if (r->size) {
+ if (r->type & PCI_ADDRESS_SPACE_IO)
+ paddr = &pci_bios_io_addr;
+ else
+ paddr = &pci_bios_mem_addr;
+ *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
+ pci_set_io_region_addr(d, i, *paddr);
+ *paddr += r->size;
+ }
+ }
+ break;
+ }
+
+ /* map the interrupt */
+ pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
+ if (pin != 0) {
+ pin = pci_slot_get_pirq(d, pin - 1);
+ pic_irq = pci_irqs[pin];
+ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
+ }
+}
+
+/*
+ * This function initializes the PCI devices as a normal PCI BIOS
+ * would do. It is provided just in case the BIOS has no support for
+ * PCI.
+ */
+void pci_bios_init(void)
+{
+ int i, irq;
+ uint8_t elcr[2];
+
+ pci_bios_io_addr = 0xc000;
+ pci_bios_mem_addr = 0xf0000000;
+
+ /* activate IRQ mappings */
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+ for(i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+ /* activate irq remapping in PIIX */
+ pci_config_writeb(piix3_dev, 0x60 + i, irq);
+ }
+ isa_outb(elcr[0], 0x4d0);
+ isa_outb(elcr[1], 0x4d1);
+
+ pci_for_each_device(pci_bios_init_device);
+}
+
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 33167cdf75..24830457a7 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
if (is_heathrow) {
isa_mem_base = 0x80000000;
- pci_bus = pci_grackle_init(0xfec00000);
/* Register 2 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
/* init basic PC hardware */
+ pic = heathrow_pic_init(&heathrow_pic_mem_index);
+ set_irq = heathrow_pic_set_irq;
+ pci_bus = pci_grackle_init(0xfec00000, pic);
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
- pic = heathrow_pic_init(&heathrow_pic_mem_index);
- set_irq = heathrow_pic_set_irq;
- pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
@@ -462,7 +461,6 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
- pci_bus = pci_pmac_init();
/* Register 8 MB of ISA IO space */
PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
@@ -472,13 +470,13 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
+ pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
+ set_irq = openpic_set_irq;
+ pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
- pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
- set_irq = openpic_set_irq;
- pci_set_pic(pci_bus, set_irq, pic);
/* XXX: suppress that */
isa_pic = pic_init(pic_irq_request, NULL);
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
new file mode 100644
index 0000000000..a31b74c80a
--- /dev/null
+++ b/hw/prep_pci.c
@@ -0,0 +1,167 @@
+/*
+ * QEMU PREP PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState PREPPCIState;
+
+static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+ s->config_reg = val;
+}
+
+static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr)
+{
+ PREPPCIState *s = opaque;
+ return s->config_reg;
+}
+
+static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
+{
+ int i;
+
+ for(i = 0; i < 11; i++) {
+ if ((addr & (1 << (11 + i))) != 0)
+ break;
+ }
+ return (addr & 0x7ff) | (i << 11);
+}
+
+static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
+}
+
+static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
+}
+
+static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ PREPPCIState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+}
+
+static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
+ return val;
+}
+
+static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
+{
+ PREPPCIState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
+ &PPC_PCIIO_writeb,
+ &PPC_PCIIO_writew,
+ &PPC_PCIIO_writel,
+};
+
+static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
+ &PPC_PCIIO_readb,
+ &PPC_PCIIO_readw,
+ &PPC_PCIIO_readl,
+};
+
+static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ /* XXX: we do not simulate the hardware - we rely on the BIOS to
+ set correctly for irq line field */
+ pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_prep_init(void)
+{
+ PREPPCIState *s;
+ PCIDevice *d;
+ int PPC_io_memory;
+
+ s = qemu_mallocz(sizeof(PREPPCIState));
+ s->bus = pci_register_bus(prep_set_irq, NULL, 0);
+
+ register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
+ register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
+
+ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
+ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
+ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
+ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
+ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+
+ PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
+ PPC_PCIIO_write, s);
+ cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
+
+ /* PCI host bridge */
+ d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
+ sizeof(PCIDevice), 0, NULL, NULL);
+ d->config[0x00] = 0x57; // vendor_id : Motorola
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x01; // device_id : Raven
+ d->config[0x03] = 0x48;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+
+ return s->bus;
+}
+
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 3619005d71..f25fa3eeab 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -183,6 +183,11 @@ void pic_set_irq(int irq, int level)
slavio_pic_set_irq(slavio_intctl, irq, level);
}
+void pic_set_irq_new(void *opaque, int irq, int level)
+{
+ pic_set_irq(irq, level);
+}
+
void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
{
slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 208d3dd63a..5e6f8baf95 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -329,7 +329,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
}
}
}
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE);
+ pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL);
isa_mem_base = VGA_BASE;
vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
new file mode 100644
index 0000000000..a7e3600047
--- /dev/null
+++ b/hw/unin_pci.c
@@ -0,0 +1,261 @@
+/*
+ * QEMU Uninorth PCI host (for all Mac99 and newer machines)
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * 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 "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+typedef PCIHostState UNINState;
+
+static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ UNINState *s = opaque;
+ int i;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ for (i = 11; i < 32; i++) {
+ if ((val & (1 << i)) != 0)
+ break;
+ }
+#if 0
+ s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
+#else
+ s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
+#endif
+}
+
+static uint32_t pci_unin_main_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ UNINState *s = opaque;
+ uint32_t val;
+ int devfn;
+
+ devfn = (s->config_reg >> 8) & 0xFF;
+ val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
+ &pci_unin_main_config_writel,
+ &pci_unin_main_config_writel,
+ &pci_unin_main_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
+ &pci_unin_main_config_readl,
+ &pci_unin_main_config_readl,
+ &pci_unin_main_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_unin_main_write[] = {
+ &pci_host_data_writeb,
+ &pci_host_data_writew,
+ &pci_host_data_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_main_read[] = {
+ &pci_host_data_readb,
+ &pci_host_data_readw,
+ &pci_host_data_readl,
+};
+
+#if 0
+
+static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ UNINState *s = opaque;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ s->config_reg = 0x80000000 | (val & ~0x00000001);
+}
+
+static uint32_t pci_unin_config_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ UNINState *s = opaque;
+ uint32_t val;
+
+ val = (s->config_reg | 0x00000001) & ~0x80000000;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_unin_config_write[] = {
+ &pci_unin_config_writel,
+ &pci_unin_config_writel,
+ &pci_unin_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_config_read[] = {
+ &pci_unin_config_readl,
+ &pci_unin_config_readl,
+ &pci_unin_config_readl,
+};
+
+static CPUWriteMemoryFunc *pci_unin_write[] = {
+ &pci_host_pci_writeb,
+ &pci_host_pci_writew,
+ &pci_host_pci_writel,
+};
+
+static CPUReadMemoryFunc *pci_unin_read[] = {
+ &pci_host_pci_readb,
+ &pci_host_pci_readw,
+ &pci_host_pci_readl,
+};
+#endif
+
+static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
+}
+
+PCIBus *pci_pmac_init(void *pic)
+{
+ UNINState *s;
+ PCIDevice *d;
+ int pci_mem_config, pci_mem_data;
+
+ /* Use values found on a real PowerMac */
+ /* Uninorth main bus */
+ s = qemu_mallocz(sizeof(UNINState));
+ s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3);
+
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
+ pci_unin_main_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
+ pci_unin_main_write, s);
+ cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
+ d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice),
+ 11 << 3, NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x1F; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+
+#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
+ /* pci-to-pci bridge */
+ d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
+ NULL, NULL);
+ d->config[0x00] = 0x11; // vendor_id : TI
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x26; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x05; // revision
+ d->config[0x0A] = 0x04; // class_sub = pci2pci
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x20; // latency_timer
+ d->config[0x0E] = 0x01; // header_type
+
+ d->config[0x18] = 0x01; // primary_bus
+ d->config[0x19] = 0x02; // secondary_bus
+ d->config[0x1A] = 0x02; // subordinate_bus
+ d->config[0x1B] = 0x20; // secondary_latency_timer
+ d->config[0x1C] = 0x11; // io_base
+ d->config[0x1D] = 0x01; // io_limit
+ d->config[0x20] = 0x00; // memory_base
+ d->config[0x21] = 0x80;
+ d->config[0x22] = 0x00; // memory_limit
+ d->config[0x23] = 0x80;
+ d->config[0x24] = 0x01; // prefetchable_memory_base
+ d->config[0x25] = 0x80;
+ d->config[0x26] = 0xF1; // prefectchable_memory_limit
+ d->config[0x27] = 0x7F;
+ // d->config[0x34] = 0xdc // capabilities_pointer
+#endif
+#if 0 // XXX: not needed for now
+ /* Uninorth AGP bus */
+ s = &pci_bridge[1];
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
+ pci_unin_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
+ pci_unin_write, s);
+ cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
+
+ d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
+ NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x20; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ // d->config[0x34] = 0x80; // capabilities_pointer
+#endif
+
+#if 0 // XXX: not needed for now
+ /* Uninorth internal bus */
+ s = &pci_bridge[2];
+ pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
+ pci_unin_config_write, s);
+ pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
+ pci_unin_write, s);
+ cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
+ cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
+
+ d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
+ 3, 11 << 3, NULL, NULL);
+ d->config[0x00] = 0x6b; // vendor_id : Apple
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x1E; // device_id
+ d->config[0x03] = 0x00;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x0A] = 0x00; // class_sub = pci host
+ d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ d->config[0x0C] = 0x08; // cache_line_size
+ d->config[0x0D] = 0x10; // latency_timer
+ d->config[0x0E] = 0x00; // header_type
+ d->config[0x34] = 0x00; // capabilities_pointer
+#endif
+ return s->bus;
+}
+
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 23964f36a5..a18833da85 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -638,7 +638,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
+void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn)
{
UHCIState *s;
uint8_t *pci_conf;
@@ -647,8 +647,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
s = (UHCIState *)pci_register_device(bus,
"USB-UHCI", sizeof(UHCIState),
- ((PCIDevice *)piix3_state)->devfn + 2,
- NULL, NULL);
+ devfn, NULL, NULL);
pci_conf = s->dev.config;
pci_conf[0x00] = 0x86;
pci_conf[0x01] = 0x80;
diff --git a/hw/usb.h b/hw/usb.h
index 05502e04db..cb654e000c 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -155,7 +155,7 @@ int set_usb_string(uint8_t *buf, const char *str);
USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
/* usb-uhci.c */
-void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
+void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn);
/* usb-linux.c */
USBDevice *usb_host_device_open(const char *devname);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
new file mode 100644
index 0000000000..34a4bc6c5a
--- /dev/null
+++ b/hw/versatile_pci.c
@@ -0,0 +1,119 @@
+/*
+ * ARM Versatile/PB PCI host controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "vl.h"
+
+static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
+{
+ return addr & 0xf8ff;
+}
+
+static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
+}
+
+static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
+}
+
+static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
+}
+
+static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
+ return val;
+}
+
+static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t val;
+ val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static CPUWriteMemoryFunc *pci_vpb_config_write[] = {
+ &pci_vpb_config_writeb,
+ &pci_vpb_config_writew,
+ &pci_vpb_config_writel,
+};
+
+static CPUReadMemoryFunc *pci_vpb_config_read[] = {
+ &pci_vpb_config_readb,
+ &pci_vpb_config_readw,
+ &pci_vpb_config_readl,
+};
+
+static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
+{
+ pic_set_irq_new(pic, 27 + irq_num, level);
+}
+
+PCIBus *pci_vpb_init(void *pic)
+{
+ PCIBus *s;
+ PCIDevice *d;
+ int mem_config;
+
+ s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3);
+ /* ??? Register memory space. */
+
+ mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
+ pci_vpb_config_write, s);
+ /* Selfconfig area. */
+ cpu_register_physical_memory(0x41000000, 0x10000, mem_config);
+ /* Normal config area. */
+ cpu_register_physical_memory(0x42000000, 0x10000, mem_config);
+
+ d = pci_register_device(s, "Versatile/PB PCI Controller",
+ sizeof(PCIDevice), -1, NULL, NULL);
+ d->config[0x00] = 0xee; // vendor_id
+ d->config[0x01] = 0x10;
+ d->config[0x02] = 0x00; // device_id
+ d->config[0x03] = 0x03;
+ d->config[0x04] = 0x00;
+ d->config[0x05] = 0x00;
+ d->config[0x06] = 0x20;
+ d->config[0x07] = 0x02;
+ d->config[0x08] = 0x00; // revision
+ d->config[0x09] = 0x00; // programming i/f
+ d->config[0x0A] = 0x40; // class_sub = pci host
+ d->config[0x0B] = 0x0b; // class_base = PCI_bridge
+ d->config[0x0D] = 0x10; // latency_timer
+
+ return s;
+}
+
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index e198a518ea..8a821d42d6 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -10,6 +10,8 @@
#include "vl.h"
#include "arm_pic.h"
+#define LOCK_VALUE 0xa05f
+
/* Primary interrupt controller. */
typedef struct vpb_sic_state
@@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
return s;
}
+/* System controller. */
+
+typedef struct {
+ uint32_t base;
+ uint32_t leds;
+ uint16_t lockval;
+ uint32_t cfgdata1;
+ uint32_t cfgdata2;
+ uint32_t flags;
+ uint32_t nvflags;
+ uint32_t resetlevel;
+} vpb_sys_state;
+
+static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
+{
+ vpb_sys_state *s = (vpb_sys_state *)opaque;
+
+ offset -= s->base;
+ switch (offset) {
+ case 0x00: /* ID */
+ return 0x41007004;
+ case 0x04: /* SW */
+ /* General purpose hardware switches.
+ We don't have a useful way of exposing these to the user. */
+ return 0;
+ case 0x08: /* LED */
+ return s->leds;
+ case 0x20: /* LOCK */
+ return s->lockval;
+ case 0x0c: /* OSC0 */
+ case 0x10: /* OSC1 */
+ case 0x14: /* OSC2 */
+ case 0x18: /* OSC3 */
+ case 0x1c: /* OSC4 */
+ case 0x24: /* 100HZ */
+ /* ??? Implement these. */
+ return 0;
+ case 0x28: /* CFGDATA1 */
+ return s->cfgdata1;
+ case 0x2c: /* CFGDATA2 */
+ return s->cfgdata2;
+ case 0x30: /* FLAGS */
+ return s->flags;
+ case 0x38: /* NVFLAGS */
+ return s->nvflags;
+ case 0x40: /* RESETCTL */
+ return s->resetlevel;
+ case 0x44: /* PCICTL */
+ return 1;
+ case 0x48: /* MCI */
+ return 0;
+ case 0x4c: /* FLASH */
+ return 0;
+ case 0x50: /* CLCD */
+ return 0x1000;
+ case 0x54: /* CLCDSER */
+ return 0;
+ case 0x58: /* BOOTCS */
+ return 0;
+ case 0x5c: /* 24MHz */
+ /* ??? not implemented. */
+ return 0;
+ case 0x60: /* MISC */
+ return 0;
+ case 0x64: /* DMAPSR0 */
+ case 0x68: /* DMAPSR1 */
+ case 0x6c: /* DMAPSR2 */
+ case 0x8c: /* OSCRESET0 */
+ case 0x90: /* OSCRESET1 */
+ case 0x94: /* OSCRESET2 */
+ case 0x98: /* OSCRESET3 */
+ case 0x9c: /* OSCRESET4 */
+ case 0xc0: /* SYS_TEST_OSC0 */
+ case 0xc4: /* SYS_TEST_OSC1 */
+ case 0xc8: /* SYS_TEST_OSC2 */
+ case 0xcc: /* SYS_TEST_OSC3 */
+ case 0xd0: /* SYS_TEST_OSC4 */
+ return 0;
+ default:
+ printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
+ return 0;
+ }
+}
+
+static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ vpb_sys_state *s = (vpb_sys_state *)opaque;
+ offset -= s->base;
+
+ switch (offset) {
+ case 0x08: /* LED */
+ s->leds = val;
+ case 0x0c: /* OSC0 */
+ case 0x10: /* OSC1 */
+ case 0x14: /* OSC2 */
+ case 0x18: /* OSC3 */
+ case 0x1c: /* OSC4 */
+ /* ??? */
+ break;
+ case 0x20: /* LOCK */
+ if (val == LOCK_VALUE)
+ s->lockval = val;
+ else
+ s->lockval = val & 0x7fff;
+ break;
+ case 0x28: /* CFGDATA1 */
+ /* ??? Need to implement this. */
+ s->cfgdata1 = val;
+ break;
+ case 0x2c: /* CFGDATA2 */
+ /* ??? Need to implement this. */
+ s->cfgdata2 = val;
+ break;
+ case 0x30: /* FLAGSSET */
+ s->flags |= val;
+ break;
+ case 0x34: /* FLAGSCLR */
+ s->flags &= ~val;
+ break;
+ case 0x38: /* NVFLAGSSET */
+ s->nvflags |= val;
+ break;
+ case 0x3c: /* NVFLAGSCLR */
+ s->nvflags &= ~val;
+ break;
+ case 0x40: /* RESETCTL */
+ if (s->lockval == LOCK_VALUE) {
+ s->resetlevel = val;
+ if (val & 0x100)
+ cpu_abort(cpu_single_env, "Board reset\n");
+ }
+ break;
+ case 0x44: /* PCICTL */
+ /* nothing to do. */
+ break;
+ case 0x4c: /* FLASH */
+ case 0x50: /* CLCD */
+ case 0x54: /* CLCDSER */
+ case 0x64: /* DMAPSR0 */
+ case 0x68: /* DMAPSR1 */
+ case 0x6c: /* DMAPSR2 */
+ case 0x8c: /* OSCRESET0 */
+ case 0x90: /* OSCRESET1 */
+ case 0x94: /* OSCRESET2 */
+ case 0x98: /* OSCRESET3 */
+ case 0x9c: /* OSCRESET4 */
+ break;
+ default:
+ printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
+ return;
+ }
+}
+
+static CPUReadMemoryFunc *vpb_sys_readfn[] = {
+ vpb_sys_read,
+ vpb_sys_read,
+ vpb_sys_read
+};
+
+static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
+ vpb_sys_write,
+ vpb_sys_write,
+ vpb_sys_write
+};
+
+static vpb_sys_state *vpb_sys_init(uint32_t base)
+{
+ vpb_sys_state *s;
+ int iomemtype;
+
+ s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
+ if (!s)
+ return NULL;
+ s->base = base;
+ iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
+ vpb_sys_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ /* ??? Save/restore. */
+ return s;
+}
+
/* Board init. */
/* The AB and PB boards both use the same core, just with different
@@ -159,6 +343,10 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
CPUState *env;
void *pic;
void *sic;
+ PCIBus *pci_bus;
+ NICInfo *nd;
+ int n;
+ int done_smc = 0;
env = cpu_init();
cpu_arm_set_model(env, ARM_CPUID_ARM926);
@@ -166,20 +354,24 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
/* SDRAM at address zero. */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ vpb_sys_init(0x10000000);
pic = arm_pic_init_cpu(env);
pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
sic = vpb_sic_init(0x10003000, pic, 31);
pl050_init(0x10006000, sic, 3, 0);
pl050_init(0x10007000, sic, 4, 1);
- /* TODO: Init PCI NICs. */
- if (nd_table[0].vlan) {
- if (nd_table[0].model == NULL
- || strcmp(nd_table[0].model, "smc91c111") == 0) {
- smc91c111_init(&nd_table[0], 0x10010000, sic, 25);
+ pci_bus = pci_vpb_init(sic);
+ /* The Versatile PCI bridge does not provide access to PCI IO space,
+ so many of the qemu PCI devices are not useable. */
+ for(n = 0; n < nb_nics; n++) {
+ nd = &nd_table[n];
+ if (!nd->model)
+ nd->model = done_smc ? "rtl8139" : "smc91c111";
+ if (strcmp(nd->model, "smc91c111") == 0) {
+ smc91c111_init(nd, 0x10010000, sic, 25);
} else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
- exit (1);
+ pci_nic_init(pci_bus, nd);
}
}