diff mbox

[v3,13/25] piix_pci: add NEC PC-9821 family interface

Message ID 200910281652.AA00176@YOUR-BD18D6DD63.m1.interq.or.jp
State New
Headers show

Commit Message

武田 =?ISO-2022-JP?B?IBskQj1TTGkbKEI=?= Oct. 28, 2009, 4:52 p.m. UTC

diff mbox

Patch

diff --git a/qemu/hw/pci_ids.h b/qemu/hw/pci_ids.h
index 63379c2..ca32656 100644
--- a/qemu/hw/pci_ids.h
+++ b/qemu/hw/pci_ids.h
@@ -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
diff --git a/qemu/hw/piix_pci.c b/qemu/hw/piix_pci.c
index ed036fe..8b7ff9d 100644
--- a/qemu/hw/piix_pci.c
+++ b/qemu/hw/piix_pci.c
@@ -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 */
     }
 };