]> git.proxmox.com Git - qemu.git/blobdiff - hw/gt64xxx.c
usb-hub: implement reset
[qemu.git] / hw / gt64xxx.c
index b027ce8497b2b0de4d012cdd82dd835c46fb9182..432683aceaf6525b4265b72675af60435d2f8758 100644 (file)
@@ -2,7 +2,7 @@
  * QEMU GT64120 PCI host
  *
  * Copyright (c) 2006,2007 Aurelien Jarno
- * 
+ *
  * 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
  * THE SOFTWARE.
  */
 
-#include "vl.h"
-
-typedef target_phys_addr_t pci_addr_t;
+#include "hw.h"
+#include "mips.h"
+#include "pci.h"
 #include "pci_host.h"
+#include "pc.h"
+#include "exec-memory.h"
 
 //#define DEBUG
 
 #ifdef DEBUG
-#define dprintf(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
 #else
-#define dprintf(fmt, ...)
+#define DPRINTF(fmt, ...)
 #endif
 
 #define GT_REGS                        (0x1000 >> 2)
@@ -222,16 +224,14 @@ typedef target_phys_addr_t pci_addr_t;
 #define GT_PCI0_HICMASK        (0xca4 >> 2)
 #define GT_PCI1_SERR1MASK      (0xca8 >> 2)
 
-
-typedef PCIHostState GT64120PCIState;
-
 #define PCI_MAPPING_ENTRY(regname)            \
     target_phys_addr_t regname ##_start;      \
     target_phys_addr_t regname ##_length;     \
-    int regname ##_handle
+    MemoryRegion regname ##_mem
 
 typedef struct GT64120State {
-    GT64120PCIState *pci;
+    SysBusDevice busdev;
+    PCIHostState pci;
     uint32_t regs[GT_REGS];
     PCI_MAPPING_ENTRY(PCI0IO);
     PCI_MAPPING_ENTRY(ISD);
@@ -269,17 +269,18 @@ static void gt64120_isd_mapping(GT64120State *s)
     target_phys_addr_t start = s->regs[GT_ISD] << 21;
     target_phys_addr_t length = 0x1000;
 
-    if (s->ISD_length)
-        cpu_register_physical_memory(s->ISD_start, s->ISD_length,
-                                     IO_MEM_UNASSIGNED);
+    if (s->ISD_length) {
+        memory_region_del_subregion(get_system_memory(), &s->ISD_mem);
+    }
     check_reserved_space(&start, &length);
     length = 0x1000;
     /* Map new address */
-    dprintf("ISD: %x@%x -> %x@%x, %x\n", s->ISD_length, s->ISD_start,
-            length, start, s->ISD_handle);
+    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
+        " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
+        s->ISD_length, s->ISD_start, length, start);
     s->ISD_start = start;
     s->ISD_length = length;
-    cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle);
+    memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
 }
 
 static void gt64120_pci_mapping(GT64120State *s)
@@ -287,28 +288,32 @@ static void gt64120_pci_mapping(GT64120State *s)
     /* Update IO mapping */
     if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
     {
-      /* Unmap old IO address */           
+      /* Unmap old IO address */
       if (s->PCI0IO_length)
       {
-        cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED);         
+          memory_region_del_subregion(get_system_memory(), &s->PCI0IO_mem);
+          memory_region_destroy(&s->PCI0IO_mem);
       }
       /* Map new IO address */
       s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
       s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
       isa_mem_base = s->PCI0IO_start;
-      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
+      if (s->PCI0IO_length) {
+          isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
+          memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
+                                      &s->PCI0IO_mem);
+      }
     }
 }
 
 static void gt64120_writel (void *opaque, target_phys_addr_t addr,
-                            uint32_t val)
+                            uint64_t val, unsigned size)
 {
     GT64120State *s = opaque;
     uint32_t saddr;
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
 
     saddr = (addr & 0xfff) >> 2;
     switch (saddr) {
@@ -423,7 +428,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
     case GT_DEV_B3:
     case GT_DEV_BOOT:
         /* Not implemented */
-        dprintf ("Unimplemented device register offset 0x%x\n", saddr << 2);
+        DPRINTF ("Unimplemented device register offset 0x%x\n", saddr << 2);
         break;
 
     /* ECC */
@@ -457,7 +462,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
     case GT_DMA2_CUR:
     case GT_DMA3_CUR:
         /* Not implemented */
-        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
         break;
 
     /* DMA Channel Control */
@@ -466,13 +471,13 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
     case GT_DMA2_CTRL:
     case GT_DMA3_CTRL:
         /* Not implemented */
-        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
         break;
 
     /* DMA Arbiter */
     case GT_DMA_ARB:
         /* Not implemented */
-        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
         break;
 
     /* Timer/Counter */
@@ -482,7 +487,7 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
     case GT_TC3:
     case GT_TC_CONTROL:
         /* Not implemented */
-        dprintf ("Unimplemented timer register offset 0x%x\n", saddr << 2);
+        DPRINTF ("Unimplemented timer register offset 0x%x\n", saddr << 2);
         break;
 
     /* PCI Internal */
@@ -525,11 +530,13 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
         /* not implemented */
         break;
     case GT_PCI0_CFGADDR:
-        s->pci->config_reg = val & 0x80fffffc;
+        s->pci.config_reg = val & 0x80fffffc;
         break;
     case GT_PCI0_CFGDATA:
-        if (s->pci->config_reg & (1u << 31))
-            pci_host_data_writel(s->pci, 0, val);
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+            val = bswap32(val);
+        if (s->pci.config_reg & (1u << 31))
+            pci_data_write(s->pci.bus, s->pci.config_reg, val, 4);
         break;
 
     /* Interrupts */
@@ -537,19 +544,19 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
         /* not really implemented */
         s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
         s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
-        dprintf("INTRCAUSE %x\n", val);
+        DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
         break;
     case GT_INTRMASK:
         s->regs[saddr] = val & 0x3c3ffffe;
-        dprintf("INTRMASK %x\n", val);
+        DPRINTF("INTRMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_ICMASK:
         s->regs[saddr] = val & 0x03fffffe;
-        dprintf("ICMASK %x\n", val);
+        DPRINTF("ICMASK %" PRIx64 "\n", val);
         break;
     case GT_PCI0_SERR0MASK:
         s->regs[saddr] = val & 0x0000003f;
-        dprintf("SERR0MASK %x\n", val);
+        DPRINTF("SERR0MASK %" PRIx64 "\n", val);
         break;
 
     /* Reserved when only PCI_0 is configured. */
@@ -573,21 +580,19 @@ static void gt64120_writel (void *opaque, target_phys_addr_t addr,
         break;
 
     default:
-        dprintf ("Bad register offset 0x%x\n", (int)addr);
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
         break;
     }
 }
 
-static uint32_t gt64120_readl (void *opaque,
-                               target_phys_addr_t addr)
+static uint64_t gt64120_readl (void *opaque,
+                               target_phys_addr_t addr, unsigned size)
 {
     GT64120State *s = opaque;
     uint32_t val;
     uint32_t saddr;
 
-    val = 0;
     saddr = (addr & 0xfff) >> 2;
-
     switch (saddr) {
 
     /* CPU Configuration */
@@ -604,7 +609,7 @@ static uint32_t gt64120_readl (void *opaque,
     case GT_CPUERR_DATAHI:
     case GT_CPUERR_PARITY:
         /* Emulated memory has no error, always return the initial
-           values */ 
+           values */
         val = s->regs[saddr];
         break;
 
@@ -614,7 +619,7 @@ static uint32_t gt64120_readl (void *opaque,
         /* Reading those register should empty all FIFO on the PCI
            bus, which are not emulated. The return value should be
            a random value that should be ignored. */
-        val = 0xc000ffee; 
+        val = 0xc000ffee;
         break;
 
     /* ECC */
@@ -624,7 +629,7 @@ static uint32_t gt64120_readl (void *opaque,
     case GT_ECC_CALC:
     case GT_ECC_ERRADDR:
         /* Emulated memory has no error, always return the initial
-           values */ 
+           values */
         val = s->regs[saddr];
         break;
 
@@ -663,7 +668,7 @@ static uint32_t gt64120_readl (void *opaque,
         val = s->regs[saddr];
         break;
     case GT_PCI0_IACK:
-        /* Read the IRQ number */ 
+        /* Read the IRQ number */
         val = pic_read_irq(isa_pic);
         break;
 
@@ -765,13 +770,15 @@ static uint32_t gt64120_readl (void *opaque,
 
     /* PCI Internal */
     case GT_PCI0_CFGADDR:
-        val = s->pci->config_reg;
+        val = s->pci.config_reg;
         break;
     case GT_PCI0_CFGDATA:
-        if (!(s->pci->config_reg & (1u << 31)))
+        if (!(s->pci.config_reg & (1 << 31)))
             val = 0xffffffff;
         else
-            val = pci_host_data_readl(s->pci, 0);
+            val = pci_data_read(s->pci.bus, s->pci.config_reg, 4);
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (s->pci.config_reg & 0x00fff800))
+            val = bswap32(val);
         break;
 
     case GT_PCI0_CMD:
@@ -813,19 +820,19 @@ static uint32_t gt64120_readl (void *opaque,
     /* Interrupts */
     case GT_INTRCAUSE:
         val = s->regs[saddr];
-        dprintf("INTRCAUSE %x\n", val);
+        DPRINTF("INTRCAUSE %x\n", val);
         break;
     case GT_INTRMASK:
         val = s->regs[saddr];
-        dprintf("INTRMASK %x\n", val);
+        DPRINTF("INTRMASK %x\n", val);
         break;
     case GT_PCI0_ICMASK:
         val = s->regs[saddr];
-        dprintf("ICMASK %x\n", val);
+        DPRINTF("ICMASK %x\n", val);
         break;
     case GT_PCI0_SERR0MASK:
         val = s->regs[saddr];
-        dprintf("SERR0MASK %x\n", val);
+        DPRINTF("SERR0MASK %x\n", val);
         break;
 
     /* Reserved when only PCI_0 is configured. */
@@ -840,29 +847,23 @@ static uint32_t gt64120_readl (void *opaque,
 
     default:
         val = s->regs[saddr];
-        dprintf ("Bad register offset 0x%x\n", (int)addr);
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
         break;
     }
 
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
+
     return val;
 }
 
-static CPUWriteMemoryFunc *gt64120_write[] = {
-    &gt64120_writel,
-    &gt64120_writel,
-    &gt64120_writel,
+static const MemoryRegionOps isd_mem_ops = {
+    .read = gt64120_readl,
+    .write = gt64120_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static CPUReadMemoryFunc *gt64120_read[] = {
-    &gt64120_readl,
-    &gt64120_readl,
-    &gt64120_readl,
-};
-
-static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
+static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
 {
     int slot;
 
@@ -887,12 +888,12 @@ static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
     }
 }
 
-extern PCIDevice *piix4_dev;
 static int pci_irq_levels[4];
 
-static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level)
+static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
+    qemu_irq *pic = opaque;
 
     pci_irq_levels[irq_num] = level;
 
@@ -912,7 +913,7 @@ static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level)
 }
 
 
-void gt64120_reset(void *opaque)
+static void gt64120_reset(void *opaque)
 {
     GT64120State *s = opaque;
 
@@ -1073,7 +1074,6 @@ void gt64120_reset(void *opaque)
     s->regs[GT_PCI1_CFGADDR]  = 0x00000000;
     s->regs[GT_PCI1_CFGDATA]  = 0x00000000;
     s->regs[GT_PCI0_CFGADDR]  = 0x00000000;
-    s->regs[GT_PCI0_CFGDATA]  = 0x00000000;
 
     /* Interrupt registers are all zeroed at reset */
 
@@ -1081,87 +1081,76 @@ void gt64120_reset(void *opaque)
     gt64120_pci_mapping(s);
 }
 
-static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len)
+PCIBus *gt64120_register(qemu_irq *pic)
 {
-    uint32_t val = pci_default_read_config(d, address, len);
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    return val;
+    SysBusDevice *s;
+    GT64120State *d;
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "gt64120");
+    qdev_init_nofail(dev);
+    s = sysbus_from_qdev(dev);
+    d = FROM_SYSBUS(GT64120State, s);
+    d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
+                                  gt64120_pci_set_irq, gt64120_pci_map_irq,
+                                  pic,
+                                  get_system_memory(),
+                                  get_system_io(),
+                                  PCI_DEVFN(18, 0), 4);
+    memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
+
+    pci_create_simple(d->pci.bus, PCI_DEVFN(0, 0), "gt64120_pci");
+    return d->pci.bus;
 }
 
-static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val,
-                                 int len)
+static int gt64120_init(SysBusDevice *dev)
 {
-#ifdef TARGET_WORDS_BIGENDIAN
-    val = bswap32(val);
-#endif
-    pci_default_write_config(d, address, val, len);
-}
+    GT64120State *s;
 
-static void gt64120_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-    pci_device_save(d, f);
-}
+    s = FROM_SYSBUS(GT64120State, dev);
 
-static int gt64120_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-    int ret;
-
-    if (version_id != 1)
-        return -EINVAL;
-    ret = pci_device_load(d, f);
-    if (ret < 0)
-        return ret;
+    /* FIXME: This value is computed from registers during reset, but some
+       devices (e.g. VGA card) need to know it when they are registered.
+       This also mean that changing the register to change the mapping
+       does not fully work. */
+    isa_mem_base = 0x10000000;
+    qemu_register_reset(gt64120_reset, s);
     return 0;
 }
 
-PCIBus *pci_gt64120_init(qemu_irq *pic)
+static int gt64120_pci_init(PCIDevice *d)
 {
-    GT64120State *s;
-    PCIDevice *d;
-
-    s = qemu_mallocz(sizeof(GT64120State));
-    s->pci = qemu_mallocz(sizeof(GT64120PCIState));
-
-    s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
-                                   pic, 144, 4);
-    s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s);
-    d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
-                            0, gt64120_read_config, gt64120_write_config);
-
     /* FIXME: Malta specific hw assumptions ahead */
+    pci_set_word(d->config + PCI_COMMAND, 0);
+    pci_set_word(d->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_config_set_prog_interface(d->config, 0);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
+    pci_set_byte(d->config + 0x3d, 0x01);
 
-    d->config[0x00] = 0xab; /* vendor_id */
-    d->config[0x01] = 0x11;
-    d->config[0x02] = 0x20; /* device_id */
-    d->config[0x03] = 0x46;
-
-    d->config[0x04] = 0x00;
-    d->config[0x05] = 0x00;
-    d->config[0x06] = 0x80;
-    d->config[0x07] = 0x02;
-
-    d->config[0x08] = 0x10;
-    d->config[0x09] = 0x00;
-    d->config[0x0A] = 0x00;
-    d->config[0x0B] = 0x06;
-
-    d->config[0x10] = 0x08;
-    d->config[0x14] = 0x08;
-    d->config[0x17] = 0x01;
-    d->config[0x1B] = 0x1c;
-    d->config[0x1F] = 0x1f;
-    d->config[0x23] = 0x14;
-    d->config[0x24] = 0x01;
-    d->config[0x27] = 0x14;
-    d->config[0x3D] = 0x01;
-
-    gt64120_reset(s);
+    return 0;
+}
 
-    register_savevm("GT64120 PCI Bus", 0, 1, gt64120_save, gt64120_load, d);
+static PCIDeviceInfo gt64120_pci_info = {
+    .qdev.name = "gt64120_pci",
+    .qdev.size = sizeof(PCIDevice),
+    .init      = gt64120_pci_init,
+    .vendor_id = PCI_VENDOR_ID_MARVELL,
+    .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
+    .revision  = 0x10,
+    .class_id  = PCI_CLASS_BRIDGE_HOST,
+};
 
-    return s->pci->bus;
+static void gt64120_pci_register_devices(void)
+{
+    sysbus_register_dev("gt64120", sizeof(GT64120State),
+                        gt64120_init);
+    pci_qdev_register(&gt64120_pci_info);
 }
+
+device_init(gt64120_pci_register_devices)