Add PowerPC power-management state check callback.
[qemu] / hw / pxa2xx_gpio.c
index eab2e72..723b1c1 100644 (file)
@@ -24,6 +24,7 @@ struct pxa2xx_gpio_info_s {
     uint32_t rising[PXA2XX_GPIO_BANKS];
     uint32_t falling[PXA2XX_GPIO_BANKS];
     uint32_t status[PXA2XX_GPIO_BANKS];
+    uint32_t gpsr[PXA2XX_GPIO_BANKS];
     uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
 
     uint32_t prev_level[PXA2XX_GPIO_BANKS];
@@ -53,7 +54,7 @@ static struct {
 } pxa2xx_gpio_regs[0x200] = {
     [0 ... 0x1ff] = { GPIO_NONE, 0 },
 #define PXA2XX_REG(reg, a0, a1, a2, a3)        \
-    [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 }, 
+    [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
 
     PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
     PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
@@ -152,6 +153,11 @@ static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset)
     case GPDR:         /* GPIO Pin-Direction registers */
         return s->dir[bank];
 
+    case GPSR:         /* GPIO Pin-Output Set registers */
+        printf("%s: Read from a write-only register " REG_FMT "\n",
+                        __FUNCTION__, offset);
+        return s->gpsr[bank];  /* Return last written value.  */
+
     case GRER:         /* GPIO Rising-Edge Detect Enable registers */
         return s->rising[bank];
 
@@ -201,6 +207,7 @@ static void pxa2xx_gpio_write(void *opaque,
     case GPSR:         /* GPIO Pin-Output Set registers */
         s->olevel[bank] |= value;
         pxa2xx_gpio_handler_update(s);
+        s->gpsr[bank] = value;
         break;
 
     case GPCR:         /* GPIO Pin-Output Clear registers */
@@ -247,6 +254,51 @@ static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = {
     pxa2xx_gpio_write
 };
 
+static void pxa2xx_gpio_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->lines);
+
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        qemu_put_be32s(f, &s->ilevel[i]);
+        qemu_put_be32s(f, &s->olevel[i]);
+        qemu_put_be32s(f, &s->dir[i]);
+        qemu_put_be32s(f, &s->rising[i]);
+        qemu_put_be32s(f, &s->falling[i]);
+        qemu_put_be32s(f, &s->status[i]);
+        qemu_put_be32s(f, &s->gafr[i * 2 + 0]);
+        qemu_put_be32s(f, &s->gafr[i * 2 + 1]);
+
+        qemu_put_be32s(f, &s->prev_level[i]);
+    }
+}
+
+static int pxa2xx_gpio_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int i;
+
+    if (qemu_get_be32(f) != s->lines)
+        return -EINVAL;
+
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        qemu_get_be32s(f, &s->ilevel[i]);
+        qemu_get_be32s(f, &s->olevel[i]);
+        qemu_get_be32s(f, &s->dir[i]);
+        qemu_get_be32s(f, &s->rising[i]);
+        qemu_get_be32s(f, &s->falling[i]);
+        qemu_get_be32s(f, &s->status[i]);
+        qemu_get_be32s(f, &s->gafr[i * 2 + 0]);
+        qemu_get_be32s(f, &s->gafr[i * 2 + 1]);
+
+        qemu_get_be32s(f, &s->prev_level[i]);
+    }
+
+    return 0;
+}
+
 struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
                 CPUState *env, qemu_irq *pic, int lines)
 {
@@ -263,7 +315,10 @@ struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
 
     iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn,
                     pxa2xx_gpio_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+    register_savevm("pxa2xx_gpio", 0, 0,
+                    pxa2xx_gpio_save, pxa2xx_gpio_load, s);
 
     return s;
 }