@@ -57,6 +57,10 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_CBUS_BRIDGE 0x0001
+#define PCI_DEVICE_ID_NEC_PC98_GRAPHICS 0x0009
+
#define PCI_VENDOR_ID_MOTOROLA 0x1057
#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
@@ -44,6 +44,9 @@ struct PCII440FXState {
target_phys_addr_t isa_page_descs[384 / 4];
uint8_t smm_enabled;
PIIX3State *piix3;
+ /* NEC PC-9821 */
+ uint8_t drb;
+ uint8_t errsts_no_error;
};
static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
@@ -139,6 +142,20 @@ void i440fx_init_memory_mappings(PCII440FXState *d)
}
}
+void i440fx_update_isa_page_descs(PCII440FXState *d,
+ target_phys_addr_t start_addr,
+ ram_addr_t size)
+{
+ target_phys_addr_t addr;
+
+ for (addr = start_addr; addr < start_addr + size; addr += 0x1000) {
+ if (addr >= 0xa0000 && addr < 0x100000) {
+ int i = (addr - 0xa0000) >> 12;
+ d->isa_page_descs[i] = cpu_get_physical_page_desc(addr);
+ }
+ }
+}
+
static void i440fx_write_config(PCIDevice *dev,
uint32_t address, uint32_t val, int len)
{
@@ -146,8 +163,17 @@ static void i440fx_write_config(PCIDevice *dev,
/* XXX: implement SMRAM.D_LOCK */
pci_default_write_config(dev, address, val, len);
- if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
+ if ((address >= 0x59 && address <= 0x5f) || address == 0x72) {
i440fx_update_memory_mappings(d);
+ } else if (address >= 0x60 && address <= 0x67) {
+ if (d->drb) {
+ d->dev.config[address] = d->drb; /* DRB */
+ }
+ } else if (address == 0x91) {
+ if (d->errsts_no_error) {
+ d->dev.config[address] = 0x00; /* ERRSTS */
+ }
+ }
}
static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
@@ -222,7 +248,9 @@ static int i440fx_initfn(PCIDevice *dev)
return 0;
}
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
+static PCIBus *i440fx_init_common(PCII440FXState **pi440fx_state,
+ int *piix3_devfn, qemu_irq *pic,
+ const char *piix3_name, int devfn)
{
DeviceState *dev;
PCIBus *b;
@@ -240,7 +268,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
piix3 = DO_UPCAST(PIIX3State, dev,
- pci_create_simple(b, -1, "PIIX3"));
+ pci_create_simple(b, devfn, piix3_name));
piix3->pic = pic;
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
(*pi440fx_state)->piix3 = piix3;
@@ -250,6 +278,11 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
return b;
}
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
+{
+ return i440fx_init_common(pi440fx_state, piix3_devfn, pic, "PIIX3", -1);
+}
+
/* PIIX3 PCI to ISA bridge */
static void piix3_set_irq(void *opaque, int irq_num, int level)
@@ -346,6 +379,87 @@ static int piix3_initfn(PCIDevice *dev)
return 0;
}
+/* NEC PC-9821 */
+
+PCIBus *pc98_i440fx_init(PCII440FXState **pi440fx_state,
+ int *piix3_devfn, qemu_irq *pic, ram_addr_t ram_size)
+{
+ PCIBus *pci_bus;
+ PCII440FXState *d;
+ int i;
+
+ /* XXX: implement PC-98 graphics bus bridge */
+ pci_bus = i440fx_init_common(pi440fx_state, piix3_devfn, pic,
+ "STAR_ALPHA", 0x30);
+ d = *pi440fx_state;
+ d->drb = (uint8_t)(ram_size / 0x800000);
+ for (i = 0; i < 8; i++) {
+ d->dev.config[0x60 + i] = d->drb;
+ }
+ d->errsts_no_error = 1;
+
+ return pci_bus;
+}
+
+static void pc98_piix3_reset(void *opaque)
+{
+ static const struct {
+ int port;
+ uint32_t data;
+ } params[] = {
+ /* initialized in PC-9821Rv20 ITF */
+ { 0x04, 0x3a000107 },
+ { 0x40, 0x00ef0010 },
+ { 0x44, 0xfffbfffa },
+ { 0x48, 0xfffefffe },
+ { 0x4c, 0x0000ffff },
+ { 0x50, 0x0f020100 },
+ { 0x54, 0x078a0504 },
+ { 0x58, 0x0b8a0908 },
+ { 0x5c, 0x8f0e0d8c },
+ { 0x60, 0x80808080 },
+ { 0x64, 0x18073f50 },
+ { 0x68, 0xac000000 },
+ { 0x6c, 0x00000000 },
+ { 0x70, 0x0000c00c },
+ { 0x78, 0x000fd9b2 },
+ /* end of params */
+ { -1, 0xffffffff },
+ };
+ PIIX3State *d = opaque;
+ uint8_t *pci_conf = d->dev.config;
+ int i;
+
+ for (i = 0; params[i].port != -1; i++) {
+ pci_conf[params[i].port + 0] = (params[i].data >> 0) & 0xff;
+ pci_conf[params[i].port + 1] = (params[i].data >> 8) & 0xff;
+ pci_conf[params[i].port + 2] = (params[i].data >> 16) & 0xff;
+ pci_conf[params[i].port + 3] = (params[i].data >> 24) & 0xff;
+ }
+
+ memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels));
+}
+
+static int pc98_piix3_initfn(PCIDevice *dev)
+{
+ PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
+ uint8_t *pci_conf;
+
+ isa_bus_new(&d->dev.qdev);
+ vmstate_register(0, &vmstate_piix3, d);
+
+ pci_conf = d->dev.config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_NEC);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_NEC_CBUS_BRIDGE); // STAR ALPHA
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
+ pci_conf[PCI_HEADER_TYPE] =
+ PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
+
+ pc98_piix3_reset(d);
+ qemu_register_reset(pc98_piix3_reset, d);
+ return 0;
+}
+
static PCIDeviceInfo i440fx_info[] = {
{
.qdev.name = "i440FX",
@@ -361,6 +475,12 @@ static PCIDeviceInfo i440fx_info[] = {
.qdev.no_user = 1,
.init = piix3_initfn,
},{
+ .qdev.name = "STAR_ALPHA",
+ .qdev.desc = "ISA bridge",
+ .qdev.size = sizeof(PIIX3State),
+ .qdev.no_user = 1,
+ .init = pc98_piix3_initfn,
+ },{
/* end of list */
}
};