]> git.proxmox.com Git - qemu.git/blobdiff - hw/pxa2xx_lcd.c
prepare for future GPLv2+ relicensing
[qemu.git] / hw / pxa2xx_lcd.c
index c36ff3644bff63218de792fbf1cb3485b3cdc0e7..19a09ff13166ecf8a0cfc27aeb336cc2cf7e239c 100644 (file)
@@ -5,6 +5,9 @@
  * Written by Andrzej Zaborowski <balrog@zabor.org>
  *
  * This code is licensed under the GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
  */
 
 #include "hw.h"
 #include "pixel_ops.h"
 /* FIXME: For graphic_rotate. Should probably be done in common code.  */
 #include "sysemu.h"
+#include "framebuffer.h"
+
+struct DMAChannel {
+    target_phys_addr_t branch;
+    uint8_t up;
+    uint8_t palette[1024];
+    uint8_t pbuffer[1024];
+    void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr,
+                   int *miny, int *maxy);
+
+    target_phys_addr_t descriptor;
+    target_phys_addr_t source;
+    uint32_t id;
+    uint32_t command;
+};
 
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
-
-struct pxa2xx_lcdc_s {
+struct PXA2xxLCDState {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
     qemu_irq irq;
     int irqlevel;
 
     int invalidated;
     DisplayState *ds;
-    QEMUConsole *console;
     drawfn *line_fn[2];
     int dest_width;
     int xres, yres;
@@ -52,30 +69,18 @@ struct pxa2xx_lcdc_s {
     uint32_t liidr;
     uint8_t bscntr;
 
-    struct {
-        target_phys_addr_t branch;
-        int up;
-        uint8_t palette[1024];
-        uint8_t pbuffer[1024];
-        void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb,
-                        int *miny, int *maxy);
-
-        target_phys_addr_t descriptor;
-        target_phys_addr_t source;
-        uint32_t id;
-        uint32_t command;
-    } dma_ch[7];
+    struct DMAChannel dma_ch[7];
 
     qemu_irq vsync_cb;
     int orientation;
 };
 
-struct __attribute__ ((__packed__)) pxa_frame_descriptor_s {
+typedef struct QEMU_PACKED {
     uint32_t fdaddr;
     uint32_t fsaddr;
     uint32_t fidr;
     uint32_t ldcmd;
-};
+} PXAFrameDescriptor;
 
 #define LCCR0  0x000   /* LCD Controller Control register 0 */
 #define LCCR1  0x004   /* LCD Controller Control register 1 */
@@ -179,7 +184,7 @@ struct __attribute__ ((__packed__)) pxa_frame_descriptor_s {
 #define LDCMD_PAL      (1 << 26)
 
 /* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s)
+static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
 {
     int level = 0;
     level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
@@ -199,7 +204,7 @@ static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s)
 }
 
 /* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch)
+static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
 {
     int unmasked;
     if (ch == 0) {
@@ -219,7 +224,7 @@ static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch)
 }
 
 /* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch)
+static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
 {
     int unmasked;
     if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
@@ -242,7 +247,7 @@ static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch)
 }
 
 /* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch)
+static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
 {
     int unmasked;
     if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
@@ -265,7 +270,7 @@ static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch)
 }
 
 /* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch)
+static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
 {
     s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
     if (s->irqlevel)
@@ -275,7 +280,7 @@ static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch)
 }
 
 /* Set Read Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s)
+static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
 {
     s->status[0] |= LCSR0_RDST;
     if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
@@ -283,14 +288,13 @@ static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s)
 }
 
 /* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
+static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
 {
-    struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS];
+    PXAFrameDescriptor desc;
     target_phys_addr_t descptr;
     int i;
 
     for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
-        desc[i] = 0;
         s->dma_ch[i].source = 0;
 
         if (!s->dma_ch[i].up)
@@ -305,21 +309,21 @@ static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
             descptr = s->dma_ch[i].descriptor;
 
         if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
-                    sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size))
+                    sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size))
             continue;
 
-        descptr -= PXA2XX_SDRAM_BASE;
-        desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr);
-        s->dma_ch[i].descriptor = desc[i]->fdaddr;
-        s->dma_ch[i].source = desc[i]->fsaddr;
-        s->dma_ch[i].id = desc[i]->fidr;
-        s->dma_ch[i].command = desc[i]->ldcmd;
+        cpu_physical_memory_read(descptr, (void *)&desc, sizeof(desc));
+        s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
+        s->dma_ch[i].source = tswap32(desc.fsaddr);
+        s->dma_ch[i].id = tswap32(desc.fidr);
+        s->dma_ch[i].command = tswap32(desc.ldcmd);
     }
 }
 
-static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset)
+static uint64_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset,
+                                 unsigned size)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
     int ch;
 
     switch (offset) {
@@ -404,17 +408,16 @@ static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset)
 
     default:
     fail:
-        cpu_abort(cpu_single_env,
-                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
     }
 
     return 0;
 }
 
-static void pxa2xx_lcdc_write(void *opaque,
-                target_phys_addr_t offset, uint32_t value)
+static void pxa2xx_lcdc_write(void *opaque, target_phys_addr_t offset,
+                              uint64_t value, unsigned size)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
     int ch;
 
     switch (offset) {
@@ -560,25 +563,18 @@ static void pxa2xx_lcdc_write(void *opaque,
 
     default:
     fail:
-        cpu_abort(cpu_single_env,
-                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
     }
 }
 
-static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = {
-    pxa2xx_lcdc_read,
-    pxa2xx_lcdc_read,
-    pxa2xx_lcdc_read
-};
-
-static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = {
-    pxa2xx_lcdc_write,
-    pxa2xx_lcdc_write,
-    pxa2xx_lcdc_write
+static const MemoryRegionOps pxa2xx_lcdc_ops = {
+    .read = pxa2xx_lcdc_read,
+    .write = pxa2xx_lcdc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
 /* Load new palette for a given DMA channel, convert to internal format */
-static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp)
+static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
 {
     int i, n, format, r, g, b, alpha;
     uint32_t *dest, *src;
@@ -669,19 +665,16 @@ static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp)
     }
 }
 
-static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
-                uint8_t *fb, int *miny, int *maxy)
+static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
+                target_phys_addr_t addr, int *miny, int *maxy)
 {
-    int y, src_width, dest_width, dirty[2];
-    uint8_t *src, *dest;
-    ram_addr_t x, addr, new_addr, start, end;
-    drawfn fn = 0;
+    int src_width, dest_width;
+    drawfn fn = NULL;
     if (s->dest_width)
         fn = s->line_fn[s->transp][s->bpp];
     if (!fn)
         return;
 
-    src = fb;
     src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
     if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
         src_width *= 3;
@@ -690,54 +683,25 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
     else if (s->bpp > pxa_lcdc_8bpp)
         src_width *= 2;
 
-    dest = ds_get_data(s->ds);
     dest_width = s->xres * s->dest_width;
-
-    addr = (ram_addr_t) (fb - phys_ram_base);
-    start = addr + s->yres * src_width;
-    end = addr;
-    dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
-    for (y = 0; y < s->yres; y ++) {
-        new_addr = addr + src_width;
-        for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
-                        x += TARGET_PAGE_SIZE) {
-            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
-            dirty[0] |= dirty[1];
-        }
-        if (dirty[0] || s->invalidated) {
-            fn((uint32_t *) s->dma_ch[0].palette,
-                            dest, src, s->xres, s->dest_width);
-            if (addr < start)
-                start = addr;
-            end = new_addr;
-            if (y < *miny)
-                *miny = y;
-            if (y >= *maxy)
-                *maxy = y + 1;
-        }
-        addr = new_addr;
-        dirty[0] = dirty[1];
-        src += src_width;
-        dest += dest_width;
-    }
-
-    if (end > start)
-        cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+    *miny = 0;
+    framebuffer_update_display(s->ds, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, dest_width, s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
 }
 
-static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
-                uint8_t *fb, int *miny, int *maxy)
+static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
+               target_phys_addr_t addr, int *miny, int *maxy)
 {
-    int y, src_width, dest_width, dirty[2];
-    uint8_t *src, *dest;
-    ram_addr_t x, addr, new_addr, start, end;
-    drawfn fn = 0;
+    int src_width, dest_width;
+    drawfn fn = NULL;
     if (s->dest_width)
         fn = s->line_fn[s->transp][s->bpp];
     if (!fn)
         return;
 
-    src = fb;
     src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
     if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
         src_width *= 3;
@@ -747,41 +711,77 @@ static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
         src_width *= 2;
 
     dest_width = s->yres * s->dest_width;
-    dest = ds_get_data(s->ds) + dest_width * (s->xres - 1);
-
-    addr = (ram_addr_t) (fb - phys_ram_base);
-    start = addr + s->yres * src_width;
-    end = addr;
-    dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
-    for (y = 0; y < s->yres; y ++) {
-        new_addr = addr + src_width;
-        for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
-                        x += TARGET_PAGE_SIZE) {
-            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
-            dirty[0] |= dirty[1];
-        }
-        if (dirty[0] || s->invalidated) {
-            fn((uint32_t *) s->dma_ch[0].palette,
-                            dest, src, s->xres, -dest_width);
-            if (addr < start)
-                start = addr;
-            end = new_addr;
-            if (y < *miny)
-                *miny = y;
-            if (y >= *maxy)
-                *maxy = y + 1;
-        }
-        addr = new_addr;
-        dirty[0] = dirty[1];
-        src += src_width;
-        dest += s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, s->dest_width, -dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
+                target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, -dest_width, -s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
+               target_phys_addr_t addr, int *miny, int *maxy)
+{
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
     }
 
-    if (end > start)
-        cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(s->ds, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, -s->dest_width, dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
 }
 
-static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
+static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
 {
     int width, height;
     if (!(s->control[0] & LCCR0_ENB))
@@ -791,10 +791,11 @@ static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
     height = LCCR2_LPP(s->control[2]) + 1;
 
     if (width != s->xres || height != s->yres) {
-        if (s->orientation)
-            qemu_console_resize(s->console, height, width);
-        else
-            qemu_console_resize(s->console, width, height);
+        if (s->orientation == 90 || s->orientation == 270) {
+            qemu_console_resize(s->ds, height, width);
+        } else {
+            qemu_console_resize(s->ds, width, height);
+        }
         s->invalidated = 1;
         s->xres = width;
         s->yres = height;
@@ -803,8 +804,7 @@ static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
 
 static void pxa2xx_update_display(void *opaque)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
-    uint8_t *fb;
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
     target_phys_addr_t fbptr;
     int miny, maxy;
     int ch;
@@ -826,17 +826,15 @@ static void pxa2xx_update_display(void *opaque)
             }
             fbptr = s->dma_ch[ch].source;
             if (!(fbptr >= PXA2XX_SDRAM_BASE &&
-                    fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) {
+                    fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
                 pxa2xx_dma_ber_set(s, ch);
                 continue;
             }
-            fbptr -= PXA2XX_SDRAM_BASE;
-            fb = phys_ram_base + fbptr;
 
             if (s->dma_ch[ch].command & LDCMD_PAL) {
-                memcpy(s->dma_ch[ch].pbuffer, fb,
-                                MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
-                                sizeof(s->dma_ch[ch].pbuffer)));
+                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
+                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+                        sizeof(s->dma_ch[ch].pbuffer)));
                 pxa2xx_palette_parse(s, ch, s->bpp);
             } else {
                 /* Do we need to reparse palette */
@@ -846,7 +844,7 @@ static void pxa2xx_update_display(void *opaque)
                 /* ACK frame start */
                 pxa2xx_dma_sof_set(s, ch);
 
-                s->dma_ch[ch].redraw(s, fb, &miny, &maxy);
+                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
                 s->invalidated = 0;
 
                 /* ACK frame completed */
@@ -860,10 +858,26 @@ static void pxa2xx_update_display(void *opaque)
         s->status[0] |= LCSR0_LDD;
     }
 
-    if (s->orientation)
-        dpy_update(s->ds, miny, 0, maxy, s->xres);
-    else
-        dpy_update(s->ds, 0, miny, s->xres, maxy);
+    if (miny >= 0) {
+        switch (s->orientation) {
+        case 0:
+            dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
+            break;
+        case 90:
+            dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
+            break;
+        case 180:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
+            break;
+        case 270:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
+            break;
+        }
+    }
     pxa2xx_lcdc_int_update(s);
 
     qemu_irq_raise(s->vsync_cb);
@@ -871,7 +885,7 @@ static void pxa2xx_update_display(void *opaque)
 
 static void pxa2xx_invalidate_display(void *opaque)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
     s->invalidated = 1;
 }
 
@@ -882,12 +896,21 @@ static void pxa2xx_screen_dump(void *opaque, const char *filename)
 
 static void pxa2xx_lcdc_orientation(void *opaque, int angle)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
 
-    if (angle) {
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert;
-    } else {
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz;
+    switch (angle) {
+    case 0:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
+        break;
+    case 90:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
+        break;
+    case 180:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
+        break;
+    case 270:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
+        break;
     }
 
     s->orientation = angle;
@@ -895,74 +918,26 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle)
     pxa2xx_lcdc_resize(s);
 }
 
-static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque)
-{
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
-    int i;
-
-    qemu_put_be32(f, s->irqlevel);
-    qemu_put_be32(f, s->transp);
-
-    for (i = 0; i < 6; i ++)
-        qemu_put_be32s(f, &s->control[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->status[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->ovl1c[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_put_be32s(f, &s->ovl2c[i]);
-    qemu_put_be32s(f, &s->ccr);
-    qemu_put_be32s(f, &s->cmdcr);
-    qemu_put_be32s(f, &s->trgbr);
-    qemu_put_be32s(f, &s->tcr);
-    qemu_put_be32s(f, &s->liidr);
-    qemu_put_8s(f, &s->bscntr);
-
-    for (i = 0; i < 7; i ++) {
-        qemu_put_betl(f, s->dma_ch[i].branch);
-        qemu_put_byte(f, s->dma_ch[i].up);
-        qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
-
-        qemu_put_betl(f, s->dma_ch[i].descriptor);
-        qemu_put_betl(f, s->dma_ch[i].source);
-        qemu_put_be32s(f, &s->dma_ch[i].id);
-        qemu_put_be32s(f, &s->dma_ch[i].command);
+static const VMStateDescription vmstate_dma_channel = {
+    .name = "dma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINTTL(branch, struct DMAChannel),
+        VMSTATE_UINT8(up, struct DMAChannel),
+        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
+        VMSTATE_UINTTL(descriptor, struct DMAChannel),
+        VMSTATE_UINTTL(source, struct DMAChannel),
+        VMSTATE_UINT32(id, struct DMAChannel),
+        VMSTATE_UINT32(command, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
     }
-}
+};
 
-static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
+static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
 {
-    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
-    int i;
-
-    s->irqlevel = qemu_get_be32(f);
-    s->transp = qemu_get_be32(f);
-
-    for (i = 0; i < 6; i ++)
-        qemu_get_be32s(f, &s->control[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->status[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->ovl1c[i]);
-    for (i = 0; i < 2; i ++)
-        qemu_get_be32s(f, &s->ovl2c[i]);
-    qemu_get_be32s(f, &s->ccr);
-    qemu_get_be32s(f, &s->cmdcr);
-    qemu_get_be32s(f, &s->trgbr);
-    qemu_get_be32s(f, &s->tcr);
-    qemu_get_be32s(f, &s->liidr);
-    qemu_get_8s(f, &s->bscntr);
-
-    for (i = 0; i < 7; i ++) {
-        s->dma_ch[i].branch = qemu_get_betl(f);
-        s->dma_ch[i].up = qemu_get_byte(f);
-        qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
-
-        s->dma_ch[i].descriptor = qemu_get_betl(f);
-        s->dma_ch[i].source = qemu_get_betl(f);
-        qemu_get_be32s(f, &s->dma_ch[i].id);
-        qemu_get_be32s(f, &s->dma_ch[i].command);
-    }
+    PXA2xxLCDState *s = opaque;
 
     s->bpp = LCCR3_BPP(s->control[3]);
     s->xres = s->yres = s->pal_for = -1;
@@ -970,6 +945,31 @@ static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
+static const VMStateDescription vmstate_pxa2xx_lcdc = {
+    .name = "pxa2xx_lcdc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_lcdc_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
+        VMSTATE_INT32(transp, PXA2xxLCDState),
+        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
+        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32(ccr, PXA2xxLCDState),
+        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
+        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
+        VMSTATE_UINT32(tcr, PXA2xxLCDState),
+        VMSTATE_UINT32(liidr, PXA2xxLCDState),
+        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
+        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
+                             vmstate_dma_channel, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 #define BITS 8
 #include "pxa2xx_template.h"
 #define BITS 15
@@ -981,26 +981,25 @@ static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
 #define BITS 32
 #include "pxa2xx_template.h"
 
-struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq,
-                DisplayState *ds)
+PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
+                                 target_phys_addr_t base, qemu_irq irq)
 {
-    int iomemtype;
-    struct pxa2xx_lcdc_s *s;
+    PXA2xxLCDState *s;
 
-    s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s));
+    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
     s->invalidated = 1;
     s->irq = irq;
-    s->ds = ds;
+    s->sysmem = sysmem;
 
     pxa2xx_lcdc_orientation(s, graphic_rotate);
 
-    iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn,
-                    pxa2xx_lcdc_writefn, s);
-    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+    memory_region_init_io(&s->iomem, &pxa2xx_lcdc_ops, s,
+                          "pxa2xx-lcd-controller", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
 
-    s->console = graphic_console_init(ds, pxa2xx_update_display,
-                                      pxa2xx_invalidate_display,
-                                      pxa2xx_screen_dump, NULL, s);
+    s->ds = graphic_console_init(pxa2xx_update_display,
+                                 pxa2xx_invalidate_display,
+                                 pxa2xx_screen_dump, NULL, s);
 
     switch (ds_get_bits_per_pixel(s->ds)) {
     case 0:
@@ -1036,13 +1035,12 @@ struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq,
         exit(1);
     }
 
-    register_savevm("pxa2xx_lcdc", 0, 0,
-                    pxa2xx_lcdc_save, pxa2xx_lcdc_load, s);
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
 
     return s;
 }
 
-void pxa2xx_lcd_vsync_notifier(struct pxa2xx_lcdc_s *s, qemu_irq handler)
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
 {
     s->vsync_cb = handler;
 }