]> git.proxmox.com Git - mirror_qemu.git/commitdiff
hw: move display devices to hw/display/, configure via default-configs/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 11:59:04 +0000 (12:59 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 8 Apr 2013 16:13:13 +0000 (18:13 +0200)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
46 files changed:
default-configs/arm-softmmu.mak
default-configs/i386-softmmu.mak
default-configs/lm32-softmmu.mak
default-configs/sh4-softmmu.mak
default-configs/sh4eb-softmmu.mak
default-configs/sparc-softmmu.mak
default-configs/x86_64-softmmu.mak
hw/Makefile.objs
hw/arm/Makefile.objs
hw/blizzard.c [deleted file]
hw/blizzard_template.h
hw/display/Makefile.objs
hw/display/blizzard.c [new file with mode: 0644]
hw/display/exynos4210_fimd.c [new file with mode: 0644]
hw/display/framebuffer.c [new file with mode: 0644]
hw/display/milkymist-tmu2.c [new file with mode: 0644]
hw/display/milkymist-vgafb.c [new file with mode: 0644]
hw/display/omap_dss.c [new file with mode: 0644]
hw/display/omap_lcdc.c [new file with mode: 0644]
hw/display/pxa2xx_lcd.c [new file with mode: 0644]
hw/display/qxl-logger.c [new file with mode: 0644]
hw/display/qxl-render.c [new file with mode: 0644]
hw/display/qxl.c [new file with mode: 0644]
hw/display/sm501.c [new file with mode: 0644]
hw/display/tc6393xb.c [new file with mode: 0644]
hw/display/tcx.c [new file with mode: 0644]
hw/display/vga.c [new file with mode: 0644]
hw/exynos4210_fimd.c [deleted file]
hw/framebuffer.c [deleted file]
hw/i386/Makefile.objs
hw/lm32/Makefile.objs
hw/milkymist-tmu2.c [deleted file]
hw/milkymist-vgafb.c [deleted file]
hw/milkymist-vgafb_template.h
hw/omap_dss.c [deleted file]
hw/omap_lcdc.c [deleted file]
hw/pxa2xx_lcd.c [deleted file]
hw/qxl-logger.c [deleted file]
hw/qxl-render.c [deleted file]
hw/qxl.c [deleted file]
hw/sh4/Makefile.objs
hw/sm501.c [deleted file]
hw/sparc/Makefile.objs
hw/tc6393xb.c [deleted file]
hw/tcx.c [deleted file]
hw/vga.c [deleted file]

index c0e011084b20eeb7dc16e97bcbd5b9b472882ae5..a7dd44a4321af5f0d94780aeb3cb2d732a6e28e2 100644 (file)
@@ -48,8 +48,14 @@ CONFIG_PL310=y
 CONFIG_PL330=y
 CONFIG_CADENCE=y
 CONFIG_XGMAC=y
+CONFIG_EXYNOS4=y
+CONFIG_PXA2XX=y
+CONFIG_FRAMEBUFFER=y
 CONFIG_MARVELL_88W8618=y
+CONFIG_OMAP=y
+CONFIG_BLIZZARD=y
 CONFIG_ONENAND=y
+CONFIG_ZAURUS=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
index 4f0b3f346f0f9dd6d78c2c8cf712f4051d69ecd0..48ed8d4413c8977bf391b17b79bc00c7401677b5 100644 (file)
@@ -3,6 +3,7 @@
 include pci.mak
 include usb.mak
 CONFIG_VGA=y
+CONFIG_QXL=$(CONFIG_SPICE)
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_CIRRUS=y
index 2654ad6e449bec6cee0873d1a97a5437db463ff6..6b2ee430e5620fe8d1e6450c3b519266f5a0aa90 100644 (file)
@@ -1,6 +1,7 @@
 # Default configuration for lm32-softmmu
 
 CONFIG_MILKYMIST=y
+CONFIG_FRAMEBUFFER=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
index 20a05f9f35c396e347573acebf312ccf18a9a87b..f6bf62d1c22a3f8bd3c904a7e76129e12ddeab12 100644 (file)
@@ -8,3 +8,4 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
 CONFIG_SH4=y
 CONFIG_IDE_MMIO=y
+CONFIG_SM501=y
index 875e7e62c2e329ad325bb76c2cfc652353feee8c..c1d513d099becb76ab5fb1958fce75a19c846a2a 100644 (file)
@@ -8,3 +8,4 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
 CONFIG_SH4=y
 CONFIG_IDE_MMIO=y
+CONFIG_SM501=y
index eda87976623cd4e6b6e52260e60fb0f7f08ad586..25bcbe38bc781b50485dfd6210f1f5ef321b600b 100644 (file)
@@ -9,4 +9,5 @@ CONFIG_FDC=y
 CONFIG_EMPTY_SLOT=y
 CONFIG_PCNET_COMMON=y
 CONFIG_LANCE=y
+CONFIG_TCX=y
 CONFIG_CS4231=y
index 6fba70ff7386696e5953558f04476e6d1920a4aa..58b33cfa24ec9677912e0688a6e988fe95d4ebb3 100644 (file)
@@ -3,6 +3,7 @@
 include pci.mak
 include usb.mak
 CONFIG_VGA=y
+CONFIG_QXL=$(CONFIG_SPICE)
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_CIRRUS=y
index 83a6bf2b18b47c13fa7f527df62e4a868e597ceb..eef8742af3ddf773aae3a7057239841d58809ba6 100644 (file)
@@ -31,11 +31,6 @@ obj-y += $(devices-dirs-y)
 
 ifeq ($(CONFIG_SOFTMMU),y)
 
-# Per-target files
-# virtio has to be here due to weird dependency between PCI and virtio-net.
-# need to fix this properly
-obj-$(CONFIG_VGA) += vga.o
-
 # Inter-VM PCI shared memory & VFIO PCI device assignment
 ifeq ($(CONFIG_PCI), y)
 obj-$(CONFIG_KVM) += ivshmem.o
index 6582f5a0aad71d35b79a8300ad2a1b71263062c2..3efefe59cf5e7de621c690267eb3ffb467ec5564 100644 (file)
@@ -5,22 +5,21 @@ obj-y += a9scu.o
 obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-y += exynos4210_gic.o exynos4210_combiner.o
 obj-y += exynos4210_uart.o exynos4210_pwm.o
-obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
+obj-y += exynos4210_pmu.o exynos4210_mct.o
 obj-y += exynos4210_rtc.o exynos4210_i2c.o
 obj-y += arm_mptimer.o a15mpcore.o
 obj-y += armv7m_nvic.o
 obj-y += pxa2xx_timer.o pxa2xx_dma.o
-obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
-obj-y += zaurus.o tc6393xb.o
-obj-y += omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
+obj-y += pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
+obj-y += zaurus.o
+obj-y += omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
                 omap_gpio.o omap_intc.o omap_uart.o
-obj-y += omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
+obj-y += soc_dma.o omap_gptimer.o omap_synctimer.o \
                 omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
 obj-y += tsc210x.o
-obj-y += blizzard.o cbus.o tusb6010.o
+obj-y += cbus.o tusb6010.o
 obj-y += mst_fpga.o
 obj-y += bitbang_i2c.o
-obj-y += framebuffer.o
 obj-y += strongarm.o
 obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
 obj-$(CONFIG_KVM) += kvm/arm_gic.o
diff --git a/hw/blizzard.c b/hw/blizzard.c
deleted file mode 100644 (file)
index bdb0b15..0000000
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "hw/arm/devices.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-
-typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
-
-typedef struct {
-    uint8_t reg;
-    uint32_t addr;
-    int swallow;
-
-    int pll;
-    int pll_range;
-    int pll_ctrl;
-    uint8_t pll_mode;
-    uint8_t clksel;
-    int memenable;
-    int memrefresh;
-    uint8_t timing[3];
-    int priority;
-
-    uint8_t lcd_config;
-    int x;
-    int y;
-    int skipx;
-    int skipy;
-    uint8_t hndp;
-    uint8_t vndp;
-    uint8_t hsync;
-    uint8_t vsync;
-    uint8_t pclk;
-    uint8_t u;
-    uint8_t v;
-    uint8_t yrc[2];
-    int ix[2];
-    int iy[2];
-    int ox[2];
-    int oy[2];
-
-    int enable;
-    int blank;
-    int bpp;
-    int invalidate;
-    int mx[2];
-    int my[2];
-    uint8_t mode;
-    uint8_t effect;
-    uint8_t iformat;
-    uint8_t source;
-    QemuConsole *con;
-    blizzard_fn_t *line_fn_tab[2];
-    void *fb;
-
-    uint8_t hssi_config[3];
-    uint8_t tv_config;
-    uint8_t tv_timing[4];
-    uint8_t vbi;
-    uint8_t tv_x;
-    uint8_t tv_y;
-    uint8_t tv_test;
-    uint8_t tv_filter_config;
-    uint8_t tv_filter_idx;
-    uint8_t tv_filter_coeff[0x20];
-    uint8_t border_r;
-    uint8_t border_g;
-    uint8_t border_b;
-    uint8_t gamma_config;
-    uint8_t gamma_idx;
-    uint8_t gamma_lut[0x100];
-    uint8_t matrix_ena;
-    uint8_t matrix_coeff[0x12];
-    uint8_t matrix_r;
-    uint8_t matrix_g;
-    uint8_t matrix_b;
-    uint8_t pm;
-    uint8_t status;
-    uint8_t rgbgpio_dir;
-    uint8_t rgbgpio;
-    uint8_t gpio_dir;
-    uint8_t gpio;
-    uint8_t gpio_edge[2];
-    uint8_t gpio_irq;
-    uint8_t gpio_pdown;
-
-    struct {
-        int x;
-        int y;
-        int dx;
-        int dy;
-        int len;
-        int buflen;
-        void *buf;
-        void *data;
-        uint16_t *ptr;
-        int angle;
-        int pitch;
-        blizzard_fn_t line_fn;
-    } data;
-} BlizzardState;
-
-/* Bytes(!) per pixel */
-static const int blizzard_iformat_bpp[0x10] = {
-    0,
-    2, /* RGB 5:6:5*/
-    3, /* RGB 6:6:6 mode 1 */
-    3, /* RGB 8:8:8 mode 1 */
-    0, 0,
-    4, /* RGB 6:6:6 mode 2 */
-    4, /* RGB 8:8:8 mode 2 */
-    0, /* YUV 4:2:2 */
-    0, /* YUV 4:2:0 */
-    0, 0, 0, 0, 0, 0,
-};
-
-static inline void blizzard_rgb2yuv(int r, int g, int b,
-                int *y, int *u, int *v)
-{
-    *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
-    *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
-    *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
-}
-
-static void blizzard_window(BlizzardState *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    uint8_t *src, *dst;
-    int bypp[2];
-    int bypl[3];
-    int y;
-    blizzard_fn_t fn = s->data.line_fn;
-
-    if (!fn)
-        return;
-    if (s->mx[0] > s->data.x)
-        s->mx[0] = s->data.x;
-    if (s->my[0] > s->data.y)
-        s->my[0] = s->data.y;
-    if (s->mx[1] < s->data.x + s->data.dx)
-        s->mx[1] = s->data.x + s->data.dx;
-    if (s->my[1] < s->data.y + s->data.dy)
-        s->my[1] = s->data.y + s->data.dy;
-
-    bypp[0] = s->bpp;
-    bypp[1] = surface_bytes_per_pixel(surface);
-    bypl[0] = bypp[0] * s->data.pitch;
-    bypl[1] = bypp[1] * s->x;
-    bypl[2] = bypp[0] * s->data.dx;
-
-    src = s->data.data;
-    dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
-    for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
-        fn(dst, src, bypl[2]);
-}
-
-static int blizzard_transfer_setup(BlizzardState *s)
-{
-    if (s->source > 3 || !s->bpp ||
-                    s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
-        return 0;
-
-    s->data.angle = s->effect & 3;
-    s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
-    s->data.x = s->ix[0];
-    s->data.y = s->iy[0];
-    s->data.dx = s->ix[1] - s->ix[0] + 1;
-    s->data.dy = s->iy[1] - s->iy[0] + 1;
-    s->data.len = s->bpp * s->data.dx * s->data.dy;
-    s->data.pitch = s->data.dx;
-    if (s->data.len > s->data.buflen) {
-        s->data.buf = g_realloc(s->data.buf, s->data.len);
-        s->data.buflen = s->data.len;
-    }
-    s->data.ptr = s->data.buf;
-    s->data.data = s->data.buf;
-    s->data.len /= 2;
-    return 1;
-}
-
-static void blizzard_reset(BlizzardState *s)
-{
-    s->reg = 0;
-    s->swallow = 0;
-
-    s->pll = 9;
-    s->pll_range = 1;
-    s->pll_ctrl = 0x14;
-    s->pll_mode = 0x32;
-    s->clksel = 0x00;
-    s->memenable = 0;
-    s->memrefresh = 0x25c;
-    s->timing[0] = 0x3f;
-    s->timing[1] = 0x13;
-    s->timing[2] = 0x21;
-    s->priority = 0;
-
-    s->lcd_config = 0x74;
-    s->x = 8;
-    s->y = 1;
-    s->skipx = 0;
-    s->skipy = 0;
-    s->hndp = 3;
-    s->vndp = 2;
-    s->hsync = 1;
-    s->vsync = 1;
-    s->pclk = 0x80;
-
-    s->ix[0] = 0;
-    s->ix[1] = 0;
-    s->iy[0] = 0;
-    s->iy[1] = 0;
-    s->ox[0] = 0;
-    s->ox[1] = 0;
-    s->oy[0] = 0;
-    s->oy[1] = 0;
-
-    s->yrc[0] = 0x00;
-    s->yrc[1] = 0x30;
-    s->u = 0;
-    s->v = 0;
-
-    s->iformat = 3;
-    s->source = 0;
-    s->bpp = blizzard_iformat_bpp[s->iformat];
-
-    s->hssi_config[0] = 0x00;
-    s->hssi_config[1] = 0x00;
-    s->hssi_config[2] = 0x01;
-    s->tv_config = 0x00;
-    s->tv_timing[0] = 0x00;
-    s->tv_timing[1] = 0x00;
-    s->tv_timing[2] = 0x00;
-    s->tv_timing[3] = 0x00;
-    s->vbi = 0x10;
-    s->tv_x = 0x14;
-    s->tv_y = 0x03;
-    s->tv_test = 0x00;
-    s->tv_filter_config = 0x80;
-    s->tv_filter_idx = 0x00;
-    s->border_r = 0x10;
-    s->border_g = 0x80;
-    s->border_b = 0x80;
-    s->gamma_config = 0x00;
-    s->gamma_idx = 0x00;
-    s->matrix_ena = 0x00;
-    memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
-    s->matrix_r = 0x00;
-    s->matrix_g = 0x00;
-    s->matrix_b = 0x00;
-    s->pm = 0x02;
-    s->status = 0x00;
-    s->rgbgpio_dir = 0x00;
-    s->gpio_dir = 0x00;
-    s->gpio_edge[0] = 0x00;
-    s->gpio_edge[1] = 0x00;
-    s->gpio_irq = 0x00;
-    s->gpio_pdown = 0xff;
-}
-
-static inline void blizzard_invalidate_display(void *opaque) {
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    s->invalidate = 1;
-}
-
-static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    switch (reg) {
-    case 0x00: /* Revision Code */
-        return 0xa5;
-
-    case 0x02: /* Configuration Readback */
-        return 0x83;   /* Macrovision OK, CNF[2:0] = 3 */
-
-    case 0x04: /* PLL M-Divider */
-        return (s->pll - 1) | (1 << 7);
-    case 0x06: /* PLL Lock Range Control */
-        return s->pll_range;
-    case 0x08: /* PLL Lock Synthesis Control 0 */
-        return s->pll_ctrl & 0xff;
-    case 0x0a: /* PLL Lock Synthesis Control 1 */
-        return s->pll_ctrl >> 8;
-    case 0x0c: /* PLL Mode Control 0 */
-        return s->pll_mode;
-
-    case 0x0e: /* Clock-Source Select */
-        return s->clksel;
-
-    case 0x10: /* Memory Controller Activate */
-    case 0x14: /* Memory Controller Bank 0 Status Flag */
-        return s->memenable;
-
-    case 0x18: /* Auto-Refresh Interval Setting 0 */
-        return s->memrefresh & 0xff;
-    case 0x1a: /* Auto-Refresh Interval Setting 1 */
-        return s->memrefresh >> 8;
-
-    case 0x1c: /* Power-On Sequence Timing Control */
-        return s->timing[0];
-    case 0x1e: /* Timing Control 0 */
-        return s->timing[1];
-    case 0x20: /* Timing Control 1 */
-        return s->timing[2];
-
-    case 0x24: /* Arbitration Priority Control */
-        return s->priority;
-
-    case 0x28: /* LCD Panel Configuration */
-        return s->lcd_config;
-
-    case 0x2a: /* LCD Horizontal Display Width */
-        return s->x >> 3;
-    case 0x2c: /* LCD Horizontal Non-display Period */
-        return s->hndp;
-    case 0x2e: /* LCD Vertical Display Height 0 */
-        return s->y & 0xff;
-    case 0x30: /* LCD Vertical Display Height 1 */
-        return s->y >> 8;
-    case 0x32: /* LCD Vertical Non-display Period */
-        return s->vndp;
-    case 0x34: /* LCD HS Pulse-width */
-        return s->hsync;
-    case 0x36: /* LCd HS Pulse Start Position */
-        return s->skipx >> 3;
-    case 0x38: /* LCD VS Pulse-width */
-        return s->vsync;
-    case 0x3a: /* LCD VS Pulse Start Position */
-        return s->skipy;
-
-    case 0x3c: /* PCLK Polarity */
-        return s->pclk;
-
-    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
-        return s->hssi_config[0];
-    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
-        return s->hssi_config[1];
-    case 0x42: /* High-speed Serial Interface Tx Mode */
-        return s->hssi_config[2];
-    case 0x44: /* TV Display Configuration */
-        return s->tv_config;
-    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits */
-        return s->tv_timing[(reg - 0x46) >> 1];
-    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
-        return s->vbi;
-    case 0x50: /* TV Horizontal Start Position */
-        return s->tv_x;
-    case 0x52: /* TV Vertical Start Position */
-        return s->tv_y;
-    case 0x54: /* TV Test Pattern Setting */
-        return s->tv_test;
-    case 0x56: /* TV Filter Setting */
-        return s->tv_filter_config;
-    case 0x58: /* TV Filter Coefficient Index */
-        return s->tv_filter_idx;
-    case 0x5a: /* TV Filter Coefficient Data */
-        if (s->tv_filter_idx < 0x20)
-            return s->tv_filter_coeff[s->tv_filter_idx ++];
-        return 0;
-
-    case 0x60: /* Input YUV/RGB Translate Mode 0 */
-        return s->yrc[0];
-    case 0x62: /* Input YUV/RGB Translate Mode 1 */
-        return s->yrc[1];
-    case 0x64: /* U Data Fix */
-        return s->u;
-    case 0x66: /* V Data Fix */
-        return s->v;
-
-    case 0x68: /* Display Mode */
-        return s->mode;
-
-    case 0x6a: /* Special Effects */
-        return s->effect;
-
-    case 0x6c: /* Input Window X Start Position 0 */
-        return s->ix[0] & 0xff;
-    case 0x6e: /* Input Window X Start Position 1 */
-        return s->ix[0] >> 3;
-    case 0x70: /* Input Window Y Start Position 0 */
-        return s->ix[0] & 0xff;
-    case 0x72: /* Input Window Y Start Position 1 */
-        return s->ix[0] >> 3;
-    case 0x74: /* Input Window X End Position 0 */
-        return s->ix[1] & 0xff;
-    case 0x76: /* Input Window X End Position 1 */
-        return s->ix[1] >> 3;
-    case 0x78: /* Input Window Y End Position 0 */
-        return s->ix[1] & 0xff;
-    case 0x7a: /* Input Window Y End Position 1 */
-        return s->ix[1] >> 3;
-    case 0x7c: /* Output Window X Start Position 0 */
-        return s->ox[0] & 0xff;
-    case 0x7e: /* Output Window X Start Position 1 */
-        return s->ox[0] >> 3;
-    case 0x80: /* Output Window Y Start Position 0 */
-        return s->oy[0] & 0xff;
-    case 0x82: /* Output Window Y Start Position 1 */
-        return s->oy[0] >> 3;
-    case 0x84: /* Output Window X End Position 0 */
-        return s->ox[1] & 0xff;
-    case 0x86: /* Output Window X End Position 1 */
-        return s->ox[1] >> 3;
-    case 0x88: /* Output Window Y End Position 0 */
-        return s->oy[1] & 0xff;
-    case 0x8a: /* Output Window Y End Position 1 */
-        return s->oy[1] >> 3;
-
-    case 0x8c: /* Input Data Format */
-        return s->iformat;
-    case 0x8e: /* Data Source Select */
-        return s->source;
-    case 0x90: /* Display Memory Data Port */
-        return 0;
-
-    case 0xa8: /* Border Color 0 */
-        return s->border_r;
-    case 0xaa: /* Border Color 1 */
-        return s->border_g;
-    case 0xac: /* Border Color 2 */
-        return s->border_b;
-
-    case 0xb4: /* Gamma Correction Enable */
-        return s->gamma_config;
-    case 0xb6: /* Gamma Correction Table Index */
-        return s->gamma_idx;
-    case 0xb8: /* Gamma Correction Table Data */
-        return s->gamma_lut[s->gamma_idx ++];
-
-    case 0xba: /* 3x3 Matrix Enable */
-        return s->matrix_ena;
-    case 0xbc ... 0xde:        /* Coefficient Registers */
-        return s->matrix_coeff[(reg - 0xbc) >> 1];
-    case 0xe0: /* 3x3 Matrix Red Offset */
-        return s->matrix_r;
-    case 0xe2: /* 3x3 Matrix Green Offset */
-        return s->matrix_g;
-    case 0xe4: /* 3x3 Matrix Blue Offset */
-        return s->matrix_b;
-
-    case 0xe6: /* Power-save */
-        return s->pm;
-    case 0xe8: /* Non-display Period Control / Status */
-        return s->status | (1 << 5);
-    case 0xea: /* RGB Interface Control */
-        return s->rgbgpio_dir;
-    case 0xec: /* RGB Interface Status */
-        return s->rgbgpio;
-    case 0xee: /* General-purpose IO Pins Configuration */
-        return s->gpio_dir;
-    case 0xf0: /* General-purpose IO Pins Status / Control */
-        return s->gpio;
-    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
-        return s->gpio_edge[0];
-    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
-        return s->gpio_edge[1];
-    case 0xf6: /* GPIO Interrupt Status */
-        return s->gpio_irq;
-    case 0xf8: /* GPIO Pull-down Control */
-        return s->gpio_pdown;
-
-    default:
-        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
-        return 0;
-    }
-}
-
-static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    switch (reg) {
-    case 0x04: /* PLL M-Divider */
-        s->pll = (value & 0x3f) + 1;
-        break;
-    case 0x06: /* PLL Lock Range Control */
-        s->pll_range = value & 3;
-        break;
-    case 0x08: /* PLL Lock Synthesis Control 0 */
-        s->pll_ctrl &= 0xf00;
-        s->pll_ctrl |= (value << 0) & 0x0ff;
-        break;
-    case 0x0a: /* PLL Lock Synthesis Control 1 */
-        s->pll_ctrl &= 0x0ff;
-        s->pll_ctrl |= (value << 8) & 0xf00;
-        break;
-    case 0x0c: /* PLL Mode Control 0 */
-        s->pll_mode = value & 0x77;
-        if ((value & 3) == 0 || (value & 3) == 3)
-            fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
-                    __FUNCTION__, value & 3);
-        break;
-
-    case 0x0e: /* Clock-Source Select */
-        s->clksel = value & 0xff;
-        break;
-
-    case 0x10: /* Memory Controller Activate */
-        s->memenable = value & 1;
-        break;
-    case 0x14: /* Memory Controller Bank 0 Status Flag */
-        break;
-
-    case 0x18: /* Auto-Refresh Interval Setting 0 */
-        s->memrefresh &= 0xf00;
-        s->memrefresh |= (value << 0) & 0x0ff;
-        break;
-    case 0x1a: /* Auto-Refresh Interval Setting 1 */
-        s->memrefresh &= 0x0ff;
-        s->memrefresh |= (value << 8) & 0xf00;
-        break;
-
-    case 0x1c: /* Power-On Sequence Timing Control */
-        s->timing[0] = value & 0x7f;
-        break;
-    case 0x1e: /* Timing Control 0 */
-        s->timing[1] = value & 0x17;
-        break;
-    case 0x20: /* Timing Control 1 */
-        s->timing[2] = value & 0x35;
-        break;
-
-    case 0x24: /* Arbitration Priority Control */
-        s->priority = value & 1;
-        break;
-
-    case 0x28: /* LCD Panel Configuration */
-        s->lcd_config = value & 0xff;
-        if (value & (1 << 7))
-            fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
-        break;
-
-    case 0x2a: /* LCD Horizontal Display Width */
-        s->x = value << 3;
-        break;
-    case 0x2c: /* LCD Horizontal Non-display Period */
-        s->hndp = value & 0xff;
-        break;
-    case 0x2e: /* LCD Vertical Display Height 0 */
-        s->y &= 0x300;
-        s->y |= (value << 0) & 0x0ff;
-        break;
-    case 0x30: /* LCD Vertical Display Height 1 */
-        s->y &= 0x0ff;
-        s->y |= (value << 8) & 0x300;
-        break;
-    case 0x32: /* LCD Vertical Non-display Period */
-        s->vndp = value & 0xff;
-        break;
-    case 0x34: /* LCD HS Pulse-width */
-        s->hsync = value & 0xff;
-        break;
-    case 0x36: /* LCD HS Pulse Start Position */
-        s->skipx = value & 0xff;
-        break;
-    case 0x38: /* LCD VS Pulse-width */
-        s->vsync = value & 0xbf;
-        break;
-    case 0x3a: /* LCD VS Pulse Start Position */
-        s->skipy = value & 0xff;
-        break;
-
-    case 0x3c: /* PCLK Polarity */
-        s->pclk = value & 0x82;
-        /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
-        break;
-
-    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
-        s->hssi_config[0] = value;
-        break;
-    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
-        s->hssi_config[1] = value;
-        if (((value >> 4) & 3) == 3)
-            fprintf(stderr, "%s: Illegal active-data-links value\n",
-                            __FUNCTION__);
-        break;
-    case 0x42: /* High-speed Serial Interface Tx Mode */
-        s->hssi_config[2] = value & 0xbd;
-        break;
-
-    case 0x44: /* TV Display Configuration */
-        s->tv_config = value & 0xfe;
-        break;
-    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits 0 */
-        s->tv_timing[(reg - 0x46) >> 1] = value;
-        break;
-    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
-        s->vbi = value;
-        break;
-    case 0x50: /* TV Horizontal Start Position */
-        s->tv_x = value;
-        break;
-    case 0x52: /* TV Vertical Start Position */
-        s->tv_y = value & 0x7f;
-        break;
-    case 0x54: /* TV Test Pattern Setting */
-        s->tv_test = value;
-        break;
-    case 0x56: /* TV Filter Setting */
-        s->tv_filter_config = value & 0xbf;
-        break;
-    case 0x58: /* TV Filter Coefficient Index */
-        s->tv_filter_idx = value & 0x1f;
-        break;
-    case 0x5a: /* TV Filter Coefficient Data */
-        if (s->tv_filter_idx < 0x20)
-            s->tv_filter_coeff[s->tv_filter_idx ++] = value;
-        break;
-
-    case 0x60: /* Input YUV/RGB Translate Mode 0 */
-        s->yrc[0] = value & 0xb0;
-        break;
-    case 0x62: /* Input YUV/RGB Translate Mode 1 */
-        s->yrc[1] = value & 0x30;
-        break;
-    case 0x64: /* U Data Fix */
-        s->u = value & 0xff;
-        break;
-    case 0x66: /* V Data Fix */
-        s->v = value & 0xff;
-        break;
-
-    case 0x68: /* Display Mode */
-        if ((s->mode ^ value) & 3)
-            s->invalidate = 1;
-        s->mode = value & 0xb7;
-        s->enable = value & 1;
-        s->blank = (value >> 1) & 1;
-        if (value & (1 << 4))
-            fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
-        break;
-
-    case 0x6a: /* Special Effects */
-        s->effect = value & 0xfb;
-        break;
-
-    case 0x6c: /* Input Window X Start Position 0 */
-        s->ix[0] &= 0x300;
-        s->ix[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x6e: /* Input Window X Start Position 1 */
-        s->ix[0] &= 0x0ff;
-        s->ix[0] |= (value << 8) & 0x300;
-        break;
-    case 0x70: /* Input Window Y Start Position 0 */
-        s->iy[0] &= 0x300;
-        s->iy[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x72: /* Input Window Y Start Position 1 */
-        s->iy[0] &= 0x0ff;
-        s->iy[0] |= (value << 8) & 0x300;
-        break;
-    case 0x74: /* Input Window X End Position 0 */
-        s->ix[1] &= 0x300;
-        s->ix[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x76: /* Input Window X End Position 1 */
-        s->ix[1] &= 0x0ff;
-        s->ix[1] |= (value << 8) & 0x300;
-        break;
-    case 0x78: /* Input Window Y End Position 0 */
-        s->iy[1] &= 0x300;
-        s->iy[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x7a: /* Input Window Y End Position 1 */
-        s->iy[1] &= 0x0ff;
-        s->iy[1] |= (value << 8) & 0x300;
-        break;
-    case 0x7c: /* Output Window X Start Position 0 */
-        s->ox[0] &= 0x300;
-        s->ox[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x7e: /* Output Window X Start Position 1 */
-        s->ox[0] &= 0x0ff;
-        s->ox[0] |= (value << 8) & 0x300;
-        break;
-    case 0x80: /* Output Window Y Start Position 0 */
-        s->oy[0] &= 0x300;
-        s->oy[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x82: /* Output Window Y Start Position 1 */
-        s->oy[0] &= 0x0ff;
-        s->oy[0] |= (value << 8) & 0x300;
-        break;
-    case 0x84: /* Output Window X End Position 0 */
-        s->ox[1] &= 0x300;
-        s->ox[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x86: /* Output Window X End Position 1 */
-        s->ox[1] &= 0x0ff;
-        s->ox[1] |= (value << 8) & 0x300;
-        break;
-    case 0x88: /* Output Window Y End Position 0 */
-        s->oy[1] &= 0x300;
-        s->oy[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x8a: /* Output Window Y End Position 1 */
-        s->oy[1] &= 0x0ff;
-        s->oy[1] |= (value << 8) & 0x300;
-        break;
-
-    case 0x8c: /* Input Data Format */
-        s->iformat = value & 0xf;
-        s->bpp = blizzard_iformat_bpp[s->iformat];
-        if (!s->bpp)
-            fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
-                            __FUNCTION__, s->iformat);
-        break;
-    case 0x8e: /* Data Source Select */
-        s->source = value & 7;
-        /* Currently all windows will be "destructive overlays".  */
-        if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
-                                        s->iy[0] != s->oy[0] ||
-                                        s->ix[1] != s->ox[1] ||
-                                        s->iy[1] != s->oy[1])) ||
-                        !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
-                          (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
-            fprintf(stderr, "%s: Illegal input/output window positions\n",
-                            __FUNCTION__);
-
-        blizzard_transfer_setup(s);
-        break;
-
-    case 0x90: /* Display Memory Data Port */
-        if (!s->data.len && !blizzard_transfer_setup(s))
-            break;
-
-        *s->data.ptr ++ = value;
-        if (-- s->data.len == 0)
-            blizzard_window(s);
-        break;
-
-    case 0xa8: /* Border Color 0 */
-        s->border_r = value;
-        break;
-    case 0xaa: /* Border Color 1 */
-        s->border_g = value;
-        break;
-    case 0xac: /* Border Color 2 */
-        s->border_b = value;
-        break;
-
-    case 0xb4: /* Gamma Correction Enable */
-        s->gamma_config = value & 0x87;
-        break;
-    case 0xb6: /* Gamma Correction Table Index */
-        s->gamma_idx = value;
-        break;
-    case 0xb8: /* Gamma Correction Table Data */
-        s->gamma_lut[s->gamma_idx ++] = value;
-        break;
-
-    case 0xba: /* 3x3 Matrix Enable */
-        s->matrix_ena = value & 1;
-        break;
-    case 0xbc ... 0xde:        /* Coefficient Registers */
-        s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
-        break;
-    case 0xe0: /* 3x3 Matrix Red Offset */
-        s->matrix_r = value;
-        break;
-    case 0xe2: /* 3x3 Matrix Green Offset */
-        s->matrix_g = value;
-        break;
-    case 0xe4: /* 3x3 Matrix Blue Offset */
-        s->matrix_b = value;
-        break;
-
-    case 0xe6: /* Power-save */
-        s->pm = value & 0x83;
-        if (value & s->mode & 1)
-            fprintf(stderr, "%s: The display must be disabled before entering "
-                            "Standby Mode\n", __FUNCTION__);
-        break;
-    case 0xe8: /* Non-display Period Control / Status */
-        s->status = value & 0x1b;
-        break;
-    case 0xea: /* RGB Interface Control */
-        s->rgbgpio_dir = value & 0x8f;
-        break;
-    case 0xec: /* RGB Interface Status */
-        s->rgbgpio = value & 0xcf;
-        break;
-    case 0xee: /* General-purpose IO Pins Configuration */
-        s->gpio_dir = value;
-        break;
-    case 0xf0: /* General-purpose IO Pins Status / Control */
-        s->gpio = value;
-        break;
-    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
-        s->gpio_edge[0] = value;
-        break;
-    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
-        s->gpio_edge[1] = value;
-        break;
-    case 0xf6: /* GPIO Interrupt Status */
-        s->gpio_irq &= value;
-        break;
-    case 0xf8: /* GPIO Pull-down Control */
-        s->gpio_pdown = value;
-        break;
-
-    default:
-        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
-        break;
-    }
-}
-
-uint16_t s1d13745_read(void *opaque, int dc)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    uint16_t value = blizzard_reg_read(s, s->reg);
-
-    if (s->swallow -- > 0)
-        return 0;
-    if (dc)
-        s->reg ++;
-
-    return value;
-}
-
-void s1d13745_write(void *opaque, int dc, uint16_t value)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    if (s->swallow -- > 0)
-        return;
-    if (dc) {
-        blizzard_reg_write(s, s->reg, value);
-
-        if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
-            s->reg += 2;
-    } else
-        s->reg = value & 0xff;
-}
-
-void s1d13745_write_block(void *opaque, int dc,
-                void *buf, size_t len, int pitch)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    while (len > 0) {
-        if (s->reg == 0x90 && dc &&
-                        (s->data.len || blizzard_transfer_setup(s)) &&
-                        len >= (s->data.len << 1)) {
-            len -= s->data.len << 1;
-            s->data.len = 0;
-            s->data.data = buf;
-            if (pitch)
-                s->data.pitch = pitch;
-            blizzard_window(s);
-            s->data.data = s->data.buf;
-            continue;
-        }
-
-        s1d13745_write(opaque, dc, *(uint16_t *) buf);
-        len -= 2;
-        buf += 2;
-    }
-}
-
-static void blizzard_update_display(void *opaque)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y, bypp, bypl, bwidth;
-    uint8_t *src, *dst;
-
-    if (!s->enable)
-        return;
-
-    if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
-        s->invalidate = 1;
-        qemu_console_resize(s->con, s->x, s->y);
-        surface = qemu_console_surface(s->con);
-    }
-
-    if (s->invalidate) {
-        s->invalidate = 0;
-
-        if (s->blank) {
-            bypp = surface_bytes_per_pixel(surface);
-            memset(surface_data(surface), 0, bypp * s->x * s->y);
-            return;
-        }
-
-        s->mx[0] = 0;
-        s->mx[1] = s->x;
-        s->my[0] = 0;
-        s->my[1] = s->y;
-    }
-
-    if (s->mx[1] <= s->mx[0])
-        return;
-
-    bypp = surface_bytes_per_pixel(surface);
-    bypl = bypp * s->x;
-    bwidth = bypp * (s->mx[1] - s->mx[0]);
-    y = s->my[0];
-    src = s->fb + bypl * y + bypp * s->mx[0];
-    dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
-    for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
-        memcpy(dst, src, bwidth);
-
-    dpy_gfx_update(s->con, s->mx[0], s->my[0],
-                   s->mx[1] - s->mx[0], y - s->my[0]);
-
-    s->mx[0] = s->x;
-    s->mx[1] = 0;
-    s->my[0] = s->y;
-    s->my[1] = 0;
-}
-
-static void blizzard_screen_dump(void *opaque, const char *filename,
-                                 bool cswitch, Error **errp)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    blizzard_update_display(opaque);
-    if (s && surface_data(surface)) {
-        ppm_save(filename, surface, errp);
-    }
-}
-
-#define DEPTH 8
-#include "hw/blizzard_template.h"
-#define DEPTH 15
-#include "hw/blizzard_template.h"
-#define DEPTH 16
-#include "hw/blizzard_template.h"
-#define DEPTH 24
-#include "hw/blizzard_template.h"
-#define DEPTH 32
-#include "hw/blizzard_template.h"
-
-void *s1d13745_init(qemu_irq gpio_int)
-{
-    BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
-    DisplaySurface *surface;
-
-    s->fb = g_malloc(0x180000);
-
-    s->con = graphic_console_init(blizzard_update_display,
-                                  blizzard_invalidate_display,
-                                  blizzard_screen_dump, NULL, s);
-    surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        s->line_fn_tab[0] = s->line_fn_tab[1] =
-                g_malloc0(sizeof(blizzard_fn_t) * 0x10);
-        break;
-    case 8:
-        s->line_fn_tab[0] = blizzard_draw_fn_8;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_8;
-        break;
-    case 15:
-        s->line_fn_tab[0] = blizzard_draw_fn_15;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_15;
-        break;
-    case 16:
-        s->line_fn_tab[0] = blizzard_draw_fn_16;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_16;
-        break;
-    case 24:
-        s->line_fn_tab[0] = blizzard_draw_fn_24;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_24;
-        break;
-    case 32:
-        s->line_fn_tab[0] = blizzard_draw_fn_32;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_32;
-        break;
-    default:
-        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
-        exit(1);
-    }
-
-    blizzard_reset(s);
-
-    return s;
-}
index 42f4e90b04a2a4daca310b3946abfa28dfc2c98c..a8a8899478ee0bc0f122a5a72be2c926b5624780 100644 (file)
@@ -55,7 +55,7 @@ static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
     unsigned int r, g, b;
     const uint16_t *end = (const void *) src + width;
     while (src < end) {
-        data = lduw_raw(src ++);
+        data = *src ++;
         b = (data & 0x1f) << 3;
         data >>= 5;
         g = (data & 0x3f) << 2;
index 3ac154d708279201f65146443f0262de2b5125e4..3f7027d46b63b70f4980179c78ee6bf578991678 100644 (file)
@@ -11,3 +11,24 @@ common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
 common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
 common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
 common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
+
+common-obj-$(CONFIG_BLIZZARD) += blizzard.o
+common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
+common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
+common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
+
+ifeq ($(CONFIG_GLX),y)
+common-obj-$(CONFIG_MILKYMIST) += milkymist-tmu2.o
+endif
+
+obj-$(CONFIG_OMAP) += omap_dss.o
+obj-$(CONFIG_OMAP) += omap_lcdc.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
+obj-$(CONFIG_SM501) += sm501.o
+obj-$(CONFIG_TCX) += tcx.o
+
+obj-$(CONFIG_VGA) += vga.o
+
+common-obj-$(CONFIG_QXL) += qxl-logger.o qxl-render.o
+obj-$(CONFIG_QXL) += qxl.o
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
new file mode 100644 (file)
index 0000000..bdb0b15
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "hw/arm/devices.h"
+#include "hw/vga_int.h"
+#include "ui/pixel_ops.h"
+
+typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
+
+typedef struct {
+    uint8_t reg;
+    uint32_t addr;
+    int swallow;
+
+    int pll;
+    int pll_range;
+    int pll_ctrl;
+    uint8_t pll_mode;
+    uint8_t clksel;
+    int memenable;
+    int memrefresh;
+    uint8_t timing[3];
+    int priority;
+
+    uint8_t lcd_config;
+    int x;
+    int y;
+    int skipx;
+    int skipy;
+    uint8_t hndp;
+    uint8_t vndp;
+    uint8_t hsync;
+    uint8_t vsync;
+    uint8_t pclk;
+    uint8_t u;
+    uint8_t v;
+    uint8_t yrc[2];
+    int ix[2];
+    int iy[2];
+    int ox[2];
+    int oy[2];
+
+    int enable;
+    int blank;
+    int bpp;
+    int invalidate;
+    int mx[2];
+    int my[2];
+    uint8_t mode;
+    uint8_t effect;
+    uint8_t iformat;
+    uint8_t source;
+    QemuConsole *con;
+    blizzard_fn_t *line_fn_tab[2];
+    void *fb;
+
+    uint8_t hssi_config[3];
+    uint8_t tv_config;
+    uint8_t tv_timing[4];
+    uint8_t vbi;
+    uint8_t tv_x;
+    uint8_t tv_y;
+    uint8_t tv_test;
+    uint8_t tv_filter_config;
+    uint8_t tv_filter_idx;
+    uint8_t tv_filter_coeff[0x20];
+    uint8_t border_r;
+    uint8_t border_g;
+    uint8_t border_b;
+    uint8_t gamma_config;
+    uint8_t gamma_idx;
+    uint8_t gamma_lut[0x100];
+    uint8_t matrix_ena;
+    uint8_t matrix_coeff[0x12];
+    uint8_t matrix_r;
+    uint8_t matrix_g;
+    uint8_t matrix_b;
+    uint8_t pm;
+    uint8_t status;
+    uint8_t rgbgpio_dir;
+    uint8_t rgbgpio;
+    uint8_t gpio_dir;
+    uint8_t gpio;
+    uint8_t gpio_edge[2];
+    uint8_t gpio_irq;
+    uint8_t gpio_pdown;
+
+    struct {
+        int x;
+        int y;
+        int dx;
+        int dy;
+        int len;
+        int buflen;
+        void *buf;
+        void *data;
+        uint16_t *ptr;
+        int angle;
+        int pitch;
+        blizzard_fn_t line_fn;
+    } data;
+} BlizzardState;
+
+/* Bytes(!) per pixel */
+static const int blizzard_iformat_bpp[0x10] = {
+    0,
+    2, /* RGB 5:6:5*/
+    3, /* RGB 6:6:6 mode 1 */
+    3, /* RGB 8:8:8 mode 1 */
+    0, 0,
+    4, /* RGB 6:6:6 mode 2 */
+    4, /* RGB 8:8:8 mode 2 */
+    0, /* YUV 4:2:2 */
+    0, /* YUV 4:2:0 */
+    0, 0, 0, 0, 0, 0,
+};
+
+static inline void blizzard_rgb2yuv(int r, int g, int b,
+                int *y, int *u, int *v)
+{
+    *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
+    *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
+    *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
+}
+
+static void blizzard_window(BlizzardState *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    uint8_t *src, *dst;
+    int bypp[2];
+    int bypl[3];
+    int y;
+    blizzard_fn_t fn = s->data.line_fn;
+
+    if (!fn)
+        return;
+    if (s->mx[0] > s->data.x)
+        s->mx[0] = s->data.x;
+    if (s->my[0] > s->data.y)
+        s->my[0] = s->data.y;
+    if (s->mx[1] < s->data.x + s->data.dx)
+        s->mx[1] = s->data.x + s->data.dx;
+    if (s->my[1] < s->data.y + s->data.dy)
+        s->my[1] = s->data.y + s->data.dy;
+
+    bypp[0] = s->bpp;
+    bypp[1] = surface_bytes_per_pixel(surface);
+    bypl[0] = bypp[0] * s->data.pitch;
+    bypl[1] = bypp[1] * s->x;
+    bypl[2] = bypp[0] * s->data.dx;
+
+    src = s->data.data;
+    dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
+    for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
+        fn(dst, src, bypl[2]);
+}
+
+static int blizzard_transfer_setup(BlizzardState *s)
+{
+    if (s->source > 3 || !s->bpp ||
+                    s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
+        return 0;
+
+    s->data.angle = s->effect & 3;
+    s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
+    s->data.x = s->ix[0];
+    s->data.y = s->iy[0];
+    s->data.dx = s->ix[1] - s->ix[0] + 1;
+    s->data.dy = s->iy[1] - s->iy[0] + 1;
+    s->data.len = s->bpp * s->data.dx * s->data.dy;
+    s->data.pitch = s->data.dx;
+    if (s->data.len > s->data.buflen) {
+        s->data.buf = g_realloc(s->data.buf, s->data.len);
+        s->data.buflen = s->data.len;
+    }
+    s->data.ptr = s->data.buf;
+    s->data.data = s->data.buf;
+    s->data.len /= 2;
+    return 1;
+}
+
+static void blizzard_reset(BlizzardState *s)
+{
+    s->reg = 0;
+    s->swallow = 0;
+
+    s->pll = 9;
+    s->pll_range = 1;
+    s->pll_ctrl = 0x14;
+    s->pll_mode = 0x32;
+    s->clksel = 0x00;
+    s->memenable = 0;
+    s->memrefresh = 0x25c;
+    s->timing[0] = 0x3f;
+    s->timing[1] = 0x13;
+    s->timing[2] = 0x21;
+    s->priority = 0;
+
+    s->lcd_config = 0x74;
+    s->x = 8;
+    s->y = 1;
+    s->skipx = 0;
+    s->skipy = 0;
+    s->hndp = 3;
+    s->vndp = 2;
+    s->hsync = 1;
+    s->vsync = 1;
+    s->pclk = 0x80;
+
+    s->ix[0] = 0;
+    s->ix[1] = 0;
+    s->iy[0] = 0;
+    s->iy[1] = 0;
+    s->ox[0] = 0;
+    s->ox[1] = 0;
+    s->oy[0] = 0;
+    s->oy[1] = 0;
+
+    s->yrc[0] = 0x00;
+    s->yrc[1] = 0x30;
+    s->u = 0;
+    s->v = 0;
+
+    s->iformat = 3;
+    s->source = 0;
+    s->bpp = blizzard_iformat_bpp[s->iformat];
+
+    s->hssi_config[0] = 0x00;
+    s->hssi_config[1] = 0x00;
+    s->hssi_config[2] = 0x01;
+    s->tv_config = 0x00;
+    s->tv_timing[0] = 0x00;
+    s->tv_timing[1] = 0x00;
+    s->tv_timing[2] = 0x00;
+    s->tv_timing[3] = 0x00;
+    s->vbi = 0x10;
+    s->tv_x = 0x14;
+    s->tv_y = 0x03;
+    s->tv_test = 0x00;
+    s->tv_filter_config = 0x80;
+    s->tv_filter_idx = 0x00;
+    s->border_r = 0x10;
+    s->border_g = 0x80;
+    s->border_b = 0x80;
+    s->gamma_config = 0x00;
+    s->gamma_idx = 0x00;
+    s->matrix_ena = 0x00;
+    memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
+    s->matrix_r = 0x00;
+    s->matrix_g = 0x00;
+    s->matrix_b = 0x00;
+    s->pm = 0x02;
+    s->status = 0x00;
+    s->rgbgpio_dir = 0x00;
+    s->gpio_dir = 0x00;
+    s->gpio_edge[0] = 0x00;
+    s->gpio_edge[1] = 0x00;
+    s->gpio_irq = 0x00;
+    s->gpio_pdown = 0xff;
+}
+
+static inline void blizzard_invalidate_display(void *opaque) {
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    s->invalidate = 1;
+}
+
+static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x00: /* Revision Code */
+        return 0xa5;
+
+    case 0x02: /* Configuration Readback */
+        return 0x83;   /* Macrovision OK, CNF[2:0] = 3 */
+
+    case 0x04: /* PLL M-Divider */
+        return (s->pll - 1) | (1 << 7);
+    case 0x06: /* PLL Lock Range Control */
+        return s->pll_range;
+    case 0x08: /* PLL Lock Synthesis Control 0 */
+        return s->pll_ctrl & 0xff;
+    case 0x0a: /* PLL Lock Synthesis Control 1 */
+        return s->pll_ctrl >> 8;
+    case 0x0c: /* PLL Mode Control 0 */
+        return s->pll_mode;
+
+    case 0x0e: /* Clock-Source Select */
+        return s->clksel;
+
+    case 0x10: /* Memory Controller Activate */
+    case 0x14: /* Memory Controller Bank 0 Status Flag */
+        return s->memenable;
+
+    case 0x18: /* Auto-Refresh Interval Setting 0 */
+        return s->memrefresh & 0xff;
+    case 0x1a: /* Auto-Refresh Interval Setting 1 */
+        return s->memrefresh >> 8;
+
+    case 0x1c: /* Power-On Sequence Timing Control */
+        return s->timing[0];
+    case 0x1e: /* Timing Control 0 */
+        return s->timing[1];
+    case 0x20: /* Timing Control 1 */
+        return s->timing[2];
+
+    case 0x24: /* Arbitration Priority Control */
+        return s->priority;
+
+    case 0x28: /* LCD Panel Configuration */
+        return s->lcd_config;
+
+    case 0x2a: /* LCD Horizontal Display Width */
+        return s->x >> 3;
+    case 0x2c: /* LCD Horizontal Non-display Period */
+        return s->hndp;
+    case 0x2e: /* LCD Vertical Display Height 0 */
+        return s->y & 0xff;
+    case 0x30: /* LCD Vertical Display Height 1 */
+        return s->y >> 8;
+    case 0x32: /* LCD Vertical Non-display Period */
+        return s->vndp;
+    case 0x34: /* LCD HS Pulse-width */
+        return s->hsync;
+    case 0x36: /* LCd HS Pulse Start Position */
+        return s->skipx >> 3;
+    case 0x38: /* LCD VS Pulse-width */
+        return s->vsync;
+    case 0x3a: /* LCD VS Pulse Start Position */
+        return s->skipy;
+
+    case 0x3c: /* PCLK Polarity */
+        return s->pclk;
+
+    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
+        return s->hssi_config[0];
+    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
+        return s->hssi_config[1];
+    case 0x42: /* High-speed Serial Interface Tx Mode */
+        return s->hssi_config[2];
+    case 0x44: /* TV Display Configuration */
+        return s->tv_config;
+    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits */
+        return s->tv_timing[(reg - 0x46) >> 1];
+    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
+        return s->vbi;
+    case 0x50: /* TV Horizontal Start Position */
+        return s->tv_x;
+    case 0x52: /* TV Vertical Start Position */
+        return s->tv_y;
+    case 0x54: /* TV Test Pattern Setting */
+        return s->tv_test;
+    case 0x56: /* TV Filter Setting */
+        return s->tv_filter_config;
+    case 0x58: /* TV Filter Coefficient Index */
+        return s->tv_filter_idx;
+    case 0x5a: /* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            return s->tv_filter_coeff[s->tv_filter_idx ++];
+        return 0;
+
+    case 0x60: /* Input YUV/RGB Translate Mode 0 */
+        return s->yrc[0];
+    case 0x62: /* Input YUV/RGB Translate Mode 1 */
+        return s->yrc[1];
+    case 0x64: /* U Data Fix */
+        return s->u;
+    case 0x66: /* V Data Fix */
+        return s->v;
+
+    case 0x68: /* Display Mode */
+        return s->mode;
+
+    case 0x6a: /* Special Effects */
+        return s->effect;
+
+    case 0x6c: /* Input Window X Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x6e: /* Input Window X Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x70: /* Input Window Y Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x72: /* Input Window Y Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x74: /* Input Window X End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x76: /* Input Window X End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x78: /* Input Window Y End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x7a: /* Input Window Y End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x7c: /* Output Window X Start Position 0 */
+        return s->ox[0] & 0xff;
+    case 0x7e: /* Output Window X Start Position 1 */
+        return s->ox[0] >> 3;
+    case 0x80: /* Output Window Y Start Position 0 */
+        return s->oy[0] & 0xff;
+    case 0x82: /* Output Window Y Start Position 1 */
+        return s->oy[0] >> 3;
+    case 0x84: /* Output Window X End Position 0 */
+        return s->ox[1] & 0xff;
+    case 0x86: /* Output Window X End Position 1 */
+        return s->ox[1] >> 3;
+    case 0x88: /* Output Window Y End Position 0 */
+        return s->oy[1] & 0xff;
+    case 0x8a: /* Output Window Y End Position 1 */
+        return s->oy[1] >> 3;
+
+    case 0x8c: /* Input Data Format */
+        return s->iformat;
+    case 0x8e: /* Data Source Select */
+        return s->source;
+    case 0x90: /* Display Memory Data Port */
+        return 0;
+
+    case 0xa8: /* Border Color 0 */
+        return s->border_r;
+    case 0xaa: /* Border Color 1 */
+        return s->border_g;
+    case 0xac: /* Border Color 2 */
+        return s->border_b;
+
+    case 0xb4: /* Gamma Correction Enable */
+        return s->gamma_config;
+    case 0xb6: /* Gamma Correction Table Index */
+        return s->gamma_idx;
+    case 0xb8: /* Gamma Correction Table Data */
+        return s->gamma_lut[s->gamma_idx ++];
+
+    case 0xba: /* 3x3 Matrix Enable */
+        return s->matrix_ena;
+    case 0xbc ... 0xde:        /* Coefficient Registers */
+        return s->matrix_coeff[(reg - 0xbc) >> 1];
+    case 0xe0: /* 3x3 Matrix Red Offset */
+        return s->matrix_r;
+    case 0xe2: /* 3x3 Matrix Green Offset */
+        return s->matrix_g;
+    case 0xe4: /* 3x3 Matrix Blue Offset */
+        return s->matrix_b;
+
+    case 0xe6: /* Power-save */
+        return s->pm;
+    case 0xe8: /* Non-display Period Control / Status */
+        return s->status | (1 << 5);
+    case 0xea: /* RGB Interface Control */
+        return s->rgbgpio_dir;
+    case 0xec: /* RGB Interface Status */
+        return s->rgbgpio;
+    case 0xee: /* General-purpose IO Pins Configuration */
+        return s->gpio_dir;
+    case 0xf0: /* General-purpose IO Pins Status / Control */
+        return s->gpio;
+    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
+        return s->gpio_edge[0];
+    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
+        return s->gpio_edge[1];
+    case 0xf6: /* GPIO Interrupt Status */
+        return s->gpio_irq;
+    case 0xf8: /* GPIO Pull-down Control */
+        return s->gpio_pdown;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        return 0;
+    }
+}
+
+static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x04: /* PLL M-Divider */
+        s->pll = (value & 0x3f) + 1;
+        break;
+    case 0x06: /* PLL Lock Range Control */
+        s->pll_range = value & 3;
+        break;
+    case 0x08: /* PLL Lock Synthesis Control 0 */
+        s->pll_ctrl &= 0xf00;
+        s->pll_ctrl |= (value << 0) & 0x0ff;
+        break;
+    case 0x0a: /* PLL Lock Synthesis Control 1 */
+        s->pll_ctrl &= 0x0ff;
+        s->pll_ctrl |= (value << 8) & 0xf00;
+        break;
+    case 0x0c: /* PLL Mode Control 0 */
+        s->pll_mode = value & 0x77;
+        if ((value & 3) == 0 || (value & 3) == 3)
+            fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
+                    __FUNCTION__, value & 3);
+        break;
+
+    case 0x0e: /* Clock-Source Select */
+        s->clksel = value & 0xff;
+        break;
+
+    case 0x10: /* Memory Controller Activate */
+        s->memenable = value & 1;
+        break;
+    case 0x14: /* Memory Controller Bank 0 Status Flag */
+        break;
+
+    case 0x18: /* Auto-Refresh Interval Setting 0 */
+        s->memrefresh &= 0xf00;
+        s->memrefresh |= (value << 0) & 0x0ff;
+        break;
+    case 0x1a: /* Auto-Refresh Interval Setting 1 */
+        s->memrefresh &= 0x0ff;
+        s->memrefresh |= (value << 8) & 0xf00;
+        break;
+
+    case 0x1c: /* Power-On Sequence Timing Control */
+        s->timing[0] = value & 0x7f;
+        break;
+    case 0x1e: /* Timing Control 0 */
+        s->timing[1] = value & 0x17;
+        break;
+    case 0x20: /* Timing Control 1 */
+        s->timing[2] = value & 0x35;
+        break;
+
+    case 0x24: /* Arbitration Priority Control */
+        s->priority = value & 1;
+        break;
+
+    case 0x28: /* LCD Panel Configuration */
+        s->lcd_config = value & 0xff;
+        if (value & (1 << 7))
+            fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
+        break;
+
+    case 0x2a: /* LCD Horizontal Display Width */
+        s->x = value << 3;
+        break;
+    case 0x2c: /* LCD Horizontal Non-display Period */
+        s->hndp = value & 0xff;
+        break;
+    case 0x2e: /* LCD Vertical Display Height 0 */
+        s->y &= 0x300;
+        s->y |= (value << 0) & 0x0ff;
+        break;
+    case 0x30: /* LCD Vertical Display Height 1 */
+        s->y &= 0x0ff;
+        s->y |= (value << 8) & 0x300;
+        break;
+    case 0x32: /* LCD Vertical Non-display Period */
+        s->vndp = value & 0xff;
+        break;
+    case 0x34: /* LCD HS Pulse-width */
+        s->hsync = value & 0xff;
+        break;
+    case 0x36: /* LCD HS Pulse Start Position */
+        s->skipx = value & 0xff;
+        break;
+    case 0x38: /* LCD VS Pulse-width */
+        s->vsync = value & 0xbf;
+        break;
+    case 0x3a: /* LCD VS Pulse Start Position */
+        s->skipy = value & 0xff;
+        break;
+
+    case 0x3c: /* PCLK Polarity */
+        s->pclk = value & 0x82;
+        /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
+        break;
+
+    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
+        s->hssi_config[0] = value;
+        break;
+    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
+        s->hssi_config[1] = value;
+        if (((value >> 4) & 3) == 3)
+            fprintf(stderr, "%s: Illegal active-data-links value\n",
+                            __FUNCTION__);
+        break;
+    case 0x42: /* High-speed Serial Interface Tx Mode */
+        s->hssi_config[2] = value & 0xbd;
+        break;
+
+    case 0x44: /* TV Display Configuration */
+        s->tv_config = value & 0xfe;
+        break;
+    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits 0 */
+        s->tv_timing[(reg - 0x46) >> 1] = value;
+        break;
+    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
+        s->vbi = value;
+        break;
+    case 0x50: /* TV Horizontal Start Position */
+        s->tv_x = value;
+        break;
+    case 0x52: /* TV Vertical Start Position */
+        s->tv_y = value & 0x7f;
+        break;
+    case 0x54: /* TV Test Pattern Setting */
+        s->tv_test = value;
+        break;
+    case 0x56: /* TV Filter Setting */
+        s->tv_filter_config = value & 0xbf;
+        break;
+    case 0x58: /* TV Filter Coefficient Index */
+        s->tv_filter_idx = value & 0x1f;
+        break;
+    case 0x5a: /* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            s->tv_filter_coeff[s->tv_filter_idx ++] = value;
+        break;
+
+    case 0x60: /* Input YUV/RGB Translate Mode 0 */
+        s->yrc[0] = value & 0xb0;
+        break;
+    case 0x62: /* Input YUV/RGB Translate Mode 1 */
+        s->yrc[1] = value & 0x30;
+        break;
+    case 0x64: /* U Data Fix */
+        s->u = value & 0xff;
+        break;
+    case 0x66: /* V Data Fix */
+        s->v = value & 0xff;
+        break;
+
+    case 0x68: /* Display Mode */
+        if ((s->mode ^ value) & 3)
+            s->invalidate = 1;
+        s->mode = value & 0xb7;
+        s->enable = value & 1;
+        s->blank = (value >> 1) & 1;
+        if (value & (1 << 4))
+            fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
+        break;
+
+    case 0x6a: /* Special Effects */
+        s->effect = value & 0xfb;
+        break;
+
+    case 0x6c: /* Input Window X Start Position 0 */
+        s->ix[0] &= 0x300;
+        s->ix[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x6e: /* Input Window X Start Position 1 */
+        s->ix[0] &= 0x0ff;
+        s->ix[0] |= (value << 8) & 0x300;
+        break;
+    case 0x70: /* Input Window Y Start Position 0 */
+        s->iy[0] &= 0x300;
+        s->iy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x72: /* Input Window Y Start Position 1 */
+        s->iy[0] &= 0x0ff;
+        s->iy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x74: /* Input Window X End Position 0 */
+        s->ix[1] &= 0x300;
+        s->ix[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x76: /* Input Window X End Position 1 */
+        s->ix[1] &= 0x0ff;
+        s->ix[1] |= (value << 8) & 0x300;
+        break;
+    case 0x78: /* Input Window Y End Position 0 */
+        s->iy[1] &= 0x300;
+        s->iy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7a: /* Input Window Y End Position 1 */
+        s->iy[1] &= 0x0ff;
+        s->iy[1] |= (value << 8) & 0x300;
+        break;
+    case 0x7c: /* Output Window X Start Position 0 */
+        s->ox[0] &= 0x300;
+        s->ox[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7e: /* Output Window X Start Position 1 */
+        s->ox[0] &= 0x0ff;
+        s->ox[0] |= (value << 8) & 0x300;
+        break;
+    case 0x80: /* Output Window Y Start Position 0 */
+        s->oy[0] &= 0x300;
+        s->oy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x82: /* Output Window Y Start Position 1 */
+        s->oy[0] &= 0x0ff;
+        s->oy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x84: /* Output Window X End Position 0 */
+        s->ox[1] &= 0x300;
+        s->ox[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x86: /* Output Window X End Position 1 */
+        s->ox[1] &= 0x0ff;
+        s->ox[1] |= (value << 8) & 0x300;
+        break;
+    case 0x88: /* Output Window Y End Position 0 */
+        s->oy[1] &= 0x300;
+        s->oy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x8a: /* Output Window Y End Position 1 */
+        s->oy[1] &= 0x0ff;
+        s->oy[1] |= (value << 8) & 0x300;
+        break;
+
+    case 0x8c: /* Input Data Format */
+        s->iformat = value & 0xf;
+        s->bpp = blizzard_iformat_bpp[s->iformat];
+        if (!s->bpp)
+            fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
+                            __FUNCTION__, s->iformat);
+        break;
+    case 0x8e: /* Data Source Select */
+        s->source = value & 7;
+        /* Currently all windows will be "destructive overlays".  */
+        if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
+                                        s->iy[0] != s->oy[0] ||
+                                        s->ix[1] != s->ox[1] ||
+                                        s->iy[1] != s->oy[1])) ||
+                        !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
+                          (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
+            fprintf(stderr, "%s: Illegal input/output window positions\n",
+                            __FUNCTION__);
+
+        blizzard_transfer_setup(s);
+        break;
+
+    case 0x90: /* Display Memory Data Port */
+        if (!s->data.len && !blizzard_transfer_setup(s))
+            break;
+
+        *s->data.ptr ++ = value;
+        if (-- s->data.len == 0)
+            blizzard_window(s);
+        break;
+
+    case 0xa8: /* Border Color 0 */
+        s->border_r = value;
+        break;
+    case 0xaa: /* Border Color 1 */
+        s->border_g = value;
+        break;
+    case 0xac: /* Border Color 2 */
+        s->border_b = value;
+        break;
+
+    case 0xb4: /* Gamma Correction Enable */
+        s->gamma_config = value & 0x87;
+        break;
+    case 0xb6: /* Gamma Correction Table Index */
+        s->gamma_idx = value;
+        break;
+    case 0xb8: /* Gamma Correction Table Data */
+        s->gamma_lut[s->gamma_idx ++] = value;
+        break;
+
+    case 0xba: /* 3x3 Matrix Enable */
+        s->matrix_ena = value & 1;
+        break;
+    case 0xbc ... 0xde:        /* Coefficient Registers */
+        s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
+        break;
+    case 0xe0: /* 3x3 Matrix Red Offset */
+        s->matrix_r = value;
+        break;
+    case 0xe2: /* 3x3 Matrix Green Offset */
+        s->matrix_g = value;
+        break;
+    case 0xe4: /* 3x3 Matrix Blue Offset */
+        s->matrix_b = value;
+        break;
+
+    case 0xe6: /* Power-save */
+        s->pm = value & 0x83;
+        if (value & s->mode & 1)
+            fprintf(stderr, "%s: The display must be disabled before entering "
+                            "Standby Mode\n", __FUNCTION__);
+        break;
+    case 0xe8: /* Non-display Period Control / Status */
+        s->status = value & 0x1b;
+        break;
+    case 0xea: /* RGB Interface Control */
+        s->rgbgpio_dir = value & 0x8f;
+        break;
+    case 0xec: /* RGB Interface Status */
+        s->rgbgpio = value & 0xcf;
+        break;
+    case 0xee: /* General-purpose IO Pins Configuration */
+        s->gpio_dir = value;
+        break;
+    case 0xf0: /* General-purpose IO Pins Status / Control */
+        s->gpio = value;
+        break;
+    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
+        s->gpio_edge[0] = value;
+        break;
+    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
+        s->gpio_edge[1] = value;
+        break;
+    case 0xf6: /* GPIO Interrupt Status */
+        s->gpio_irq &= value;
+        break;
+    case 0xf8: /* GPIO Pull-down Control */
+        s->gpio_pdown = value;
+        break;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+uint16_t s1d13745_read(void *opaque, int dc)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    uint16_t value = blizzard_reg_read(s, s->reg);
+
+    if (s->swallow -- > 0)
+        return 0;
+    if (dc)
+        s->reg ++;
+
+    return value;
+}
+
+void s1d13745_write(void *opaque, int dc, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    if (s->swallow -- > 0)
+        return;
+    if (dc) {
+        blizzard_reg_write(s, s->reg, value);
+
+        if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
+            s->reg += 2;
+    } else
+        s->reg = value & 0xff;
+}
+
+void s1d13745_write_block(void *opaque, int dc,
+                void *buf, size_t len, int pitch)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    while (len > 0) {
+        if (s->reg == 0x90 && dc &&
+                        (s->data.len || blizzard_transfer_setup(s)) &&
+                        len >= (s->data.len << 1)) {
+            len -= s->data.len << 1;
+            s->data.len = 0;
+            s->data.data = buf;
+            if (pitch)
+                s->data.pitch = pitch;
+            blizzard_window(s);
+            s->data.data = s->data.buf;
+            continue;
+        }
+
+        s1d13745_write(opaque, dc, *(uint16_t *) buf);
+        len -= 2;
+        buf += 2;
+    }
+}
+
+static void blizzard_update_display(void *opaque)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y, bypp, bypl, bwidth;
+    uint8_t *src, *dst;
+
+    if (!s->enable)
+        return;
+
+    if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
+        s->invalidate = 1;
+        qemu_console_resize(s->con, s->x, s->y);
+        surface = qemu_console_surface(s->con);
+    }
+
+    if (s->invalidate) {
+        s->invalidate = 0;
+
+        if (s->blank) {
+            bypp = surface_bytes_per_pixel(surface);
+            memset(surface_data(surface), 0, bypp * s->x * s->y);
+            return;
+        }
+
+        s->mx[0] = 0;
+        s->mx[1] = s->x;
+        s->my[0] = 0;
+        s->my[1] = s->y;
+    }
+
+    if (s->mx[1] <= s->mx[0])
+        return;
+
+    bypp = surface_bytes_per_pixel(surface);
+    bypl = bypp * s->x;
+    bwidth = bypp * (s->mx[1] - s->mx[0]);
+    y = s->my[0];
+    src = s->fb + bypl * y + bypp * s->mx[0];
+    dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
+    for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
+        memcpy(dst, src, bwidth);
+
+    dpy_gfx_update(s->con, s->mx[0], s->my[0],
+                   s->mx[1] - s->mx[0], y - s->my[0]);
+
+    s->mx[0] = s->x;
+    s->mx[1] = 0;
+    s->my[0] = s->y;
+    s->my[1] = 0;
+}
+
+static void blizzard_screen_dump(void *opaque, const char *filename,
+                                 bool cswitch, Error **errp)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    blizzard_update_display(opaque);
+    if (s && surface_data(surface)) {
+        ppm_save(filename, surface, errp);
+    }
+}
+
+#define DEPTH 8
+#include "hw/blizzard_template.h"
+#define DEPTH 15
+#include "hw/blizzard_template.h"
+#define DEPTH 16
+#include "hw/blizzard_template.h"
+#define DEPTH 24
+#include "hw/blizzard_template.h"
+#define DEPTH 32
+#include "hw/blizzard_template.h"
+
+void *s1d13745_init(qemu_irq gpio_int)
+{
+    BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
+    DisplaySurface *surface;
+
+    s->fb = g_malloc(0x180000);
+
+    s->con = graphic_console_init(blizzard_update_display,
+                                  blizzard_invalidate_display,
+                                  blizzard_screen_dump, NULL, s);
+    surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        s->line_fn_tab[0] = s->line_fn_tab[1] =
+                g_malloc0(sizeof(blizzard_fn_t) * 0x10);
+        break;
+    case 8:
+        s->line_fn_tab[0] = blizzard_draw_fn_8;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_8;
+        break;
+    case 15:
+        s->line_fn_tab[0] = blizzard_draw_fn_15;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_15;
+        break;
+    case 16:
+        s->line_fn_tab[0] = blizzard_draw_fn_16;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_16;
+        break;
+    case 24:
+        s->line_fn_tab[0] = blizzard_draw_fn_24;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_24;
+        break;
+    case 32:
+        s->line_fn_tab[0] = blizzard_draw_fn_32;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_32;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    blizzard_reset(s);
+
+    return s;
+}
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
new file mode 100644 (file)
index 0000000..49cca4b
--- /dev/null
@@ -0,0 +1,1930 @@
+/*
+ * Samsung exynos4210 Display Controller (FIMD)
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ * Based on LCD controller for Samsung S5PC1xx-based board emulation
+ * by Kirill Batuzov <batuzovk@ispras.ru>
+ *
+ * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "qemu/bswap.h"
+
+/* Debug messages configuration */
+#define EXYNOS4210_FIMD_DEBUG              0
+#define EXYNOS4210_FIMD_MODE_TRACE         0
+
+#if EXYNOS4210_FIMD_DEBUG == 0
+    #define DPRINT_L1(fmt, args...)       do { } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define DPRINT_ERROR(fmt, args...)    do { } while (0)
+#elif EXYNOS4210_FIMD_DEBUG == 1
+    #define DPRINT_L1(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define DPRINT_ERROR(fmt, args...)  \
+        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#else
+    #define DPRINT_L1(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...) \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+    #define DPRINT_ERROR(fmt, args...)  \
+        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#endif
+
+#if EXYNOS4210_FIMD_MODE_TRACE == 0
+    #define DPRINT_TRACE(fmt, args...)        do { } while (0)
+#else
+    #define DPRINT_TRACE(fmt, args...)        \
+        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+#endif
+
+#define NUM_OF_WINDOWS              5
+#define FIMD_REGS_SIZE              0x4114
+
+/* Video main control registers */
+#define FIMD_VIDCON0                0x0000
+#define FIMD_VIDCON1                0x0004
+#define FIMD_VIDCON2                0x0008
+#define FIMD_VIDCON3                0x000C
+#define FIMD_VIDCON0_ENVID_F        (1 << 0)
+#define FIMD_VIDCON0_ENVID          (1 << 1)
+#define FIMD_VIDCON0_ENVID_MASK     ((1 << 0) | (1 << 1))
+#define FIMD_VIDCON1_ROMASK         0x07FFE000
+
+/* Video time control registers */
+#define FIMD_VIDTCON_START          0x10
+#define FIMD_VIDTCON_END            0x1C
+#define FIMD_VIDTCON2_SIZE_MASK     0x07FF
+#define FIMD_VIDTCON2_HOR_SHIFT     0
+#define FIMD_VIDTCON2_VER_SHIFT     11
+
+/* Window control registers */
+#define FIMD_WINCON_START           0x0020
+#define FIMD_WINCON_END             0x0030
+#define FIMD_WINCON_ROMASK          0x82200000
+#define FIMD_WINCON_ENWIN           (1 << 0)
+#define FIMD_WINCON_BLD_PIX         (1 << 6)
+#define FIMD_WINCON_ALPHA_MUL       (1 << 7)
+#define FIMD_WINCON_ALPHA_SEL       (1 << 1)
+#define FIMD_WINCON_SWAP            0x078000
+#define FIMD_WINCON_SWAP_SHIFT      15
+#define FIMD_WINCON_SWAP_WORD       0x1
+#define FIMD_WINCON_SWAP_HWORD      0x2
+#define FIMD_WINCON_SWAP_BYTE       0x4
+#define FIMD_WINCON_SWAP_BITS       0x8
+#define FIMD_WINCON_BUFSTAT_L       (1 << 21)
+#define FIMD_WINCON_BUFSTAT_H       (1 << 31)
+#define FIMD_WINCON_BUFSTATUS       ((1 << 21) | (1 << 31))
+#define FIMD_WINCON_BUF0_STAT       ((0 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF1_STAT       ((1 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF2_STAT       ((0 << 21) | (1 << 31))
+#define FIMD_WINCON_BUFSELECT       ((1 << 20) | (1 << 30))
+#define FIMD_WINCON_BUF0_SEL        ((0 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF1_SEL        ((1 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF2_SEL        ((0 << 20) | (1 << 30))
+#define FIMD_WINCON_BUFMODE         (1 << 14)
+#define IS_PALETTIZED_MODE(w)       (w->wincon & 0xC)
+#define PAL_MODE_WITH_ALPHA(x)       ((x) == 7)
+#define WIN_BPP_MODE(w)             ((w->wincon >> 2) & 0xF)
+#define WIN_BPP_MODE_WITH_ALPHA(w)     \
+    (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
+
+/* Shadow control register */
+#define FIMD_SHADOWCON              0x0034
+#define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
+/* Channel mapping control register */
+#define FIMD_WINCHMAP               0x003C
+
+/* Window position control registers */
+#define FIMD_VIDOSD_START           0x0040
+#define FIMD_VIDOSD_END             0x0088
+#define FIMD_VIDOSD_COORD_MASK      0x07FF
+#define FIMD_VIDOSD_HOR_SHIFT       11
+#define FIMD_VIDOSD_VER_SHIFT       0
+#define FIMD_VIDOSD_ALPHA_AEN0      0xFFF000
+#define FIMD_VIDOSD_AEN0_SHIFT      12
+#define FIMD_VIDOSD_ALPHA_AEN1      0x000FFF
+
+/* Frame buffer address registers */
+#define FIMD_VIDWADD0_START         0x00A0
+#define FIMD_VIDWADD0_END           0x00C4
+#define FIMD_VIDWADD0_END           0x00C4
+#define FIMD_VIDWADD1_START         0x00D0
+#define FIMD_VIDWADD1_END           0x00F4
+#define FIMD_VIDWADD2_START         0x0100
+#define FIMD_VIDWADD2_END           0x0110
+#define FIMD_VIDWADD2_PAGEWIDTH     0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE       0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
+#define FIMD_VIDW0ADD0_B2           0x20A0
+#define FIMD_VIDW4ADD0_B2           0x20C0
+
+/* Video interrupt control registers */
+#define FIMD_VIDINTCON0             0x130
+#define FIMD_VIDINTCON1             0x134
+
+/* Window color key registers */
+#define FIMD_WKEYCON_START          0x140
+#define FIMD_WKEYCON_END            0x15C
+#define FIMD_WKEYCON0_COMPKEY       0x00FFFFFF
+#define FIMD_WKEYCON0_CTL_SHIFT     24
+#define FIMD_WKEYCON0_DIRCON        (1 << 24)
+#define FIMD_WKEYCON0_KEYEN         (1 << 25)
+#define FIMD_WKEYCON0_KEYBLEN       (1 << 26)
+/* Window color key alpha control register */
+#define FIMD_WKEYALPHA_START        0x160
+#define FIMD_WKEYALPHA_END          0x16C
+
+/* Dithering control register */
+#define FIMD_DITHMODE               0x170
+
+/* Window alpha control registers */
+#define FIMD_VIDALPHA_ALPHA_LOWER   0x000F0F0F
+#define FIMD_VIDALPHA_ALPHA_UPPER   0x00F0F0F0
+#define FIMD_VIDWALPHA_START        0x21C
+#define FIMD_VIDWALPHA_END          0x240
+
+/* Window color map registers */
+#define FIMD_WINMAP_START           0x180
+#define FIMD_WINMAP_END             0x190
+#define FIMD_WINMAP_EN              (1 << 24)
+#define FIMD_WINMAP_COLOR_MASK      0x00FFFFFF
+
+/* Window palette control registers */
+#define FIMD_WPALCON_HIGH           0x019C
+#define FIMD_WPALCON_LOW            0x01A0
+#define FIMD_WPALCON_UPDATEEN       (1 << 9)
+#define FIMD_WPAL_W0PAL_L           0x07
+#define FIMD_WPAL_W0PAL_L_SHT        0
+#define FIMD_WPAL_W1PAL_L           0x07
+#define FIMD_WPAL_W1PAL_L_SHT       3
+#define FIMD_WPAL_W2PAL_L           0x01
+#define FIMD_WPAL_W2PAL_L_SHT       6
+#define FIMD_WPAL_W2PAL_H           0x06
+#define FIMD_WPAL_W2PAL_H_SHT       8
+#define FIMD_WPAL_W3PAL_L           0x01
+#define FIMD_WPAL_W3PAL_L_SHT       7
+#define FIMD_WPAL_W3PAL_H           0x06
+#define FIMD_WPAL_W3PAL_H_SHT       12
+#define FIMD_WPAL_W4PAL_L           0x01
+#define FIMD_WPAL_W4PAL_L_SHT       8
+#define FIMD_WPAL_W4PAL_H           0x06
+#define FIMD_WPAL_W4PAL_H_SHT       16
+
+/* Trigger control registers */
+#define FIMD_TRIGCON                0x01A4
+#define FIMD_TRIGCON_ROMASK         0x00000004
+
+/* LCD I80 Interface Control */
+#define FIMD_I80IFCON_START         0x01B0
+#define FIMD_I80IFCON_END           0x01BC
+/* Color gain control register */
+#define FIMD_COLORGAINCON           0x01C0
+/* LCD i80 Interface Command Control */
+#define FIMD_LDI_CMDCON0            0x01D0
+#define FIMD_LDI_CMDCON1            0x01D4
+/* I80 System Interface Manual Command Control */
+#define FIMD_SIFCCON0               0x01E0
+#define FIMD_SIFCCON2               0x01E8
+
+/* Hue Control Registers */
+#define FIMD_HUECOEFCR_START        0x01EC
+#define FIMD_HUECOEFCR_END          0x01F4
+#define FIMD_HUECOEFCB_START        0x01FC
+#define FIMD_HUECOEFCB_END          0x0208
+#define FIMD_HUEOFFSET              0x020C
+
+/* Video interrupt control registers */
+#define FIMD_VIDINT_INTFIFOPEND     (1 << 0)
+#define FIMD_VIDINT_INTFRMPEND      (1 << 1)
+#define FIMD_VIDINT_INTI80PEND      (1 << 2)
+#define FIMD_VIDINT_INTEN           (1 << 0)
+#define FIMD_VIDINT_INTFIFOEN       (1 << 1)
+#define FIMD_VIDINT_INTFRMEN        (1 << 12)
+#define FIMD_VIDINT_I80IFDONE       (1 << 17)
+
+/* Window blend equation control registers */
+#define FIMD_BLENDEQ_START          0x0244
+#define FIMD_BLENDEQ_END            0x0250
+#define FIMD_BLENDCON               0x0260
+#define FIMD_ALPHA_8BIT             (1 << 0)
+#define FIMD_BLENDEQ_COEF_MASK      0xF
+
+/* Window RTQOS Control Registers */
+#define FIMD_WRTQOSCON_START        0x0264
+#define FIMD_WRTQOSCON_END          0x0274
+
+/* LCD I80 Interface Command */
+#define FIMD_I80IFCMD_START         0x0280
+#define FIMD_I80IFCMD_END           0x02AC
+
+/* Shadow windows control registers */
+#define FIMD_SHD_ADD0_START         0x40A0
+#define FIMD_SHD_ADD0_END           0x40C0
+#define FIMD_SHD_ADD1_START         0x40D0
+#define FIMD_SHD_ADD1_END           0x40F0
+#define FIMD_SHD_ADD2_START         0x4100
+#define FIMD_SHD_ADD2_END           0x4110
+
+/* Palette memory */
+#define FIMD_PAL_MEM_START          0x2400
+#define FIMD_PAL_MEM_END            0x37FC
+/* Palette memory aliases for windows 0 and 1 */
+#define FIMD_PALMEM_AL_START        0x0400
+#define FIMD_PALMEM_AL_END          0x0BFC
+
+typedef struct {
+    uint8_t r, g, b;
+    /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
+    uint32_t a;
+} rgba;
+#define RGBA_SIZE  7
+
+typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
+typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
+
+struct Exynos4210fimdWindow {
+    uint32_t wincon;        /* Window control register */
+    uint32_t buf_start[3];  /* Start address for video frame buffer */
+    uint32_t buf_end[3];    /* End address for video frame buffer */
+    uint32_t keycon[2];     /* Window color key registers */
+    uint32_t keyalpha;      /* Color key alpha control register */
+    uint32_t winmap;        /* Window color map register */
+    uint32_t blendeq;       /* Window blending equation control register */
+    uint32_t rtqoscon;      /* Window RTQOS Control Registers */
+    uint32_t palette[256];  /* Palette RAM */
+    uint32_t shadow_buf_start;      /* Start address of shadow frame buffer */
+    uint32_t shadow_buf_end;        /* End address of shadow frame buffer */
+    uint32_t shadow_buf_size;       /* Virtual shadow screen width */
+
+    pixel_to_rgb_func *pixel_to_rgb;
+    void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
+            bool blend);
+    uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
+    uint16_t lefttop_x, lefttop_y;   /* VIDOSD0 register */
+    uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
+    uint32_t osdsize;                /* VIDOSD2&3 register */
+    uint32_t alpha_val[2];           /* VIDOSD2&3, VIDWALPHA registers */
+    uint16_t virtpage_width;         /* VIDWADD2 register */
+    uint16_t virtpage_offsize;       /* VIDWADD2 register */
+    MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
+    uint8_t *host_fb_addr;           /* Host pointer to window's framebuffer */
+    hwaddr fb_len;       /* Framebuffer length */
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QemuConsole *console;
+    qemu_irq irq[3];
+
+    uint32_t vidcon[4];     /* Video main control registers 0-3 */
+    uint32_t vidtcon[4];    /* Video time control registers 0-3 */
+    uint32_t shadowcon;     /* Window shadow control register */
+    uint32_t winchmap;      /* Channel mapping control register */
+    uint32_t vidintcon[2];  /* Video interrupt control registers */
+    uint32_t dithmode;      /* Dithering control register */
+    uint32_t wpalcon[2];    /* Window palette control registers */
+    uint32_t trigcon;       /* Trigger control register */
+    uint32_t i80ifcon[4];   /* I80 interface control registers */
+    uint32_t colorgaincon;  /* Color gain control register */
+    uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
+    uint32_t sifccon[3];    /* I80 System Interface Manual Command Control */
+    uint32_t huecoef_cr[4]; /* Hue control registers */
+    uint32_t huecoef_cb[4]; /* Hue control registers */
+    uint32_t hueoffset;     /* Hue offset control register */
+    uint32_t blendcon;      /* Blending control register */
+    uint32_t i80ifcmd[12];  /* LCD I80 Interface Command */
+
+    Exynos4210fimdWindow window[5];    /* Window-specific registers */
+    uint8_t *ifb;           /* Internal frame buffer */
+    bool invalidate;        /* Image needs to be redrawn */
+    bool enabled;           /* Display controller is enabled */
+} Exynos4210fimdState;
+
+/* Perform byte/halfword/word swap of data according to WINCON */
+static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
+{
+    int i;
+    uint64_t res;
+    uint64_t x = *data;
+
+    if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
+        res = 0;
+        for (i = 0; i < 64; i++) {
+            if (x & (1ULL << (64 - i))) {
+                res |= (1ULL << i);
+            }
+        }
+        x = res;
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
+        x = bswap64(x);
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
+        x = ((x & 0x000000000000FFFFULL) << 48) |
+            ((x & 0x00000000FFFF0000ULL) << 16) |
+            ((x & 0x0000FFFF00000000ULL) >> 16) |
+            ((x & 0xFFFF000000000000ULL) >> 48);
+    }
+
+    if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
+        x = ((x & 0x00000000FFFFFFFFULL) << 32) |
+            ((x & 0xFFFFFFFF00000000ULL) >> 32);
+    }
+
+    *data = x;
+}
+
+/* Conversion routines of Pixel data from frame buffer area to internal RGBA
+ * pixel representation.
+ * Every color component internally represented as 8-bit value. If original
+ * data has less than 8 bit for component, data is extended to 8 bit. For
+ * example, if blue component has only two possible values 0 and 1 it will be
+ * extended to 0 and 0xFF */
+
+/* One bit for alpha representation */
+#define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    pixel >>= (R); \
+    p->a = (pixel & 0x1); \
+}
+
+DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
+DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
+DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
+DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
+DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
+DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
+
+/* Alpha component is always zero */
+#define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    p->a = 0x0; \
+}
+
+DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb,  5, 6, 5)
+DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb,  5, 5, 5)
+DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb,  6, 6, 6)
+DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb,  8, 8, 8)
+
+/* Alpha component has some meaningful value */
+#define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
+           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
+    pixel >>= (B); \
+    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
+           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
+    pixel >>= (G); \
+    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
+           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
+    pixel >>= (R); \
+    p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
+           ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
+    p->a = p->a | (p->a << 8) | (p->a << 16); \
+}
+
+DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
+DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
+
+/* Lookup table to extent 2-bit color component to 8 bit */
+static const uint8_t pixel_lutable_2b[4] = {
+     0x0, 0x55, 0xAA, 0xFF
+};
+/* Lookup table to extent 3-bit color component to 8 bit */
+static const uint8_t pixel_lutable_3b[8] = {
+     0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
+};
+/* Special case for a232 bpp mode */
+static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
+{
+    p->b = pixel_lutable_2b[(pixel & 0x3)];
+    pixel >>= 2;
+    p->g = pixel_lutable_3b[(pixel & 0x7)];
+    pixel >>= 3;
+    p->r = pixel_lutable_2b[(pixel & 0x3)];
+    pixel >>= 2;
+    p->a = (pixel & 0x1);
+}
+
+/* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
+ * for all three color components */
+static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
+{
+    uint8_t comm = (pixel >> 15) & 1;
+    p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    pixel >>= 5;
+    p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    pixel >>= 5;
+    p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
+    p->a = 0x0;
+}
+
+/* Put/get pixel to/from internal LCD Controller framebuffer */
+
+static int put_pixel_ifb(const rgba p, uint8_t *d)
+{
+    *(uint8_t *)d++ = p.r;
+    *(uint8_t *)d++ = p.g;
+    *(uint8_t *)d++ = p.b;
+    *(uint32_t *)d = p.a;
+    return RGBA_SIZE;
+}
+
+static int get_pixel_ifb(const uint8_t *s, rgba *p)
+{
+    p->r = *(uint8_t *)s++;
+    p->g = *(uint8_t *)s++;
+    p->b = *(uint8_t *)s++;
+    p->a = (*(uint32_t *)s) & 0x00FFFFFF;
+    return RGBA_SIZE;
+}
+
+static pixel_to_rgb_func *palette_data_format[8] = {
+    [0] = pixel_565_to_rgb,
+    [1] = pixel_a555_to_rgb,
+    [2] = pixel_666_to_rgb,
+    [3] = pixel_a665_to_rgb,
+    [4] = pixel_a666_to_rgb,
+    [5] = pixel_888_to_rgb,
+    [6] = pixel_a888_to_rgb,
+    [7] = pixel_8888_to_rgb
+};
+
+/* Returns Index in palette data formats table for given window number WINDOW */
+static uint32_t
+exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
+{
+    uint32_t ret;
+
+    switch (window) {
+    case 0:
+        ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
+        if (ret != 7) {
+            ret = 6 - ret;
+        }
+        break;
+    case 1:
+        ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
+        if (ret != 7) {
+            ret = 6 - ret;
+        }
+        break;
+    case 2:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
+        break;
+    case 3:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
+        break;
+    case 4:
+        ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
+            ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
+        break;
+    default:
+        hw_error("exynos4210.fimd: incorrect window number %d\n", window);
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+#define FIMD_1_MINUS_COLOR(x)    \
+            ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
+                                  (0xFF0000 - ((x) & 0xFF0000)))
+#define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
+#define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
+
+/* Multiply three lower bytes of two 32-bit words with each other.
+ * Each byte with values 0-255 is considered as a number with possible values
+ * in a range [0 - 1] */
+static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
+{
+    uint32_t tmp;
+    uint32_t ret;
+
+    ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
+    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
+            0xFF00 : tmp << 8;
+    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
+            0xFF0000 : tmp << 16;
+    return ret;
+}
+
+/* For each corresponding bytes of two 32-bit words: (a*b + c*d)
+ * Byte values 0-255 are mapped to a range [0 .. 1] */
+static inline uint32_t
+fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
+{
+    uint32_t tmp;
+    uint32_t ret;
+
+    ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
+            > 0xFF) ? 0xFF : tmp;
+    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
+            ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
+    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
+            ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
+                    0xFF0000 : tmp << 16;
+    return ret;
+}
+
+/* These routines cover all possible sources of window's transparent factor
+ * used in blending equation. Choice of routine is affected by WPALCON
+ * registers, BLENDCON register and window's WINCON register */
+
+static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return pix_a;
+}
+
+static uint32_t
+fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_LOWER_HALFBYTE(pix_a);
+}
+
+static uint32_t
+fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(pix_a);
+}
+
+static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
+}
+
+static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
+            EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
+}
+
+static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return w->alpha_val[pix_a];
+}
+
+static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
+}
+
+static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
+}
+
+static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
+{
+    return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
+            FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
+}
+
+/* Updates currently active alpha value get function for specified window */
+static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+    const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
+
+    if (w->wincon & FIMD_WINCON_BLD_PIX) {
+        if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
+            /* In this case, alpha component contains meaningful value */
+            if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
+            } else {
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
+            }
+        } else {
+            if (IS_PALETTIZED_MODE(w) &&
+                  PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
+                /* Alpha component has 8-bit numeric value */
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
+            } else {
+                /* Alpha has only two possible values (AEN) */
+                w->get_alpha = alpha_is_8bit ?
+                        fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
+            }
+        }
+    } else {
+        w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
+                fimd_get_alpha_sel_ext;
+    }
+}
+
+/* Blends current window's (w) pixel (foreground pixel *ret) with background
+ * window (w_blend) pixel p_bg according to formula:
+ * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
+ * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
+ */
+static void
+exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
+{
+    rgba p_fg = *ret;
+    uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
+            (p_bg.b & 0xFF);
+    uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
+            (p_fg.b & 0xFF);
+    uint32_t alpha_fg = p_fg.a;
+    int i;
+    /* It is possible that blending equation parameters a and b do not
+     * depend on window BLENEQ register. Account for this with first_coef */
+    enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
+    uint32_t first_coef = A_COEF;
+    uint32_t blend_param[COEF_NUM];
+
+    if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
+        uint32_t colorkey = (w->keycon[1] &
+              ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
+
+        if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
+            (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
+            /* Foreground pixel is displayed */
+            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
+                alpha_fg = w->keyalpha;
+                blend_param[A_COEF] = alpha_fg;
+                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
+            } else {
+                alpha_fg = 0;
+                blend_param[A_COEF] = 0xFFFFFF;
+                blend_param[B_COEF] = 0x0;
+            }
+            first_coef = P_COEF;
+        } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
+            (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
+            /* Background pixel is displayed */
+            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
+                alpha_fg = w->keyalpha;
+                blend_param[A_COEF] = alpha_fg;
+                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
+            } else {
+                alpha_fg = 0;
+                blend_param[A_COEF] = 0x0;
+                blend_param[B_COEF] = 0xFFFFFF;
+            }
+            first_coef = P_COEF;
+        }
+    }
+
+    for (i = first_coef; i < COEF_NUM; i++) {
+        switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
+        case 0:
+            blend_param[i] = 0;
+            break;
+        case 1:
+            blend_param[i] = 0xFFFFFF;
+            break;
+        case 2:
+            blend_param[i] = alpha_fg;
+            break;
+        case 3:
+            blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
+            break;
+        case 4:
+            blend_param[i] = p_bg.a;
+            break;
+        case 5:
+            blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
+            break;
+        case 6:
+            blend_param[i] = w->alpha_val[0];
+            break;
+        case 10:
+            blend_param[i] = fg_color;
+            break;
+        case 11:
+            blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
+            break;
+        case 12:
+            blend_param[i] = bg_color;
+            break;
+        case 13:
+            blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
+            break;
+        default:
+            hw_error("exynos4210.fimd: blend equation coef illegal value\n");
+            break;
+        }
+    }
+
+    fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
+            fg_color, blend_param[A_COEF]);
+    ret->b = fg_color & 0xFF;
+    fg_color >>= 8;
+    ret->g = fg_color & 0xFF;
+    fg_color >>= 8;
+    ret->r = fg_color & 0xFF;
+    ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
+            p_bg.a, blend_param[Q_COEF]);
+}
+
+/* These routines read data from video frame buffer in system RAM, convert
+ * this data to display controller internal representation, if necessary,
+ * perform pixel blending with data, currently presented in internal buffer.
+ * Result is stored in display controller internal frame buffer. */
+
+/* Draw line with index in palette table in RAM frame buffer data */
+#define DEF_DRAW_LINE_PALETTE(N) \
+static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
+               uint8_t *dst, bool blend) \
+{ \
+    int width = w->rightbot_x - w->lefttop_x + 1; \
+    uint8_t *ifb = dst; \
+    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
+    uint64_t data; \
+    rgba p, p_old; \
+    int i; \
+    do { \
+        memcpy(&data, src, sizeof(data)); \
+        src += 8; \
+        fimd_swap_data(swap, &data); \
+        for (i = (64 / (N) - 1); i >= 0; i--) { \
+            w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
+                                   ((1ULL << (N)) - 1)], &p); \
+            p.a = w->get_alpha(w, p.a); \
+            if (blend) { \
+                ifb +=  get_pixel_ifb(ifb, &p_old); \
+                exynos4210_fimd_blend_pixel(w, p_old, &p); \
+            } \
+            dst += put_pixel_ifb(p, dst); \
+        } \
+        width -= (64 / (N)); \
+    } while (width > 0); \
+}
+
+/* Draw line with direct color value in RAM frame buffer data */
+#define DEF_DRAW_LINE_NOPALETTE(N) \
+static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
+                    uint8_t *dst, bool blend) \
+{ \
+    int width = w->rightbot_x - w->lefttop_x + 1; \
+    uint8_t *ifb = dst; \
+    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
+    uint64_t data; \
+    rgba p, p_old; \
+    int i; \
+    do { \
+        memcpy(&data, src, sizeof(data)); \
+        src += 8; \
+        fimd_swap_data(swap, &data); \
+        for (i = (64 / (N) - 1); i >= 0; i--) { \
+            w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
+            p.a = w->get_alpha(w, p.a); \
+            if (blend) { \
+                ifb += get_pixel_ifb(ifb, &p_old); \
+                exynos4210_fimd_blend_pixel(w, p_old, &p); \
+            } \
+            dst += put_pixel_ifb(p, dst); \
+        } \
+        width -= (64 / (N)); \
+    } while (width > 0); \
+}
+
+DEF_DRAW_LINE_PALETTE(1)
+DEF_DRAW_LINE_PALETTE(2)
+DEF_DRAW_LINE_PALETTE(4)
+DEF_DRAW_LINE_PALETTE(8)
+DEF_DRAW_LINE_NOPALETTE(8)  /* 8bpp mode has palette and non-palette versions */
+DEF_DRAW_LINE_NOPALETTE(16)
+DEF_DRAW_LINE_NOPALETTE(32)
+
+/* Special draw line routine for window color map case */
+static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
+                       uint8_t *dst, bool blend)
+{
+    rgba p, p_old;
+    uint8_t *ifb = dst;
+    int width = w->rightbot_x - w->lefttop_x + 1;
+    uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
+
+    do {
+        pixel_888_to_rgb(map_color, &p);
+        p.a = w->get_alpha(w, p.a);
+        if (blend) {
+            ifb += get_pixel_ifb(ifb, &p_old);
+            exynos4210_fimd_blend_pixel(w, p_old, &p);
+        }
+        dst += put_pixel_ifb(p, dst);
+    } while (--width);
+}
+
+/* Write RGB to QEMU's GraphicConsole framebuffer */
+
+static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
+    *(uint8_t *)d = pixel;
+    return 1;
+}
+
+static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
+    *(uint16_t *)d = pixel;
+    return 2;
+}
+
+static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
+    *(uint16_t *)d = pixel;
+    return 2;
+}
+
+static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+    *(uint8_t *)d++ = (pixel >>  0) & 0xFF;
+    *(uint8_t *)d++ = (pixel >>  8) & 0xFF;
+    *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
+    return 3;
+}
+
+static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
+{
+    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+    *(uint32_t *)d = pixel;
+    return 4;
+}
+
+/* Routine to copy pixel from internal buffer to QEMU buffer */
+static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
+static inline void fimd_update_putpix_qemu(int bpp)
+{
+    switch (bpp) {
+    case 8:
+        put_pixel_toqemu = put_to_qemufb_pixel8;
+        break;
+    case 15:
+        put_pixel_toqemu = put_to_qemufb_pixel15;
+        break;
+    case 16:
+        put_pixel_toqemu = put_to_qemufb_pixel16;
+        break;
+    case 24:
+        put_pixel_toqemu = put_to_qemufb_pixel24;
+        break;
+    case 32:
+        put_pixel_toqemu = put_to_qemufb_pixel32;
+        break;
+    default:
+        hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
+        break;
+    }
+}
+
+/* Routine to copy a line from internal frame buffer to QEMU display */
+static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
+{
+    rgba p;
+
+    do {
+        src += get_pixel_ifb(src, &p);
+        dst += put_pixel_toqemu(p, dst);
+    } while (--width);
+}
+
+/* Parse BPPMODE_F = WINCON1[5:2] bits */
+static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+
+    if (w->winmap & FIMD_WINMAP_EN) {
+        w->draw_line = draw_line_mapcolor;
+        return;
+    }
+
+    switch (WIN_BPP_MODE(w)) {
+    case 0:
+        w->draw_line = draw_line_palette_1;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 1:
+        w->draw_line = draw_line_palette_2;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 2:
+        w->draw_line = draw_line_palette_4;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 3:
+        w->draw_line = draw_line_palette_8;
+        w->pixel_to_rgb =
+                palette_data_format[exynos4210_fimd_palette_format(s, win)];
+        break;
+    case 4:
+        w->draw_line = draw_line_8;
+        w->pixel_to_rgb = pixel_a232_to_rgb;
+        break;
+    case 5:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_565_to_rgb;
+        break;
+    case 6:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_a555_to_rgb;
+        break;
+    case 7:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_1555_to_rgb;
+        break;
+    case 8:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_666_to_rgb;
+        break;
+    case 9:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a665_to_rgb;
+        break;
+    case 10:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a666_to_rgb;
+        break;
+    case 11:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_888_to_rgb;
+        break;
+    case 12:
+        w->draw_line = draw_line_32;
+        w->pixel_to_rgb = pixel_a887_to_rgb;
+        break;
+    case 13:
+        w->draw_line = draw_line_32;
+        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+                FIMD_WINCON_ALPHA_SEL)) {
+            w->pixel_to_rgb = pixel_8888_to_rgb;
+        } else {
+            w->pixel_to_rgb = pixel_a888_to_rgb;
+        }
+        break;
+    case 14:
+        w->draw_line = draw_line_16;
+        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+                FIMD_WINCON_ALPHA_SEL)) {
+            w->pixel_to_rgb = pixel_4444_to_rgb;
+        } else {
+            w->pixel_to_rgb = pixel_a444_to_rgb;
+        }
+        break;
+    case 15:
+        w->draw_line = draw_line_16;
+        w->pixel_to_rgb = pixel_555_to_rgb;
+        break;
+    }
+}
+
+#if EXYNOS4210_FIMD_MODE_TRACE > 0
+static const char *exynos4210_fimd_get_bppmode(int mode_code)
+{
+    switch (mode_code) {
+    case 0:
+        return "1 bpp";
+    case 1:
+        return "2 bpp";
+    case 2:
+        return "4 bpp";
+    case 3:
+        return "8 bpp (palettized)";
+    case 4:
+        return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
+    case 5:
+        return "16 bpp (non-palettized, R:5-G:6-B:5)";
+    case 6:
+        return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
+    case 7:
+        return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
+    case 8:
+        return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
+    case 9:
+        return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
+    case 10:
+        return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
+    case 11:
+        return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
+    case 12:
+        return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
+    case 13:
+        return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
+    case 14:
+        return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
+    case 15:
+        return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
+    default:
+        return "Non-existing bpp mode";
+    }
+}
+
+static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
+                int win_num, uint32_t val)
+{
+    Exynos4210fimdWindow *w = &s->window[win_num];
+
+    if (w->winmap & FIMD_WINMAP_EN) {
+        printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
+                win_num, w->winmap & 0xFFFFFF);
+        return;
+    }
+
+    if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
+        return;
+    }
+    printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
+        exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
+}
+#else
+static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
+        int win_num, uint32_t val)
+{
+
+}
+#endif
+
+static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
+{
+    switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
+    case FIMD_WINCON_BUF0_STAT:
+        return 0;
+    case FIMD_WINCON_BUF1_STAT:
+        return 1;
+    case FIMD_WINCON_BUF2_STAT:
+        return 2;
+    default:
+        DPRINT_ERROR("Non-existent buffer index\n");
+        return 0;
+    }
+}
+
+/* Updates specified window's MemorySection based on values of WINCON,
+ * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
+static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
+{
+    Exynos4210fimdWindow *w = &s->window[win];
+    hwaddr fb_start_addr, fb_mapped_len;
+
+    if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
+            FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
+        return;
+    }
+
+    if (w->host_fb_addr) {
+        cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
+        w->host_fb_addr = NULL;
+        w->fb_len = 0;
+    }
+
+    fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
+    /* Total number of bytes of virtual screen used by current window */
+    w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
+            (w->rightbot_y - w->lefttop_y + 1);
+    w->mem_section = memory_region_find(sysbus_address_space(&s->busdev),
+            fb_start_addr, w->fb_len);
+    assert(w->mem_section.mr);
+    assert(w->mem_section.offset_within_address_space == fb_start_addr);
+    DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
+            win, fb_start_addr, w->fb_len);
+
+    if (w->mem_section.size != w->fb_len ||
+            !memory_region_is_ram(w->mem_section.mr)) {
+        DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
+        goto error_return;
+    }
+
+    w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
+    if (!w->host_fb_addr) {
+        DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
+        goto error_return;
+    }
+
+    if (fb_mapped_len != w->fb_len) {
+        DPRINT_ERROR("Window %u mapped framebuffer length is less then "
+                "expected\n", win);
+        cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
+        goto error_return;
+    }
+    return;
+
+error_return:
+    w->mem_section.mr = NULL;
+    w->mem_section.size = 0;
+    w->host_fb_addr = NULL;
+    w->fb_len = 0;
+}
+
+static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
+{
+    if (enabled && !s->enabled) {
+        unsigned w;
+        s->enabled = true;
+        for (w = 0; w < NUM_OF_WINDOWS; w++) {
+            fimd_update_memory_section(s, w);
+        }
+    }
+    s->enabled = enabled;
+    DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
+}
+
+static inline uint32_t unpack_upper_4(uint32_t x)
+{
+    return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
+}
+
+static inline uint32_t pack_upper_4(uint32_t x)
+{
+    return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
+            ((x & 0xF0) >> 4)) & 0xFFF;
+}
+
+static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
+{
+    if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
+        qemu_irq_lower(s->irq[0]);
+        qemu_irq_lower(s->irq[1]);
+        qemu_irq_lower(s->irq[2]);
+        return;
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
+        qemu_irq_raise(s->irq[0]);
+    } else {
+        qemu_irq_lower(s->irq[0]);
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
+        qemu_irq_raise(s->irq[1]);
+    } else {
+        qemu_irq_lower(s->irq[1]);
+    }
+    if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
+            (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
+        qemu_irq_raise(s->irq[2]);
+    } else {
+        qemu_irq_lower(s->irq[2]);
+    }
+}
+
+static void exynos4210_fimd_invalidate(void *opaque)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    s->invalidate = true;
+}
+
+static void exynos4210_update_resolution(Exynos4210fimdState *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->console);
+
+    /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
+    uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+    uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+    if (s->ifb == NULL || surface_width(surface) != width ||
+            surface_height(surface) != height) {
+        DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
+           surface_width(surface), surface_height(surface), width, height);
+        qemu_console_resize(s->console, width, height);
+        s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
+        memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
+        exynos4210_fimd_invalidate(s);
+    }
+}
+
+static void exynos4210_fimd_update(void *opaque)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    DisplaySurface *surface = qemu_console_surface(s->console);
+    Exynos4210fimdWindow *w;
+    int i, line;
+    hwaddr fb_line_addr, inc_size;
+    int scrn_height;
+    int first_line = -1, last_line = -1, scrn_width;
+    bool blend = false;
+    uint8_t *host_fb_addr;
+    bool is_dirty = false;
+    const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
+    const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+            FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+    if (!s || !s->console || !surface_bits_per_pixel(surface) ||
+            !s->enabled) {
+        return;
+    }
+    exynos4210_update_resolution(s);
+
+    for (i = 0; i < NUM_OF_WINDOWS; i++) {
+        w = &s->window[i];
+        if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
+            scrn_height = w->rightbot_y - w->lefttop_y + 1;
+            scrn_width = w->virtpage_width;
+            /* Total width of virtual screen page in bytes */
+            inc_size = scrn_width + w->virtpage_offsize;
+            memory_region_sync_dirty_bitmap(w->mem_section.mr);
+            host_fb_addr = w->host_fb_addr;
+            fb_line_addr = w->mem_section.offset_within_region;
+
+            for (line = 0; line < scrn_height; line++) {
+                is_dirty = memory_region_get_dirty(w->mem_section.mr,
+                            fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
+
+                if (s->invalidate || is_dirty) {
+                    if (first_line == -1) {
+                        first_line = line;
+                    }
+                    last_line = line;
+                    w->draw_line(w, host_fb_addr, s->ifb +
+                        w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
+                        global_width * RGBA_SIZE, blend);
+                }
+                host_fb_addr += inc_size;
+                fb_line_addr += inc_size;
+                is_dirty = false;
+            }
+            memory_region_reset_dirty(w->mem_section.mr,
+                w->mem_section.offset_within_region,
+                w->fb_len, DIRTY_MEMORY_VGA);
+            blend = true;
+        }
+    }
+
+    /* Copy resulting image to QEMU_CONSOLE. */
+    if (first_line >= 0) {
+        uint8_t *d;
+        int bpp;
+
+        bpp = surface_bits_per_pixel(surface);
+        fimd_update_putpix_qemu(bpp);
+        bpp = (bpp + 1) >> 3;
+        d = surface_data(surface);
+        for (line = first_line; line <= last_line; line++) {
+            fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
+                    RGBA_SIZE, d + global_width * line * bpp);
+        }
+        dpy_gfx_update(s->console, 0, 0, global_width, global_height);
+    }
+    s->invalidate = false;
+    s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
+    if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
+        exynos4210_fimd_enable(s, false);
+    }
+    exynos4210_fimd_update_irq(s);
+}
+
+static void exynos4210_fimd_reset(DeviceState *d)
+{
+    Exynos4210fimdState *s = DO_UPCAST(Exynos4210fimdState, busdev.qdev, d);
+    unsigned w;
+
+    DPRINT_TRACE("Display controller reset\n");
+    /* Set all display controller registers to 0 */
+    memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
+    for (w = 0; w < NUM_OF_WINDOWS; w++) {
+        memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
+        s->window[w].blendeq = 0xC2;
+        exynos4210_fimd_update_win_bppmode(s, w);
+        exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
+        fimd_update_get_alpha(s, w);
+    }
+
+    if (s->ifb != NULL) {
+        g_free(s->ifb);
+    }
+    s->ifb = NULL;
+
+    exynos4210_fimd_invalidate(s);
+    exynos4210_fimd_enable(s, false);
+    /* Some registers have non-zero initial values */
+    s->winchmap = 0x7D517D51;
+    s->colorgaincon = 0x10040100;
+    s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
+    s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
+    s->hueoffset = 0x01800080;
+}
+
+static void exynos4210_fimd_write(void *opaque, hwaddr offset,
+                              uint64_t val, unsigned size)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    unsigned w, i;
+    uint32_t old_value;
+
+    DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
+            (long long unsigned int)val, (long long unsigned int)val);
+
+    switch (offset) {
+    case FIMD_VIDCON0:
+        if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
+            exynos4210_fimd_enable(s, true);
+        } else {
+            if ((val & FIMD_VIDCON0_ENVID) == 0) {
+                exynos4210_fimd_enable(s, false);
+            }
+        }
+        s->vidcon[0] = val;
+        break;
+    case FIMD_VIDCON1:
+        /* Leave read-only bits as is */
+        val = (val & (~FIMD_VIDCON1_ROMASK)) |
+                (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
+        s->vidcon[1] = val;
+        break;
+    case FIMD_VIDCON2 ... FIMD_VIDCON3:
+        s->vidcon[(offset) >> 2] = val;
+        break;
+    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
+        s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
+        break;
+    case FIMD_WINCON_START ... FIMD_WINCON_END:
+        w = (offset - FIMD_WINCON_START) >> 2;
+        /* Window's current buffer ID */
+        i = fimd_get_buffer_id(&s->window[w]);
+        old_value = s->window[w].wincon;
+        val = (val & ~FIMD_WINCON_ROMASK) |
+                (s->window[w].wincon & FIMD_WINCON_ROMASK);
+        if (w == 0) {
+            /* Window 0 wincon ALPHA_MUL bit must always be 0 */
+            val &= ~FIMD_WINCON_ALPHA_MUL;
+        }
+        exynos4210_fimd_trace_bppmode(s, w, val);
+        switch (val & FIMD_WINCON_BUFSELECT) {
+        case FIMD_WINCON_BUF0_SEL:
+            val &= ~FIMD_WINCON_BUFSTATUS;
+            break;
+        case FIMD_WINCON_BUF1_SEL:
+            val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
+            break;
+        case FIMD_WINCON_BUF2_SEL:
+            if (val & FIMD_WINCON_BUFMODE) {
+                val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
+            }
+            break;
+        default:
+            break;
+        }
+        s->window[w].wincon = val;
+        exynos4210_fimd_update_win_bppmode(s, w);
+        fimd_update_get_alpha(s, w);
+        if ((i != fimd_get_buffer_id(&s->window[w])) ||
+                (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
+                        FIMD_WINCON_ENWIN))) {
+            fimd_update_memory_section(s, w);
+        }
+        break;
+    case FIMD_SHADOWCON:
+        old_value = s->shadowcon;
+        s->shadowcon = val;
+        for (w = 0; w < NUM_OF_WINDOWS; w++) {
+            if (FIMD_WINDOW_PROTECTED(old_value, w) &&
+                    !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
+                fimd_update_memory_section(s, w);
+            }
+        }
+        break;
+    case FIMD_WINCHMAP:
+        s->winchmap = val;
+        break;
+    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
+        w = (offset - FIMD_VIDOSD_START) >> 4;
+        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
+        switch (i) {
+        case 0:
+            old_value = s->window[w].lefttop_y;
+            s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
+                                      FIMD_VIDOSD_COORD_MASK;
+            s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
+                                      FIMD_VIDOSD_COORD_MASK;
+            if (s->window[w].lefttop_y != old_value) {
+                fimd_update_memory_section(s, w);
+            }
+            break;
+        case 1:
+            old_value = s->window[w].rightbot_y;
+            s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
+                                       FIMD_VIDOSD_COORD_MASK;
+            s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
+                                       FIMD_VIDOSD_COORD_MASK;
+            if (s->window[w].rightbot_y != old_value) {
+                fimd_update_memory_section(s, w);
+            }
+            break;
+        case 2:
+            if (w == 0) {
+                s->window[w].osdsize = val;
+            } else {
+                s->window[w].alpha_val[0] =
+                    unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
+                    FIMD_VIDOSD_AEN0_SHIFT) |
+                    (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
+                s->window[w].alpha_val[1] =
+                    unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
+                    (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
+            }
+            break;
+        case 3:
+            if (w != 1 && w != 2) {
+                DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
+                return;
+            }
+            s->window[w].osdsize = val;
+            break;
+        }
+        break;
+    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
+        w = (offset - FIMD_VIDWADD0_START) >> 3;
+        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
+        if (i == fimd_get_buffer_id(&s->window[w]) &&
+                s->window[w].buf_start[i] != val) {
+            s->window[w].buf_start[i] = val;
+            fimd_update_memory_section(s, w);
+            break;
+        }
+        s->window[w].buf_start[i] = val;
+        break;
+    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
+        w = (offset - FIMD_VIDWADD1_START) >> 3;
+        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
+        s->window[w].buf_end[i] = val;
+        break;
+    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
+        w = (offset - FIMD_VIDWADD2_START) >> 2;
+        if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
+            (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
+                        s->window[w].virtpage_offsize)) {
+            s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
+            s->window[w].virtpage_offsize =
+                (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
+            fimd_update_memory_section(s, w);
+        }
+        break;
+    case FIMD_VIDINTCON0:
+        s->vidintcon[0] = val;
+        break;
+    case FIMD_VIDINTCON1:
+        s->vidintcon[1] &= ~(val & 7);
+        exynos4210_fimd_update_irq(s);
+        break;
+    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
+        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
+        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
+        s->window[w].keycon[i] = val;
+        break;
+    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
+        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
+        s->window[w].keyalpha = val;
+        break;
+    case FIMD_DITHMODE:
+        s->dithmode = val;
+        break;
+    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
+        w = (offset - FIMD_WINMAP_START) >> 2;
+        old_value = s->window[w].winmap;
+        s->window[w].winmap = val;
+        if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
+            exynos4210_fimd_invalidate(s);
+            exynos4210_fimd_update_win_bppmode(s, w);
+            exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
+            exynos4210_fimd_update(s);
+        }
+        break;
+    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
+        i = (offset - FIMD_WPALCON_HIGH) >> 2;
+        s->wpalcon[i] = val;
+        if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
+            for (w = 0; w < NUM_OF_WINDOWS; w++) {
+                exynos4210_fimd_update_win_bppmode(s, w);
+                fimd_update_get_alpha(s, w);
+            }
+        }
+        break;
+    case FIMD_TRIGCON:
+        val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
+        s->trigcon = val;
+        break;
+    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
+        s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
+        break;
+    case FIMD_COLORGAINCON:
+        s->colorgaincon = val;
+        break;
+    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
+        s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
+        break;
+    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
+        i = (offset - FIMD_SIFCCON0) >> 2;
+        if (i != 2) {
+            s->sifccon[i] = val;
+        }
+        break;
+    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
+        i = (offset - FIMD_HUECOEFCR_START) >> 2;
+        s->huecoef_cr[i] = val;
+        break;
+    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
+        i = (offset - FIMD_HUECOEFCB_START) >> 2;
+        s->huecoef_cb[i] = val;
+        break;
+    case FIMD_HUEOFFSET:
+        s->hueoffset = val;
+        break;
+    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
+        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
+        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
+        if (w == 0) {
+            s->window[w].alpha_val[i] = val;
+        } else {
+            s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
+                (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
+        }
+        break;
+    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
+        s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
+        break;
+    case FIMD_BLENDCON:
+        old_value = s->blendcon;
+        s->blendcon = val;
+        if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
+            for (w = 0; w < NUM_OF_WINDOWS; w++) {
+                fimd_update_get_alpha(s, w);
+            }
+        }
+        break;
+    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
+        s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
+        break;
+    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
+        s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
+        break;
+    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
+        if (fimd_get_buffer_id(&s->window[w]) == 2 &&
+                s->window[w].buf_start[2] != val) {
+            s->window[w].buf_start[2] = val;
+            fimd_update_memory_section(s, w);
+            break;
+        }
+        s->window[w].buf_start[2] = val;
+        break;
+    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
+        break;
+    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
+        if (offset & 0x0004) {
+            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+            break;
+        }
+        s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
+        break;
+    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
+        s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
+        break;
+    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
+        w = (offset - FIMD_PAL_MEM_START) >> 10;
+        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
+        s->window[w].palette[i] = val;
+        break;
+    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
+        /* Palette memory aliases for windows 0 and 1 */
+        w = (offset - FIMD_PALMEM_AL_START) >> 10;
+        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
+        s->window[w].palette[i] = val;
+        break;
+    default:
+        DPRINT_ERROR("bad write offset 0x%08x\n", offset);
+        break;
+    }
+}
+
+static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    int w, i;
+    uint32_t ret = 0;
+
+    DPRINT_L2("read offset 0x%08x\n", offset);
+
+    switch (offset) {
+    case FIMD_VIDCON0 ... FIMD_VIDCON3:
+        return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
+    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
+        return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
+    case FIMD_WINCON_START ... FIMD_WINCON_END:
+        return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
+    case FIMD_SHADOWCON:
+        return s->shadowcon;
+    case FIMD_WINCHMAP:
+        return s->winchmap;
+    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
+        w = (offset - FIMD_VIDOSD_START) >> 4;
+        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
+        switch (i) {
+        case 0:
+            ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
+            FIMD_VIDOSD_HOR_SHIFT) |
+            (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
+            break;
+        case 1:
+            ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
+                FIMD_VIDOSD_HOR_SHIFT) |
+                (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
+            break;
+        case 2:
+            if (w == 0) {
+                ret = s->window[w].osdsize;
+            } else {
+                ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
+                    FIMD_VIDOSD_AEN0_SHIFT) |
+                    pack_upper_4(s->window[w].alpha_val[1]);
+            }
+            break;
+        case 3:
+            if (w != 1 && w != 2) {
+                DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+                return 0xBAADBAAD;
+            }
+            ret = s->window[w].osdsize;
+            break;
+        }
+        return ret;
+    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
+        w = (offset - FIMD_VIDWADD0_START) >> 3;
+        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
+        return s->window[w].buf_start[i];
+    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
+        w = (offset - FIMD_VIDWADD1_START) >> 3;
+        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
+        return s->window[w].buf_end[i];
+    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
+        w = (offset - FIMD_VIDWADD2_START) >> 2;
+        return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
+            FIMD_VIDWADD2_OFFSIZE_SHIFT);
+    case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
+        return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
+    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
+        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
+        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
+        return s->window[w].keycon[i];
+    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
+        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
+        return s->window[w].keyalpha;
+    case FIMD_DITHMODE:
+        return s->dithmode;
+    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
+        return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
+    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
+        return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
+    case FIMD_TRIGCON:
+        return s->trigcon;
+    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
+        return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
+    case FIMD_COLORGAINCON:
+        return s->colorgaincon;
+    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
+        return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
+    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
+        i = (offset - FIMD_SIFCCON0) >> 2;
+        return s->sifccon[i];
+    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
+        i = (offset - FIMD_HUECOEFCR_START) >> 2;
+        return s->huecoef_cr[i];
+    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
+        i = (offset - FIMD_HUECOEFCB_START) >> 2;
+        return s->huecoef_cb[i];
+    case FIMD_HUEOFFSET:
+        return s->hueoffset;
+    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
+        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
+        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
+        return s->window[w].alpha_val[i] &
+                (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
+    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
+        return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
+    case FIMD_BLENDCON:
+        return s->blendcon;
+    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
+        return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
+    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
+        return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
+    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
+    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
+    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
+        if (offset & 0x0004) {
+            break;
+        }
+        return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
+    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
+        return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
+    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
+        w = (offset - FIMD_PAL_MEM_START) >> 10;
+        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
+        return s->window[w].palette[i];
+    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
+        /* Palette aliases for win 0,1 */
+        w = (offset - FIMD_PALMEM_AL_START) >> 10;
+        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
+        return s->window[w].palette[i];
+    }
+
+    DPRINT_ERROR("bad read offset 0x%08x\n", offset);
+    return 0xBAADBAAD;
+}
+
+static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
+    .read = exynos4210_fimd_read,
+    .write = exynos4210_fimd_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int exynos4210_fimd_load(void *opaque, int version_id)
+{
+    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
+    int w;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    for (w = 0; w < NUM_OF_WINDOWS; w++) {
+        exynos4210_fimd_update_win_bppmode(s, w);
+        fimd_update_get_alpha(s, w);
+        fimd_update_memory_section(s, w);
+    }
+
+    /* Redraw the whole screen */
+    exynos4210_update_resolution(s);
+    exynos4210_fimd_invalidate(s);
+    exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
+            FIMD_VIDCON0_ENVID_MASK);
+    return 0;
+}
+
+static const VMStateDescription exynos4210_fimd_window_vmstate = {
+    .name = "exynos4210.fimd_window",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
+        VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
+        VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
+        VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
+        VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
+        VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
+        VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
+        VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
+        VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
+        VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
+        VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
+        VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
+        VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
+        VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
+        VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
+        VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
+        VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
+        VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription exynos4210_fimd_vmstate = {
+    .name = "exynos4210.fimd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = exynos4210_fimd_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
+        VMSTATE_UINT32(winchmap, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32(dithmode, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32(trigcon, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
+        VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
+        VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
+        VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
+        VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
+        VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
+        VMSTATE_UINT32(blendcon, Exynos4210fimdState),
+        VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
+                exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int exynos4210_fimd_init(SysBusDevice *dev)
+{
+    Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev);
+
+    s->ifb = NULL;
+
+    sysbus_init_irq(dev, &s->irq[0]);
+    sysbus_init_irq(dev, &s->irq[1]);
+    sysbus_init_irq(dev, &s->irq[2]);
+
+    memory_region_init_io(&s->iomem, &exynos4210_fimd_mmio_ops, s,
+            "exynos4210.fimd", FIMD_REGS_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    s->console = graphic_console_init(exynos4210_fimd_update,
+                                  exynos4210_fimd_invalidate, NULL, NULL, s);
+
+    return 0;
+}
+
+static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    dc->vmsd = &exynos4210_fimd_vmstate;
+    dc->reset = exynos4210_fimd_reset;
+    k->init = exynos4210_fimd_init;
+}
+
+static const TypeInfo exynos4210_fimd_info = {
+    .name = "exynos4210.fimd",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210fimdState),
+    .class_init = exynos4210_fimd_class_init,
+};
+
+static void exynos4210_fimd_register_types(void)
+{
+    type_register_static(&exynos4210_fimd_info);
+}
+
+type_init(exynos4210_fimd_register_types)
diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c
new file mode 100644 (file)
index 0000000..7326a98
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Framebuffer device helper routines
+ *
+ * Copyright (c) 2009 CodeSourcery
+ * Written by Paul Brook <paul@codesourcery.com>
+ *
+ * This code is licensed under the GNU GPLv2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+/* TODO:
+   - Do something similar for framebuffers with local ram
+   - Handle rotation here instead of hacking dest_pitch
+   - Use common pixel conversion routines instead of per-device drawfn
+   - Remove all DisplayState knowledge from devices.
+ */
+
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/framebuffer.h"
+
+/* Render an image from a shared memory framebuffer.  */
+   
+void framebuffer_update_display(
+    DisplaySurface *ds,
+    MemoryRegion *address_space,
+    hwaddr base,
+    int cols, /* Width in pixels.  */
+    int rows, /* Height in pixels.  */
+    int src_width, /* Length of source line, in bytes.  */
+    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
+    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
+    int invalidate, /* nonzero to redraw the whole image.  */
+    drawfn fn,
+    void *opaque,
+    int *first_row, /* Input and output.  */
+    int *last_row /* Output only */)
+{
+    hwaddr src_len;
+    uint8_t *dest;
+    uint8_t *src;
+    uint8_t *src_base;
+    int first, last = 0;
+    int dirty;
+    int i;
+    ram_addr_t addr;
+    MemoryRegionSection mem_section;
+    MemoryRegion *mem;
+
+    i = *first_row;
+    *first_row = -1;
+    src_len = src_width * rows;
+
+    mem_section = memory_region_find(address_space, base, src_len);
+    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
+        return;
+    }
+    mem = mem_section.mr;
+    assert(mem);
+    assert(mem_section.offset_within_address_space == base);
+
+    memory_region_sync_dirty_bitmap(mem);
+    src_base = cpu_physical_memory_map(base, &src_len, 0);
+    /* If we can't map the framebuffer then bail.  We could try harder,
+       but it's not really worth it as dirty flag tracking will probably
+       already have failed above.  */
+    if (!src_base)
+        return;
+    if (src_len != src_width * rows) {
+        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+        return;
+    }
+    src = src_base;
+    dest = surface_data(ds);
+    if (dest_col_pitch < 0)
+        dest -= dest_col_pitch * (cols - 1);
+    if (dest_row_pitch < 0) {
+        dest -= dest_row_pitch * (rows - 1);
+    }
+    first = -1;
+    addr = mem_section.offset_within_region;
+
+    addr += i * src_width;
+    src += i * src_width;
+    dest += i * dest_row_pitch;
+
+    for (; i < rows; i++) {
+        dirty = memory_region_get_dirty(mem, addr, src_width,
+                                             DIRTY_MEMORY_VGA);
+        if (dirty || invalidate) {
+            fn(opaque, dest, src, cols, dest_col_pitch);
+            if (first == -1)
+                first = i;
+            last = i;
+        }
+        addr += src_width;
+        src += src_width;
+        dest += dest_row_pitch;
+    }
+    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+    if (first < 0) {
+        return;
+    }
+    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
+                              DIRTY_MEMORY_VGA);
+    *first_row = first;
+    *last_row = last;
+}
diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c
new file mode 100644 (file)
index 0000000..b723a04
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ *  QEMU model of the Milkymist texture mapping unit.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *  Copyright (c) 2010 Sebastien Bourdeauducq
+ *                       <sebastien.bourdeauducq@lekernel.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/tmu2.pdf
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+enum {
+    R_CTL = 0,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_BRIGHTNESS,
+    R_CHROMAKEY,
+    R_VERTICESADDR,
+    R_TEXFBUF,
+    R_TEXHRES,
+    R_TEXVRES,
+    R_TEXHMASK,
+    R_TEXVMASK,
+    R_DSTFBUF,
+    R_DSTHRES,
+    R_DSTVRES,
+    R_DSTHOFFSET,
+    R_DSTVOFFSET,
+    R_DSTSQUAREW,
+    R_DSTSQUAREH,
+    R_ALPHA,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY  = (1<<0),
+    CTL_CHROMAKEY   = (1<<1),
+};
+
+enum {
+    MAX_BRIGHTNESS = 63,
+    MAX_ALPHA      = 63,
+};
+
+enum {
+    MESH_MAXSIZE = 128,
+};
+
+struct vertex {
+    int x;
+    int y;
+} QEMU_PACKED;
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+
+    Display *dpy;
+    GLXFBConfig glx_fb_config;
+    GLXContext glx_context;
+};
+typedef struct MilkymistTMU2State MilkymistTMU2State;
+
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+
+static int tmu2_glx_init(MilkymistTMU2State *s)
+{
+    GLXFBConfig *configs;
+    int nelements;
+
+    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
+    if (s->dpy == NULL) {
+        return 1;
+    }
+
+    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        return 1;
+    }
+
+    s->glx_fb_config = *configs;
+    XFree(configs);
+
+    /* FIXME: call glXDestroyContext() */
+    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
+            GLX_RGBA_TYPE, NULL, 1);
+    if (s->glx_context == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
+        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
+{
+    int x, y;
+    int x0, y0, x1, y1;
+    int u0, v0, u1, v1, u2, v2, u3, v3;
+    double xscale = 1.0 / ((double)(64 * texhres));
+    double yscale = 1.0 / ((double)(64 * texvres));
+
+    glLoadIdentity();
+    glTranslatef(ho, vo, 0);
+    glEnable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+
+    for (y = 0; y < vmeshlast; y++) {
+        y0 = y * sh;
+        y1 = y0 + sh;
+        for (x = 0; x < hmeshlast; x++) {
+            x0 = x * sw;
+            x1 = x0 + sw;
+
+            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
+            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
+            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
+            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
+            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
+            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
+            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
+            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
+
+            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
+            glVertex3i(x0, y0, 0);
+            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
+            glVertex3i(x1, y0, 0);
+            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
+            glVertex3i(x1, y1, 0);
+            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
+            glVertex3i(x0, y1, 0);
+        }
+    }
+
+    glEnd();
+}
+
+static void tmu2_start(MilkymistTMU2State *s)
+{
+    int pbuffer_attrib[6] = {
+        GLX_PBUFFER_WIDTH,
+        0,
+        GLX_PBUFFER_HEIGHT,
+        0,
+        GLX_PRESERVED_CONTENTS,
+        True
+    };
+
+    GLXPbuffer pbuffer;
+    GLuint texture;
+    void *fb;
+    hwaddr fb_len;
+    void *mesh;
+    hwaddr mesh_len;
+    float m;
+
+    trace_milkymist_tmu2_start();
+
+    /* Create and set up a suitable OpenGL context */
+    pbuffer_attrib[1] = s->regs[R_DSTHRES];
+    pbuffer_attrib[3] = s->regs[R_DSTVRES];
+    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
+    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
+
+    /* Fixup endianness. TODO: would it work on BE hosts? */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
+
+    /* Row alignment */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_PACK_ALIGNMENT, 2);
+
+    /* Read the QEMU source framebuffer into an OpenGL texture */
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
+    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+
+    /* Set up texturing options */
+    /* WARNING:
+     * Many cases of TMU2 masking are not supported by OpenGL.
+     * We only implement the most common ones:
+     *  - full bilinear filtering vs. nearest texel
+     *  - texture clamping vs. texture wrapping
+     */
+    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    /* Translucency and decay */
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
+    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
+
+    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+
+    /* Map the texture */
+    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
+    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
+    if (mesh == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    tmu2_gl_map((struct vertex *)mesh,
+        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
+        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
+        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
+    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
+
+    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
+
+    /* Free OpenGL allocs */
+    glDeleteTextures(1, &texture);
+    glXMakeContextCurrent(s->dpy, None, None, NULL);
+    glXDestroyPbuffer(s->dpy, pbuffer);
+
+    s->regs[R_CTL] &= ~CTL_START_BUSY;
+
+    trace_milkymist_tmu2_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static uint64_t tmu2_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    MilkymistTMU2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_BRIGHTNESS:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_tmu2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_tmu2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void tmu2_check_registers(MilkymistTMU2State *s)
+{
+    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
+        error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned");
+    }
+}
+
+static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    MilkymistTMU2State *s = opaque;
+
+    trace_milkymist_tmu2_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        s->regs[addr] = value;
+        if (value & CTL_START_BUSY) {
+            tmu2_start(s);
+        }
+        break;
+    case R_BRIGHTNESS:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_tmu2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    tmu2_check_registers(s);
+}
+
+static const MemoryRegionOps tmu2_mmio_ops = {
+    .read = tmu2_read,
+    .write = tmu2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_tmu2_reset(DeviceState *d)
+{
+    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_tmu2_init(SysBusDevice *dev)
+{
+    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
+            "milkymist-tmu2", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_tmu2 = {
+    .name = "milkymist-tmu2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_tmu2_init;
+    dc->reset = milkymist_tmu2_reset;
+    dc->vmsd = &vmstate_milkymist_tmu2;
+}
+
+static const TypeInfo milkymist_tmu2_info = {
+    .name          = "milkymist-tmu2",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistTMU2State),
+    .class_init    = milkymist_tmu2_class_init,
+};
+
+static void milkymist_tmu2_register_types(void)
+{
+    type_register_static(&milkymist_tmu2_info);
+}
+
+type_init(milkymist_tmu2_register_types)
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
new file mode 100644 (file)
index 0000000..98762ec
--- /dev/null
@@ -0,0 +1,335 @@
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "ui/console.h"
+#include "hw/framebuffer.h"
+#include "ui/pixel_ops.h"
+#include "qemu/error-report.h"
+
+#define BITS 8
+#include "hw/milkymist-vgafb_template.h"
+#define BITS 15
+#include "hw/milkymist-vgafb_template.h"
+#define BITS 16
+#include "hw/milkymist-vgafb_template.h"
+#define BITS 24
+#include "hw/milkymist-vgafb_template.h"
+#define BITS 32
+#include "hw/milkymist-vgafb_template.h"
+
+enum {
+    R_CTRL = 0,
+    R_HRES,
+    R_HSYNC_START,
+    R_HSYNC_END,
+    R_HSCAN,
+    R_VRES,
+    R_VSYNC_START,
+    R_VSYNC_END,
+    R_VSCAN,
+    R_BASEADDRESS,
+    R_BASEADDRESS_ACT,
+    R_BURST_COUNT,
+    R_DDC,
+    R_SOURCE_CLOCK,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+struct MilkymistVgafbState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    QemuConsole *con;
+
+    int invalidate;
+    uint32_t fb_offset;
+    uint32_t fb_mask;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistVgafbState MilkymistVgafbState;
+
+static int vgafb_enabled(MilkymistVgafbState *s)
+{
+    return !(s->regs[R_CTRL] & CTRL_RESET);
+}
+
+static void vgafb_update_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    int dest_width = s->regs[R_HRES];
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 8:
+        fn = draw_line_8;
+        break;
+    case 15:
+        fn = draw_line_15;
+        dest_width *= 2;
+        break;
+    case 16:
+        fn = draw_line_16;
+        dest_width *= 2;
+        break;
+    case 24:
+        fn = draw_line_24;
+        dest_width *= 3;
+        break;
+    case 32:
+        fn = draw_line_32;
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
+                               s->regs[R_BASEADDRESS] + s->fb_offset,
+                               s->regs[R_HRES],
+                               s->regs[R_VRES],
+                               s->regs[R_HRES] * 2,
+                               dest_width,
+                               0,
+                               s->invalidate,
+                               fn,
+                               NULL,
+                               &first, &last);
+
+    if (first >= 0) {
+        dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void vgafb_invalidate_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    s->invalidate = 1;
+}
+
+static void vgafb_resize(MilkymistVgafbState *s)
+{
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
+    s->invalidate = 1;
+}
+
+static uint64_t vgafb_read(void *opaque, hwaddr addr,
+                           unsigned size)
+{
+    MilkymistVgafbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HRES:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VRES:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BASEADDRESS:
+    case R_BURST_COUNT:
+    case R_DDC:
+    case R_SOURCE_CLOCK:
+        r = s->regs[addr];
+    break;
+    case R_BASEADDRESS_ACT:
+        r = s->regs[R_BASEADDRESS];
+    break;
+
+    default:
+        error_report("milkymist_vgafb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_vgafb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
+                        unsigned size)
+{
+    MilkymistVgafbState *s = opaque;
+
+    trace_milkymist_vgafb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BURST_COUNT:
+    case R_DDC:
+    case R_SOURCE_CLOCK:
+        s->regs[addr] = value;
+        break;
+    case R_BASEADDRESS:
+        if (value & 0x1f) {
+            error_report("milkymist_vgafb: framebuffer base address have to "
+                     "be 32 byte aligned");
+            break;
+        }
+        s->regs[addr] = value & s->fb_mask;
+        s->invalidate = 1;
+        break;
+    case R_HRES:
+    case R_VRES:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_BASEADDRESS_ACT:
+        error_report("milkymist_vgafb: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_vgafb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps vgafb_mmio_ops = {
+    .read = vgafb_read,
+    .write = vgafb_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_vgafb_reset(DeviceState *d)
+{
+    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+    s->regs[R_HRES] = 640;
+    s->regs[R_VRES] = 480;
+    s->regs[R_BASEADDRESS] = 0;
+}
+
+static int milkymist_vgafb_init(SysBusDevice *dev)
+{
+    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
+            "milkymist-vgafb", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    s->con = graphic_console_init(vgafb_update_display,
+                                  vgafb_invalidate_display,
+                                  NULL, NULL, s);
+
+    return 0;
+}
+
+static int vgafb_post_load(void *opaque, int version_id)
+{
+    vgafb_invalidate_display(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_vgafb = {
+    .name = "milkymist-vgafb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vgafb_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_vgafb_properties[] = {
+    DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+    DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_vgafb_init;
+    dc->reset = milkymist_vgafb_reset;
+    dc->vmsd = &vmstate_milkymist_vgafb;
+    dc->props = milkymist_vgafb_properties;
+}
+
+static const TypeInfo milkymist_vgafb_info = {
+    .name          = "milkymist-vgafb",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistVgafbState),
+    .class_init    = milkymist_vgafb_class_init,
+};
+
+static void milkymist_vgafb_register_types(void)
+{
+    type_register_static(&milkymist_vgafb_info);
+}
+
+type_init(milkymist_vgafb_register_types)
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
new file mode 100644 (file)
index 0000000..ea3afce
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * OMAP2 Display Subsystem.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"
+
+struct omap_dss_s {
+    qemu_irq irq;
+    qemu_irq drq;
+    DisplayState *state;
+    MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
+
+    int autoidle;
+    int control;
+    int enable;
+
+    struct omap_dss_panel_s {
+        int enable;
+        int nx;
+        int ny;
+
+        int x;
+        int y;
+    } dig, lcd;
+
+    struct {
+        uint32_t idlemode;
+        uint32_t irqst;
+        uint32_t irqen;
+        uint32_t control;
+        uint32_t config;
+        uint32_t capable;
+        uint32_t timing[4];
+        int line;
+        uint32_t bg[2];
+        uint32_t trans[2];
+
+        struct omap_dss_plane_s {
+            int enable;
+            int bpp;
+            int posx;
+            int posy;
+            int nx;
+            int ny;
+
+            hwaddr addr[3];
+
+            uint32_t attr;
+            uint32_t tresh;
+            int rowinc;
+            int colinc;
+            int wininc;
+        } l[3];
+
+        int invalidate;
+        uint16_t palette[256];
+    } dispc;
+
+    struct {
+        int idlemode;
+        uint32_t control;
+        int enable;
+        int pixels;
+        int busy;
+        int skiplines;
+        uint16_t rxbuf;
+        uint32_t config[2];
+        uint32_t time[4];
+        uint32_t data[6];
+        uint16_t vsync;
+        uint16_t hsync;
+        struct rfbi_chip_s *chip[2];
+    } rfbi;
+};
+
+static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+{
+    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+}
+
+static void omap_rfbi_reset(struct omap_dss_s *s)
+{
+    s->rfbi.idlemode = 0;
+    s->rfbi.control = 2;
+    s->rfbi.enable = 0;
+    s->rfbi.pixels = 0;
+    s->rfbi.skiplines = 0;
+    s->rfbi.busy = 0;
+    s->rfbi.config[0] = 0x00310000;
+    s->rfbi.config[1] = 0x00310000;
+    s->rfbi.time[0] = 0;
+    s->rfbi.time[1] = 0;
+    s->rfbi.time[2] = 0;
+    s->rfbi.time[3] = 0;
+    s->rfbi.data[0] = 0;
+    s->rfbi.data[1] = 0;
+    s->rfbi.data[2] = 0;
+    s->rfbi.data[3] = 0;
+    s->rfbi.data[4] = 0;
+    s->rfbi.data[5] = 0;
+    s->rfbi.vsync = 0;
+    s->rfbi.hsync = 0;
+}
+
+void omap_dss_reset(struct omap_dss_s *s)
+{
+    s->autoidle = 0;
+    s->control = 0;
+    s->enable = 0;
+
+    s->dig.enable = 0;
+    s->dig.nx = 1;
+    s->dig.ny = 1;
+
+    s->lcd.enable = 0;
+    s->lcd.nx = 1;
+    s->lcd.ny = 1;
+
+    s->dispc.idlemode = 0;
+    s->dispc.irqst = 0;
+    s->dispc.irqen = 0;
+    s->dispc.control = 0;
+    s->dispc.config = 0;
+    s->dispc.capable = 0x161;
+    s->dispc.timing[0] = 0;
+    s->dispc.timing[1] = 0;
+    s->dispc.timing[2] = 0;
+    s->dispc.timing[3] = 0;
+    s->dispc.line = 0;
+    s->dispc.bg[0] = 0;
+    s->dispc.bg[1] = 0;
+    s->dispc.trans[0] = 0;
+    s->dispc.trans[1] = 0;
+
+    s->dispc.l[0].enable = 0;
+    s->dispc.l[0].bpp = 0;
+    s->dispc.l[0].addr[0] = 0;
+    s->dispc.l[0].addr[1] = 0;
+    s->dispc.l[0].addr[2] = 0;
+    s->dispc.l[0].posx = 0;
+    s->dispc.l[0].posy = 0;
+    s->dispc.l[0].nx = 1;
+    s->dispc.l[0].ny = 1;
+    s->dispc.l[0].attr = 0;
+    s->dispc.l[0].tresh = 0;
+    s->dispc.l[0].rowinc = 1;
+    s->dispc.l[0].colinc = 1;
+    s->dispc.l[0].wininc = 0;
+
+    omap_rfbi_reset(s);
+    omap_dispc_interrupt_update(s);
+}
+
+static uint64_t omap_diss_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+        return 0x20;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14: /* DSS_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* DSS_CONTROL */
+        return s->control;
+
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+        /* TODO: fake some values when appropriate s->control bits are set */
+        return 0;
+
+    case 0x5c: /* DSS_STATUS */
+        return 1 + (s->control & 1);
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_diss_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+    case 0x14: /* DSS_SYSSTATUS */
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+    case 0x5c: /* DSS_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40: /* DSS_CONTROL */
+        s->control = value & 0x3dd;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_diss_ops = {
+    .read = omap_diss_read,
+    .write = omap_diss_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_disc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x000:        /* DISPC_REVISION */
+        return 0x20;
+
+    case 0x010:        /* DISPC_SYSCONFIG */
+        return s->dispc.idlemode;
+
+    case 0x014:        /* DISPC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        return s->dispc.irqst;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        return s->dispc.irqen;
+
+    case 0x040:        /* DISPC_CONTROL */
+        return s->dispc.control;
+
+    case 0x044:        /* DISPC_CONFIG */
+        return s->dispc.config;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        return s->dispc.capable;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        return s->dispc.bg[0];
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        return s->dispc.bg[1];
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        return s->dispc.trans[0];
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        return s->dispc.trans[1];
+
+    case 0x05c:        /* DISPC_LINE_STATUS */
+        return 0x7ff;
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        return s->dispc.line;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        return s->dispc.timing[0];
+    case 0x068:        /* DISPC_TIMING_V */
+        return s->dispc.timing[1];
+    case 0x06c:        /* DISPC_POL_FREQ */
+        return s->dispc.timing[2];
+    case 0x070:        /* DISPC_DIVISOR */
+        return s->dispc.timing[3];
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
+
+    case 0x080:        /* DISPC_GFX_BA0 */
+        return s->dispc.l[0].addr[0];
+    case 0x084:        /* DISPC_GFX_BA1 */
+        return s->dispc.l[0].addr[1];
+    case 0x088:        /* DISPC_GFX_POSITION */
+        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        return s->dispc.l[0].attr;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        return s->dispc.l[0].tresh;
+    case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
+        return 256;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        return s->dispc.l[0].rowinc;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        return s->dispc.l[0].colinc;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        return s->dispc.l[0].wininc;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        return s->dispc.l[0].addr[2];
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_disc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x010:        /* DISPC_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->dispc.idlemode = value & 0x301b;
+        break;
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        s->dispc.irqst &= ~value;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        s->dispc.irqen = value & 0xffff;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x040:        /* DISPC_CONTROL */
+        s->dispc.control = value & 0x07ff9fff;
+        s->dig.enable = (value >> 1) & 1;
+        s->lcd.enable = (value >> 0) & 1;
+        if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
+            if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
+                fprintf(stderr, "%s: Overlay Optimization when no overlay "
+                        "region effectively exists leads to "
+                        "unpredictable behaviour!\n", __func__);
+            }
+        if (value & (1 << 6)) {                                /* GODIGITAL */
+            /* XXX: Shadowed fields are:
+             * s->dispc.config
+             * s->dispc.capable
+             * s->dispc.bg[0]
+             * s->dispc.bg[1]
+             * s->dispc.trans[0]
+             * s->dispc.trans[1]
+             * s->dispc.line
+             * s->dispc.timing[0]
+             * s->dispc.timing[1]
+             * s->dispc.timing[2]
+             * s->dispc.timing[3]
+             * s->lcd.nx
+             * s->lcd.ny
+             * s->dig.nx
+             * s->dig.ny
+             * s->dispc.l[0].addr[0]
+             * s->dispc.l[0].addr[1]
+             * s->dispc.l[0].addr[2]
+             * s->dispc.l[0].posx
+             * s->dispc.l[0].posy
+             * s->dispc.l[0].nx
+             * s->dispc.l[0].ny
+             * s->dispc.l[0].tresh
+             * s->dispc.l[0].rowinc
+             * s->dispc.l[0].colinc
+             * s->dispc.l[0].wininc
+             * All they need to be loaded here from their shadow registers.
+             */
+        }
+        if (value & (1 << 5)) {                                /* GOLCD */
+             /* XXX: Likewise for LCD here.  */
+        }
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x044:        /* DISPC_CONFIG */
+        s->dispc.config = value & 0x3fff;
+        /* XXX:
+         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
+         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
+         */
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        s->dispc.capable = value & 0x3ff;
+        break;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        s->dispc.bg[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        s->dispc.bg[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        s->dispc.trans[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        s->dispc.trans[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        s->dispc.line = value & 0x7ff;
+        break;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        s->dispc.timing[0] = value & 0x0ff0ff3f;
+        break;
+    case 0x068:        /* DISPC_TIMING_V */
+        s->dispc.timing[1] = value & 0x0ff0ff3f;
+        break;
+    case 0x06c:        /* DISPC_POL_FREQ */
+        s->dispc.timing[2] = value & 0x0003ffff;
+        break;
+    case 0x070:        /* DISPC_DIVISOR */
+        s->dispc.timing[3] = value & 0x00ff00ff;
+        break;
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x080:        /* DISPC_GFX_BA0 */
+        s->dispc.l[0].addr[0] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x084:        /* DISPC_GFX_BA1 */
+        s->dispc.l[0].addr[1] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x088:        /* DISPC_GFX_POSITION */
+        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
+        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
+        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        s->dispc.l[0].attr = value & 0x7ff;
+        if (value & (3 << 9))
+            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
+                            __FUNCTION__);
+        s->dispc.l[0].enable = value & 1;
+        s->dispc.l[0].bpp = (value >> 1) & 0xf;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        s->dispc.l[0].tresh = value & 0x01ff01ff;
+        break;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        s->dispc.l[0].rowinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        s->dispc.l[0].colinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        s->dispc.l[0].wininc = value;
+        break;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        s->dispc.l[0].addr[2] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_disc_ops = {
+    .read = omap_disc_read,
+    .write = omap_disc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
+{
+    if (!s->rfbi.busy)
+        return;
+
+    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
+
+    s->rfbi.busy = 0;
+}
+
+static void omap_rfbi_transfer_start(struct omap_dss_s *s)
+{
+    void *data;
+    hwaddr len;
+    hwaddr data_addr;
+    int pitch;
+    static void *bounce_buffer;
+    static hwaddr bounce_len;
+
+    if (!s->rfbi.enable || s->rfbi.busy)
+        return;
+
+    if (s->rfbi.control & (1 << 1)) {                          /* BYPASS */
+        /* TODO: in non-Bypass mode we probably need to just assert the
+         * DRQ and wait for DMA to write the pixels.  */
+        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
+        return;
+    }
+
+    if (!(s->dispc.control & (1 << 11)))                       /* RFBIMODE */
+        return;
+    /* TODO: check that LCD output is enabled in DISPC.  */
+
+    s->rfbi.busy = 1;
+
+    len = s->rfbi.pixels * 2;
+
+    data_addr = s->dispc.l[0].addr[0];
+    data = cpu_physical_memory_map(data_addr, &len, 0);
+    if (data && len != s->rfbi.pixels * 2) {
+        cpu_physical_memory_unmap(data, len, 0, 0);
+        data = NULL;
+        len = s->rfbi.pixels * 2;
+    }
+    if (!data) {
+        if (len > bounce_len) {
+            bounce_buffer = g_realloc(bounce_buffer, len);
+        }
+        data = bounce_buffer;
+        cpu_physical_memory_read(data_addr, data, len);
+    }
+
+    /* TODO bpp */
+    s->rfbi.pixels = 0;
+
+    /* TODO: negative values */
+    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
+
+    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
+    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+
+    if (data != bounce_buffer) {
+        cpu_physical_memory_unmap(data, len, 0, len);
+    }
+
+    omap_rfbi_transfer_stop(s);
+
+    /* TODO */
+    s->dispc.irqst |= 1;                                       /* FRAMEDONE */
+    omap_dispc_interrupt_update(s);
+}
+
+static uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* RFBI_REVISION */
+        return 0x10;
+
+    case 0x10: /* RFBI_SYSCONFIG */
+        return s->rfbi.idlemode;
+
+    case 0x14: /* RFBI_SYSSTATUS */
+        return 1 | (s->rfbi.busy << 8);                                /* RESETDONE */
+
+    case 0x40: /* RFBI_CONTROL */
+        return s->rfbi.control;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        return s->rfbi.pixels;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        return s->rfbi.skiplines;
+
+    case 0x58: /* RFBI_READ */
+    case 0x5c: /* RFBI_STATUS */
+        return s->rfbi.rxbuf;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        return s->rfbi.config[0];
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        return s->rfbi.time[0];
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        return s->rfbi.time[1];
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        return s->rfbi.data[0];
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        return s->rfbi.data[1];
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        return s->rfbi.data[2];
+
+    case 0x78: /* RFBI_CONFIG1 */
+        return s->rfbi.config[1];
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        return s->rfbi.time[2];
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        return s->rfbi.time[3];
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        return s->rfbi.data[3];
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        return s->rfbi.data[4];
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        return s->rfbi.data[5];
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        return s->rfbi.vsync;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        return s->rfbi.hsync;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_rfbi_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x10: /* RFBI_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_rfbi_reset(s);
+        s->rfbi.idlemode = value & 0x19;
+        break;
+
+    case 0x40: /* RFBI_CONTROL */
+        s->rfbi.control = value & 0xf;
+        s->rfbi.enable = value & 1;
+        if (value & (1 << 4) &&                                        /* ITE */
+                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
+            omap_rfbi_transfer_start(s);
+        break;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        s->rfbi.pixels = value;
+        break;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        s->rfbi.skiplines = value & 0x7ff;
+        break;
+
+    case 0x4c: /* RFBI_CMD */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
+        break;
+    case 0x50: /* RFBI_PARAM */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+        break;
+    case 0x54: /* RFBI_DATA */
+        /* TODO: take into account the format set up in s->rfbi.config[?] and
+         * s->rfbi.data[?], but special-case the most usual scenario so that
+         * speed doesn't suffer.  */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
+        }
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
+        }
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+    case 0x58: /* RFBI_READ */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x5c: /* RFBI_STATUS */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
+        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        s->rfbi.config[0] = value & 0x003f1fff;
+        break;
+
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        s->rfbi.time[0] = value & 0x3fffffff;
+        break;
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        s->rfbi.time[1] = value & 0x0fffffff;
+        break;
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        s->rfbi.data[0] = value & 0x0f1f0f1f;
+        break;
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        s->rfbi.data[1] = value & 0x0f1f0f1f;
+        break;
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        s->rfbi.data[2] = value & 0x0f1f0f1f;
+        break;
+    case 0x78: /* RFBI_CONFIG1 */
+        s->rfbi.config[1] = value & 0x003f1fff;
+        break;
+
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        s->rfbi.time[2] = value & 0x3fffffff;
+        break;
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        s->rfbi.time[3] = value & 0x0fffffff;
+        break;
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        s->rfbi.data[3] = value & 0x0f1f0f1f;
+        break;
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        s->rfbi.data[4] = value & 0x0f1f0f1f;
+        break;
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        s->rfbi.data[5] = value & 0x0f1f0f1f;
+        break;
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        s->rfbi.vsync = value & 0xffff;
+        break;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        s->rfbi.hsync = value & 0xffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_rfbi_ops = {
+    .read = omap_rfbi_read,
+    .write = omap_rfbi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_venc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* REV_ID */
+    case 0x04: /* STATUS */
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_venc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, size);
+    }
+
+    switch (addr) {
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_venc_ops = {
+    .read = omap_venc_read,
+    .write = omap_venc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_im3_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x0a8:        /* SBIMERRLOGA */
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+    case 0x1f8:        /* SBID_L */
+    case 0x1fc:        /* SBID_H */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_im3_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_im3_ops = {
+    .read = omap_im3_read,
+    .write = omap_im3_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                MemoryRegion *sysmem,
+                hwaddr l3_base,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *)
+            g_malloc0(sizeof(struct omap_dss_s));
+
+    s->irq = irq;
+    s->drq = drq;
+    omap_dss_reset(s);
+
+    memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
+                          omap_l4_region_size(ta, 0));
+    memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
+                          omap_l4_region_size(ta, 1));
+    memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
+                          omap_l4_region_size(ta, 2));
+    memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
+                          omap_l4_region_size(ta, 3));
+    memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
+                          "omap.im3", 0x1000);
+
+    omap_l4_attach(ta, 0, &s->iomem_diss1);
+    omap_l4_attach(ta, 1, &s->iomem_disc1);
+    omap_l4_attach(ta, 2, &s->iomem_rfbi1);
+    omap_l4_attach(ta, 3, &s->iomem_venc1);
+    memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
+
+#if 0
+    s->state = graphic_console_init(omap_update_display,
+                                    omap_invalidate_display, omap_screen_dump, s);
+#endif
+
+    return s;
+}
+
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
+{
+    if (cs < 0 || cs > 1)
+        hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
+    s->rfbi.chip[cs] = chip;
+}
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
new file mode 100644 (file)
index 0000000..4048cc1
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * OMAP LCD controller.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"
+#include "hw/framebuffer.h"
+#include "ui/pixel_ops.h"
+
+struct omap_lcd_panel_s {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    QemuConsole *con;
+
+    int plm;
+    int tft;
+    int mono;
+    int enable;
+    int width;
+    int height;
+    int interrupts;
+    uint32_t timing[3];
+    uint32_t subpanel;
+    uint32_t ctrl;
+
+    struct omap_dma_lcd_channel_s *dma;
+    uint16_t palette[256];
+    int palette_done;
+    int frame_done;
+    int invalidate;
+    int sync_error;
+};
+
+static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
+{
+    if (s->frame_done && (s->interrupts & 1)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->palette_done && (s->interrupts & 2)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->sync_error) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    qemu_irq_lower(s->irq);
+}
+
+#define draw_line_func drawfn
+
+#define DEPTH 8
+#include "hw/omap_lcd_template.h"
+#define DEPTH 15
+#include "hw/omap_lcd_template.h"
+#define DEPTH 16
+#include "hw/omap_lcd_template.h"
+#define DEPTH 32
+#include "hw/omap_lcd_template.h"
+
+static draw_line_func draw_line_table2[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line2_8,
+    [15]       = draw_line2_15,
+    [16]       = draw_line2_16,
+    [32]       = draw_line2_32,
+}, draw_line_table4[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line4_8,
+    [15]       = draw_line4_15,
+    [16]       = draw_line4_16,
+    [32]       = draw_line4_32,
+}, draw_line_table8[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line8_8,
+    [15]       = draw_line8_15,
+    [16]       = draw_line8_16,
+    [32]       = draw_line8_32,
+}, draw_line_table12[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line12_8,
+    [15]       = draw_line12_15,
+    [16]       = draw_line12_16,
+    [32]       = draw_line12_32,
+}, draw_line_table16[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line16_8,
+    [15]       = draw_line16_15,
+    [16]       = draw_line16_16,
+    [32]       = draw_line16_32,
+};
+
+static void omap_update_display(void *opaque)
+{
+    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
+    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
+    draw_line_func draw_line;
+    int size, height, first, last;
+    int width, linesize, step, bpp, frame_offset;
+    hwaddr frame_base;
+
+    if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable ||
+        !surface_bits_per_pixel(surface)) {
+        return;
+    }
+
+    frame_offset = 0;
+    if (omap_lcd->plm != 2) {
+        cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
+                                  omap_lcd->dma->current_frame],
+                                 (void *)omap_lcd->palette, 0x200);
+        switch (omap_lcd->palette[0] >> 12 & 7) {
+        case 3 ... 7:
+            frame_offset += 0x200;
+            break;
+        default:
+            frame_offset += 0x20;
+        }
+    }
+
+    /* Colour depth */
+    switch ((omap_lcd->palette[0] >> 12) & 7) {
+    case 1:
+        draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
+        bpp = 2;
+        break;
+
+    case 2:
+        draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
+        bpp = 4;
+        break;
+
+    case 3:
+        draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
+        bpp = 8;
+        break;
+
+    case 4 ... 7:
+        if (!omap_lcd->tft)
+            draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
+        else
+            draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
+        bpp = 16;
+        break;
+
+    default:
+        /* Unsupported at the moment.  */
+        return;
+    }
+
+    /* Resolution */
+    width = omap_lcd->width;
+    if (width != surface_width(surface) ||
+        omap_lcd->height != surface_height(surface)) {
+        qemu_console_resize(omap_lcd->con,
+                            omap_lcd->width, omap_lcd->height);
+        surface = qemu_console_surface(omap_lcd->con);
+        omap_lcd->invalidate = 1;
+    }
+
+    if (omap_lcd->dma->current_frame == 0)
+        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
+    else
+        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
+
+    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
+        omap_lcd->sync_error = 1;
+        omap_lcd_interrupts(omap_lcd);
+        omap_lcd->enable = 0;
+        return;
+    }
+
+    /* Content */
+    frame_base = omap_lcd->dma->phys_framebuffer[
+            omap_lcd->dma->current_frame] + frame_offset;
+    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
+    if (omap_lcd->dma->interrupts & 1)
+        qemu_irq_raise(omap_lcd->dma->irq);
+    if (omap_lcd->dma->dual)
+        omap_lcd->dma->current_frame ^= 1;
+
+    if (!surface_bits_per_pixel(surface)) {
+        return;
+    }
+
+    first = 0;
+    height = omap_lcd->height;
+    if (omap_lcd->subpanel & (1 << 31)) {
+        if (omap_lcd->subpanel & (1 << 29))
+            first = (omap_lcd->subpanel >> 16) & 0x3ff;
+        else
+            height = (omap_lcd->subpanel >> 16) & 0x3ff;
+        /* TODO: fill the rest of the panel with DPD */
+    }
+
+    step = width * bpp >> 3;
+    linesize = surface_stride(surface);
+    framebuffer_update_display(surface, omap_lcd->sysmem,
+                               frame_base, width, height,
+                               step, linesize, 0,
+                               omap_lcd->invalidate,
+                               draw_line, omap_lcd->palette,
+                               &first, &last);
+    if (first >= 0) {
+        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
+    }
+    omap_lcd->invalidate = 0;
+}
+
+static void omap_ppm_save(const char *filename, uint8_t *data,
+                    int w, int h, int linesize, Error **errp)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    unsigned int v;
+    int ret, y, x, bpp;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = data;
+    bpp = linesize / w;
+    for (y = 0; y < h; y ++) {
+        d = d1;
+        for (x = 0; x < w; x ++) {
+            v = *(uint32_t *) d;
+            switch (bpp) {
+            case 2:
+                ret = fputc((v >> 8) & 0xf8, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v >> 3) & 0xfc, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v << 3) & 0xf8, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                break;
+            case 3:
+            case 4:
+            default:
+                ret = fputc((v >> 16) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v >> 8) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                break;
+            }
+            d += bpp;
+        }
+        d1 += linesize;
+    }
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
+                             Error **errp)
+{
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
+
+    omap_update_display(opaque);
+    if (omap_lcd && surface_data(surface))
+        omap_ppm_save(filename, surface_data(surface),
+                    omap_lcd->width, omap_lcd->height,
+                    surface_stride(surface), errp);
+}
+
+static void omap_invalidate_display(void *opaque) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_lcd->invalidate = 1;
+}
+
+static void omap_lcd_update(struct omap_lcd_panel_s *s) {
+    if (!s->enable) {
+        s->dma->current_frame = -1;
+        s->sync_error = 0;
+        if (s->plm != 1)
+            s->frame_done = 1;
+        omap_lcd_interrupts(s);
+        return;
+    }
+
+    if (s->dma->current_frame == -1) {
+        s->frame_done = 0;
+        s->palette_done = 0;
+        s->dma->current_frame = 0;
+    }
+
+    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_top) ||
+                    !s->dma->mpu->port[
+                    s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_bottom) ||
+                    (s->dma->dual &&
+                     (!s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_top) ||
+                      !s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_bottom)))) {
+        s->dma->condition |= 1 << 2;
+        if (s->dma->interrupts & (1 << 1))
+            qemu_irq_raise(s->dma->irq);
+        s->enable = 0;
+        return;
+    }
+
+    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
+    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
+
+    if (s->plm != 2 && !s->palette_done) {
+        cpu_physical_memory_read(
+            s->dma->phys_framebuffer[s->dma->current_frame],
+            (void *)s->palette, 0x200);
+        s->palette_done = 1;
+        omap_lcd_interrupts(s);
+    }
+}
+
+static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* LCD_CONTROL */
+        return (s->tft << 23) | (s->plm << 20) |
+                (s->tft << 7) | (s->interrupts << 3) |
+                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
+
+    case 0x04: /* LCD_TIMING0 */
+        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
+
+    case 0x08: /* LCD_TIMING1 */
+        return (s->timing[1] << 10) | (s->height - 1);
+
+    case 0x0c: /* LCD_TIMING2 */
+        return s->timing[2] | 0xfc000000;
+
+    case 0x10: /* LCD_STATUS */
+        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
+
+    case 0x14: /* LCD_SUBPANEL */
+        return s->subpanel;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_lcdc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* LCD_CONTROL */
+        s->plm = (value >> 20) & 3;
+        s->tft = (value >> 7) & 1;
+        s->interrupts = (value >> 3) & 3;
+        s->mono = (value >> 1) & 1;
+        s->ctrl = value & 0x01cff300;
+        if (s->enable != (value & 1)) {
+            s->enable = value & 1;
+            omap_lcd_update(s);
+        }
+        break;
+
+    case 0x04: /* LCD_TIMING0 */
+        s->timing[0] = value >> 10;
+        s->width = (value & 0x3ff) + 1;
+        break;
+
+    case 0x08: /* LCD_TIMING1 */
+        s->timing[1] = value >> 10;
+        s->height = (value & 0x3ff) + 1;
+        break;
+
+    case 0x0c: /* LCD_TIMING2 */
+        s->timing[2] = value;
+        break;
+
+    case 0x10: /* LCD_STATUS */
+        break;
+
+    case 0x14: /* LCD_SUBPANEL */
+        s->subpanel = value & 0xa1ffffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_lcdc_ops = {
+    .read = omap_lcdc_read,
+    .write = omap_lcdc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void omap_lcdc_reset(struct omap_lcd_panel_s *s)
+{
+    s->dma->current_frame = -1;
+    s->plm = 0;
+    s->tft = 0;
+    s->mono = 0;
+    s->enable = 0;
+    s->width = 0;
+    s->height = 0;
+    s->interrupts = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->timing[2] = 0;
+    s->subpanel = 0;
+    s->palette_done = 0;
+    s->frame_done = 0;
+    s->sync_error = 0;
+    s->invalidate = 1;
+    s->subpanel = 0;
+    s->ctrl = 0;
+}
+
+struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
+                                        hwaddr base,
+                                        qemu_irq irq,
+                                        struct omap_dma_lcd_channel_s *dma,
+                                        omap_clk clk)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
+            g_malloc0(sizeof(struct omap_lcd_panel_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->sysmem = sysmem;
+    omap_lcdc_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->con = graphic_console_init(omap_update_display,
+                                  omap_invalidate_display,
+                                  omap_screen_dump, NULL, s);
+
+    return s;
+}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
new file mode 100644 (file)
index 0000000..ee59bc2
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * 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/hw.h"
+#include "ui/console.h"
+#include "hw/arm/pxa.h"
+#include "ui/pixel_ops.h"
+/* FIXME: For graphic_rotate. Should probably be done in common code.  */
+#include "sysemu/sysemu.h"
+#include "hw/framebuffer.h"
+
+struct DMAChannel {
+    uint32_t branch;
+    uint8_t up;
+    uint8_t palette[1024];
+    uint8_t pbuffer[1024];
+    void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
+                   int *miny, int *maxy);
+
+    uint32_t descriptor;
+    uint32_t source;
+    uint32_t id;
+    uint32_t command;
+};
+
+struct PXA2xxLCDState {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    int irqlevel;
+
+    int invalidated;
+    QemuConsole *con;
+    drawfn *line_fn[2];
+    int dest_width;
+    int xres, yres;
+    int pal_for;
+    int transp;
+    enum {
+        pxa_lcdc_2bpp = 1,
+        pxa_lcdc_4bpp = 2,
+        pxa_lcdc_8bpp = 3,
+        pxa_lcdc_16bpp = 4,
+        pxa_lcdc_18bpp = 5,
+        pxa_lcdc_18pbpp = 6,
+        pxa_lcdc_19bpp = 7,
+        pxa_lcdc_19pbpp = 8,
+        pxa_lcdc_24bpp = 9,
+        pxa_lcdc_25bpp = 10,
+    } bpp;
+
+    uint32_t control[6];
+    uint32_t status[2];
+    uint32_t ovl1c[2];
+    uint32_t ovl2c[2];
+    uint32_t ccr;
+    uint32_t cmdcr;
+    uint32_t trgbr;
+    uint32_t tcr;
+    uint32_t liidr;
+    uint8_t bscntr;
+
+    struct DMAChannel dma_ch[7];
+
+    qemu_irq vsync_cb;
+    int orientation;
+};
+
+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 */
+#define LCCR2  0x008   /* LCD Controller Control register 2 */
+#define LCCR3  0x00c   /* LCD Controller Control register 3 */
+#define LCCR4  0x010   /* LCD Controller Control register 4 */
+#define LCCR5  0x014   /* LCD Controller Control register 5 */
+
+#define FBR0   0x020   /* DMA Channel 0 Frame Branch register */
+#define FBR1   0x024   /* DMA Channel 1 Frame Branch register */
+#define FBR2   0x028   /* DMA Channel 2 Frame Branch register */
+#define FBR3   0x02c   /* DMA Channel 3 Frame Branch register */
+#define FBR4   0x030   /* DMA Channel 4 Frame Branch register */
+#define FBR5   0x110   /* DMA Channel 5 Frame Branch register */
+#define FBR6   0x114   /* DMA Channel 6 Frame Branch register */
+
+#define LCSR1  0x034   /* LCD Controller Status register 1 */
+#define LCSR0  0x038   /* LCD Controller Status register 0 */
+#define LIIDR  0x03c   /* LCD Controller Interrupt ID register */
+
+#define TRGBR  0x040   /* TMED RGB Seed register */
+#define TCR    0x044   /* TMED Control register */
+
+#define OVL1C1 0x050   /* Overlay 1 Control register 1 */
+#define OVL1C2 0x060   /* Overlay 1 Control register 2 */
+#define OVL2C1 0x070   /* Overlay 2 Control register 1 */
+#define OVL2C2 0x080   /* Overlay 2 Control register 2 */
+#define CCR    0x090   /* Cursor Control register */
+
+#define CMDCR  0x100   /* Command Control register */
+#define PRSR   0x104   /* Panel Read Status register */
+
+#define PXA_LCDDMA_CHANS       7
+#define DMA_FDADR              0x00    /* Frame Descriptor Address register */
+#define DMA_FSADR              0x04    /* Frame Source Address register */
+#define DMA_FIDR               0x08    /* Frame ID register */
+#define DMA_LDCMD              0x0c    /* Command register */
+
+/* LCD Buffer Strength Control register */
+#define BSCNTR 0x04000054
+
+/* Bitfield masks */
+#define LCCR0_ENB      (1 << 0)
+#define LCCR0_CMS      (1 << 1)
+#define LCCR0_SDS      (1 << 2)
+#define LCCR0_LDM      (1 << 3)
+#define LCCR0_SOFM0    (1 << 4)
+#define LCCR0_IUM      (1 << 5)
+#define LCCR0_EOFM0    (1 << 6)
+#define LCCR0_PAS      (1 << 7)
+#define LCCR0_DPD      (1 << 9)
+#define LCCR0_DIS      (1 << 10)
+#define LCCR0_QDM      (1 << 11)
+#define LCCR0_PDD      (0xff << 12)
+#define LCCR0_BSM0     (1 << 20)
+#define LCCR0_OUM      (1 << 21)
+#define LCCR0_LCDT     (1 << 22)
+#define LCCR0_RDSTM    (1 << 23)
+#define LCCR0_CMDIM    (1 << 24)
+#define LCCR0_OUC      (1 << 25)
+#define LCCR0_LDDALT   (1 << 26)
+#define LCCR1_PPL(x)   ((x) & 0x3ff)
+#define LCCR2_LPP(x)   ((x) & 0x3ff)
+#define LCCR3_API      (15 << 16)
+#define LCCR3_BPP(x)   ((((x) >> 24) & 7) | (((x) >> 26) & 8))
+#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
+#define LCCR4_K1(x)    (((x) >> 0) & 7)
+#define LCCR4_K2(x)    (((x) >> 3) & 7)
+#define LCCR4_K3(x)    (((x) >> 6) & 7)
+#define LCCR4_PALFOR(x)        (((x) >> 15) & 3)
+#define LCCR5_SOFM(ch) (1 << (ch - 1))
+#define LCCR5_EOFM(ch) (1 << (ch + 7))
+#define LCCR5_BSM(ch)  (1 << (ch + 15))
+#define LCCR5_IUM(ch)  (1 << (ch + 23))
+#define OVLC1_EN       (1 << 31)
+#define CCR_CEN                (1 << 31)
+#define FBR_BRA                (1 << 0)
+#define FBR_BINT       (1 << 1)
+#define FBR_SRCADDR    (0xfffffff << 4)
+#define LCSR0_LDD      (1 << 0)
+#define LCSR0_SOF0     (1 << 1)
+#define LCSR0_BER      (1 << 2)
+#define LCSR0_ABC      (1 << 3)
+#define LCSR0_IU0      (1 << 4)
+#define LCSR0_IU1      (1 << 5)
+#define LCSR0_OU       (1 << 6)
+#define LCSR0_QD       (1 << 7)
+#define LCSR0_EOF0     (1 << 8)
+#define LCSR0_BS0      (1 << 9)
+#define LCSR0_SINT     (1 << 10)
+#define LCSR0_RDST     (1 << 11)
+#define LCSR0_CMDINT   (1 << 12)
+#define LCSR0_BERCH(x) (((x) & 7) << 28)
+#define LCSR1_SOF(ch)  (1 << (ch - 1))
+#define LCSR1_EOF(ch)  (1 << (ch + 7))
+#define LCSR1_BS(ch)   (1 << (ch + 15))
+#define LCSR1_IU(ch)   (1 << (ch + 23))
+#define LDCMD_LENGTH(x)        ((x) & 0x001ffffc)
+#define LDCMD_EOFINT   (1 << 21)
+#define LDCMD_SOFINT   (1 << 22)
+#define LDCMD_PAL      (1 << 26)
+
+/* Route internal interrupt lines to the global IC */
+static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
+{
+    int level = 0;
+    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
+    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
+    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
+    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
+    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
+    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
+    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
+    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
+    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
+    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
+    level |= (s->status[1] & ~s->control[5]);
+
+    qemu_set_irq(s->irq, !!level);
+    s->irqlevel = level;
+}
+
+/* Set Branch Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (ch == 0) {
+        s->status[0] |= LCSR0_BS0;
+        unmasked = !(s->control[0] & LCCR0_BSM0);
+    } else {
+        s->status[1] |= LCSR1_BS(ch);
+        unmasked = !(s->control[5] & LCCR5_BSM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Start Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_SOF0;
+        unmasked = !(s->control[0] & LCCR0_SOFM0);
+    } else {
+        s->status[1] |= LCSR1_SOF(ch);
+        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set End Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_EOF0;
+        unmasked = !(s->control[0] & LCCR0_EOFM0);
+    } else {
+        s->status[1] |= LCSR1_EOF(ch);
+        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Bus Error Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
+{
+    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
+    if (s->irqlevel)
+        s->status[0] |= LCSR0_SINT;
+    else
+        s->liidr = s->dma_ch[ch].id;
+}
+
+/* Set Read Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
+{
+    s->status[0] |= LCSR0_RDST;
+    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
+        s->status[0] |= LCSR0_SINT;
+}
+
+/* Load new Frame Descriptors from DMA */
+static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
+{
+    PXAFrameDescriptor desc;
+    hwaddr descptr;
+    int i;
+
+    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
+        s->dma_ch[i].source = 0;
+
+        if (!s->dma_ch[i].up)
+            continue;
+
+        if (s->dma_ch[i].branch & FBR_BRA) {
+            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
+            if (s->dma_ch[i].branch & FBR_BINT)
+                pxa2xx_dma_bs_set(s, i);
+            s->dma_ch[i].branch &= ~FBR_BRA;
+        } else
+            descptr = s->dma_ch[i].descriptor;
+
+        if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
+                 sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size) ||
+                (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
+                 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
+            continue;
+        }
+
+        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 uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
+                                 unsigned size)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        return s->control[0];
+    case LCCR1:
+        return s->control[1];
+    case LCCR2:
+        return s->control[2];
+    case LCCR3:
+        return s->control[3];
+    case LCCR4:
+        return s->control[4];
+    case LCCR5:
+        return s->control[5];
+
+    case OVL1C1:
+        return s->ovl1c[0];
+    case OVL1C2:
+        return s->ovl1c[1];
+    case OVL2C1:
+        return s->ovl2c[0];
+    case OVL2C2:
+        return s->ovl2c[1];
+
+    case CCR:
+        return s->ccr;
+
+    case CMDCR:
+        return s->cmdcr;
+
+    case TRGBR:
+        return s->trgbr;
+    case TCR:
+        return s->tcr;
+
+    case 0x200 ... 0x1000:     /* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            return s->dma_ch[ch].descriptor;
+        case DMA_FSADR:
+            return s->dma_ch[ch].source;
+        case DMA_FIDR:
+            return s->dma_ch[ch].id;
+        case DMA_LDCMD:
+            return s->dma_ch[ch].command;
+        default:
+            goto fail;
+        }
+
+    case FBR0:
+        return s->dma_ch[0].branch;
+    case FBR1:
+        return s->dma_ch[1].branch;
+    case FBR2:
+        return s->dma_ch[2].branch;
+    case FBR3:
+        return s->dma_ch[3].branch;
+    case FBR4:
+        return s->dma_ch[4].branch;
+    case FBR5:
+        return s->dma_ch[5].branch;
+    case FBR6:
+        return s->dma_ch[6].branch;
+
+    case BSCNTR:
+        return s->bscntr;
+
+    case PRSR:
+        return 0;
+
+    case LCSR0:
+        return s->status[0];
+    case LCSR1:
+        return s->status[1];
+    case LIIDR:
+        return s->liidr;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        /* ACK Quick Disable done */
+        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
+            s->status[0] |= LCSR0_QD;
+
+        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
+            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
+
+        if ((s->control[3] & LCCR3_API) &&
+                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
+            s->status[0] |= LCSR0_ABC;
+
+        s->control[0] = value & 0x07ffffff;
+        pxa2xx_lcdc_int_update(s);
+
+        s->dma_ch[0].up = !!(value & LCCR0_ENB);
+        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
+        break;
+
+    case LCCR1:
+        s->control[1] = value;
+        break;
+
+    case LCCR2:
+        s->control[2] = value;
+        break;
+
+    case LCCR3:
+        s->control[3] = value & 0xefffffff;
+        s->bpp = LCCR3_BPP(value);
+        break;
+
+    case LCCR4:
+        s->control[4] = value & 0x83ff81ff;
+        break;
+
+    case LCCR5:
+        s->control[5] = value & 0x3f3f3f3f;
+        break;
+
+    case OVL1C1:
+        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
+
+        s->ovl1c[0] = value & 0x80ffffff;
+        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
+        break;
+
+    case OVL1C2:
+        s->ovl1c[1] = value & 0x000fffff;
+        break;
+
+    case OVL2C1:
+        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
+
+        s->ovl2c[0] = value & 0x80ffffff;
+        s->dma_ch[2].up = !!(value & OVLC1_EN);
+        s->dma_ch[3].up = !!(value & OVLC1_EN);
+        s->dma_ch[4].up = !!(value & OVLC1_EN);
+        break;
+
+    case OVL2C2:
+        s->ovl2c[1] = value & 0x007fffff;
+        break;
+
+    case CCR:
+        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
+            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
+
+        s->ccr = value & 0x81ffffe7;
+        s->dma_ch[5].up = !!(value & CCR_CEN);
+        break;
+
+    case CMDCR:
+        s->cmdcr = value & 0xff;
+        break;
+
+    case TRGBR:
+        s->trgbr = value & 0x00ffffff;
+        break;
+
+    case TCR:
+        s->tcr = value & 0x7fff;
+        break;
+
+    case 0x200 ... 0x1000:     /* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            s->dma_ch[ch].descriptor = value & 0xfffffff0;
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case FBR0:
+        s->dma_ch[0].branch = value & 0xfffffff3;
+        break;
+    case FBR1:
+        s->dma_ch[1].branch = value & 0xfffffff3;
+        break;
+    case FBR2:
+        s->dma_ch[2].branch = value & 0xfffffff3;
+        break;
+    case FBR3:
+        s->dma_ch[3].branch = value & 0xfffffff3;
+        break;
+    case FBR4:
+        s->dma_ch[4].branch = value & 0xfffffff3;
+        break;
+    case FBR5:
+        s->dma_ch[5].branch = value & 0xfffffff3;
+        break;
+    case FBR6:
+        s->dma_ch[6].branch = value & 0xfffffff3;
+        break;
+
+    case BSCNTR:
+        s->bscntr = value & 0xf;
+        break;
+
+    case PRSR:
+        break;
+
+    case LCSR0:
+        s->status[0] &= ~(value & 0xfff);
+        if (value & LCSR0_BER)
+            s->status[0] &= ~LCSR0_BERCH(7);
+        break;
+
+    case LCSR1:
+        s->status[1] &= ~(value & 0x3e3f3f);
+        break;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+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(PXA2xxLCDState *s, int ch, int bpp)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, n, format, r, g, b, alpha;
+    uint32_t *dest;
+    uint8_t *src;
+    s->pal_for = LCCR4_PALFOR(s->control[4]);
+    format = s->pal_for;
+
+    switch (bpp) {
+    case pxa_lcdc_2bpp:
+        n = 4;
+        break;
+    case pxa_lcdc_4bpp:
+        n = 16;
+        break;
+    case pxa_lcdc_8bpp:
+        n = 256;
+        break;
+    default:
+        format = 0;
+        return;
+    }
+
+    src = (uint8_t *) s->dma_ch[ch].pbuffer;
+    dest = (uint32_t *) s->dma_ch[ch].palette;
+    alpha = r = g = b = 0;
+
+    for (i = 0; i < n; i ++) {
+        switch (format) {
+        case 0: /* 16 bpp, no transparency */
+            alpha = 0;
+            if (s->control[0] & LCCR0_CMS) {
+                r = g = b = *(uint16_t *) src & 0xff;
+            }
+            else {
+                r = (*(uint16_t *) src & 0xf800) >> 8;
+                g = (*(uint16_t *) src & 0x07e0) >> 3;
+                b = (*(uint16_t *) src & 0x001f) << 3;
+            }
+            src += 2;
+            break;
+        case 1: /* 16 bpp plus transparency */
+            alpha = *(uint16_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint16_t *) src & 0xff;
+            else {
+                r = (*(uint16_t *) src & 0xf800) >> 8;
+                g = (*(uint16_t *) src & 0x07e0) >> 3;
+                b = (*(uint16_t *) src & 0x001f) << 3;
+            }
+            src += 2;
+            break;
+        case 2: /* 18 bpp plus transparency */
+            alpha = *(uint32_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint32_t *) src & 0xff;
+            else {
+                r = (*(uint32_t *) src & 0xf80000) >> 16;
+                g = (*(uint32_t *) src & 0x00fc00) >> 8;
+                b = (*(uint32_t *) src & 0x0000f8);
+            }
+            src += 4;
+            break;
+        case 3: /* 24 bpp plus transparency */
+            alpha = *(uint32_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint32_t *) src & 0xff;
+            else {
+                r = (*(uint32_t *) src & 0xff0000) >> 16;
+                g = (*(uint32_t *) src & 0x00ff00) >> 8;
+                b = (*(uint32_t *) src & 0x0000ff);
+            }
+            src += 4;
+            break;
+        }
+        switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            *dest = rgb_to_pixel8(r, g, b) | alpha;
+            break;
+        case 15:
+            *dest = rgb_to_pixel15(r, g, b) | alpha;
+            break;
+        case 16:
+            *dest = rgb_to_pixel16(r, g, b) | alpha;
+            break;
+        case 24:
+            *dest = rgb_to_pixel24(r, g, b) | alpha;
+            break;
+        case 32:
+            *dest = rgb_to_pixel32(r, g, b) | alpha;
+            break;
+        }
+        dest ++;
+    }
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
+                hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    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(surface, 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_rot90(PXA2xxLCDState *s,
+               hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    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->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, 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,
+                hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    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(surface, 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,
+               hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    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->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, 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(PXA2xxLCDState *s)
+{
+    int width, height;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    width = LCCR1_PPL(s->control[1]) + 1;
+    height = LCCR2_LPP(s->control[2]) + 1;
+
+    if (width != s->xres || height != s->yres) {
+        if (s->orientation == 90 || s->orientation == 270) {
+            qemu_console_resize(s->con, height, width);
+        } else {
+            qemu_console_resize(s->con, width, height);
+        }
+        s->invalidated = 1;
+        s->xres = width;
+        s->yres = height;
+    }
+}
+
+static void pxa2xx_update_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    hwaddr fbptr;
+    int miny, maxy;
+    int ch;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    pxa2xx_descriptor_load(s);
+
+    pxa2xx_lcdc_resize(s);
+    miny = s->yres;
+    maxy = 0;
+    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
+    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
+    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
+        if (s->dma_ch[ch].up) {
+            if (!s->dma_ch[ch].source) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+            fbptr = s->dma_ch[ch].source;
+            if (!((fbptr >= PXA2XX_SDRAM_BASE &&
+                     fbptr <= PXA2XX_SDRAM_BASE + ram_size) ||
+                    (fbptr >= PXA2XX_INTERNAL_BASE &&
+                     fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+
+            if (s->dma_ch[ch].command & LDCMD_PAL) {
+                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 */
+                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
+                    pxa2xx_palette_parse(s, ch, s->bpp);
+
+                /* ACK frame start */
+                pxa2xx_dma_sof_set(s, ch);
+
+                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
+                s->invalidated = 0;
+
+                /* ACK frame completed */
+                pxa2xx_dma_eof_set(s, ch);
+            }
+        }
+
+    if (s->control[0] & LCCR0_DIS) {
+        /* ACK last frame completed */
+        s->control[0] &= ~LCCR0_ENB;
+        s->status[0] |= LCSR0_LDD;
+    }
+
+    if (miny >= 0) {
+        switch (s->orientation) {
+        case 0:
+            dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
+            break;
+        case 90:
+            dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
+            break;
+        case 180:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
+            break;
+        case 270:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
+            break;
+        }
+    }
+    pxa2xx_lcdc_int_update(s);
+
+    qemu_irq_raise(s->vsync_cb);
+}
+
+static void pxa2xx_invalidate_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    s->invalidated = 1;
+}
+
+static void pxa2xx_lcdc_orientation(void *opaque, int angle)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+
+    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;
+    s->xres = s->yres = -1;
+    pxa2xx_lcdc_resize(s);
+}
+
+static const VMStateDescription vmstate_dma_channel = {
+    .name = "dma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(branch, struct DMAChannel),
+        VMSTATE_UINT8(up, struct DMAChannel),
+        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
+        VMSTATE_UINT32(descriptor, struct DMAChannel),
+        VMSTATE_UINT32(source, struct DMAChannel),
+        VMSTATE_UINT32(id, struct DMAChannel),
+        VMSTATE_UINT32(command, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
+{
+    PXA2xxLCDState *s = opaque;
+
+    s->bpp = LCCR3_BPP(s->control[3]);
+    s->xres = s->yres = s->pal_for = -1;
+
+    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 "hw/pxa2xx_template.h"
+#define BITS 15
+#include "hw/pxa2xx_template.h"
+#define BITS 16
+#include "hw/pxa2xx_template.h"
+#define BITS 24
+#include "hw/pxa2xx_template.h"
+#define BITS 32
+#include "hw/pxa2xx_template.h"
+
+PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
+                                 hwaddr base, qemu_irq irq)
+{
+    PXA2xxLCDState *s;
+    DisplaySurface *surface;
+
+    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
+    s->invalidated = 1;
+    s->irq = irq;
+    s->sysmem = sysmem;
+
+    pxa2xx_lcdc_orientation(s, graphic_rotate);
+
+    memory_region_init_io(&s->iomem, &pxa2xx_lcdc_ops, s,
+                          "pxa2xx-lcd-controller", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->con = graphic_console_init(pxa2xx_update_display,
+                                  pxa2xx_invalidate_display,
+                                  NULL, NULL, s);
+    surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        s->dest_width = 0;
+        break;
+    case 8:
+        s->line_fn[0] = pxa2xx_draw_fn_8;
+        s->line_fn[1] = pxa2xx_draw_fn_8t;
+        s->dest_width = 1;
+        break;
+    case 15:
+        s->line_fn[0] = pxa2xx_draw_fn_15;
+        s->line_fn[1] = pxa2xx_draw_fn_15t;
+        s->dest_width = 2;
+        break;
+    case 16:
+        s->line_fn[0] = pxa2xx_draw_fn_16;
+        s->line_fn[1] = pxa2xx_draw_fn_16t;
+        s->dest_width = 2;
+        break;
+    case 24:
+        s->line_fn[0] = pxa2xx_draw_fn_24;
+        s->line_fn[1] = pxa2xx_draw_fn_24t;
+        s->dest_width = 3;
+        break;
+    case 32:
+        s->line_fn[0] = pxa2xx_draw_fn_32;
+        s->line_fn[1] = pxa2xx_draw_fn_32t;
+        s->dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
+
+    return s;
+}
+
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
+{
+    s->vsync_cb = handler;
+}
diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c
new file mode 100644 (file)
index 0000000..84f9aa1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * qxl command logging -- for debug purposes
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/timer.h"
+#include "hw/qxl.h"
+
+static const char *qxl_type[] = {
+    [ QXL_CMD_NOP ]     = "nop",
+    [ QXL_CMD_DRAW ]    = "draw",
+    [ QXL_CMD_UPDATE ]  = "update",
+    [ QXL_CMD_CURSOR ]  = "cursor",
+    [ QXL_CMD_MESSAGE ] = "message",
+    [ QXL_CMD_SURFACE ] = "surface",
+};
+
+static const char *qxl_draw_type[] = {
+    [ QXL_DRAW_NOP         ] = "nop",
+    [ QXL_DRAW_FILL        ] = "fill",
+    [ QXL_DRAW_OPAQUE      ] = "opaque",
+    [ QXL_DRAW_COPY        ] = "copy",
+    [ QXL_COPY_BITS        ] = "copy-bits",
+    [ QXL_DRAW_BLEND       ] = "blend",
+    [ QXL_DRAW_BLACKNESS   ] = "blackness",
+    [ QXL_DRAW_WHITENESS   ] = "whitemess",
+    [ QXL_DRAW_INVERS      ] = "invers",
+    [ QXL_DRAW_ROP3        ] = "rop3",
+    [ QXL_DRAW_STROKE      ] = "stroke",
+    [ QXL_DRAW_TEXT        ] = "text",
+    [ QXL_DRAW_TRANSPARENT ] = "transparent",
+    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
+};
+
+static const char *qxl_draw_effect[] = {
+    [ QXL_EFFECT_BLEND            ] = "blend",
+    [ QXL_EFFECT_OPAQUE           ] = "opaque",
+    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
+    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
+    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
+    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
+    [ QXL_EFFECT_NOP              ] = "nop",
+    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
+};
+
+static const char *qxl_surface_cmd[] = {
+   [ QXL_SURFACE_CMD_CREATE  ] = "create",
+   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
+};
+
+static const char *spice_surface_fmt[] = {
+   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
+   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
+   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
+   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
+   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
+   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
+   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
+};
+
+static const char *qxl_cursor_cmd[] = {
+   [ QXL_CURSOR_SET   ] = "set",
+   [ QXL_CURSOR_MOVE  ] = "move",
+   [ QXL_CURSOR_HIDE  ] = "hide",
+   [ QXL_CURSOR_TRAIL ] = "trail",
+};
+
+static const char *spice_cursor_type[] = {
+   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
+   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
+   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
+   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
+   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
+   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
+   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
+};
+
+static const char *qxl_v2n(const char *n[], size_t l, int v)
+{
+    if (v >= l || !n[v]) {
+        return "???";
+    }
+    return n[v];
+}
+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
+
+static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
+{
+    QXLImage *image;
+    QXLImageDescriptor *desc;
+
+    image = qxl_phys2virt(qxl, addr, group_id);
+    if (!image) {
+        return 1;
+    }
+    desc = &image->descriptor;
+    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
+            desc->id, desc->type, desc->flags, desc->width, desc->height);
+    switch (desc->type) {
+    case SPICE_IMAGE_TYPE_BITMAP:
+        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
+                " palette %" PRIx64 " data %" PRIx64,
+                image->bitmap.format, image->bitmap.flags,
+                image->bitmap.x, image->bitmap.y,
+                image->bitmap.stride,
+                image->bitmap.palette, image->bitmap.data);
+        break;
+    }
+    fprintf(stderr, ")");
+    return 0;
+}
+
+static void qxl_log_rect(QXLRect *rect)
+{
+    fprintf(stderr, " %dx%d+%d+%d",
+            rect->right - rect->left,
+            rect->bottom - rect->top,
+            rect->left, rect->top);
+}
+
+static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
+                                 int group_id)
+{
+    int ret;
+
+    fprintf(stderr, " src %" PRIx64,
+            copy->src_bitmap);
+    ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
+    if (ret != 0) {
+        return ret;
+    }
+    fprintf(stderr, " area");
+    qxl_log_rect(&copy->src_area);
+    fprintf(stderr, " rop %d", copy->rop_descriptor);
+    return 0;
+}
+
+static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
+{
+    fprintf(stderr, ": surface_id %d type %s effect %s",
+            draw->surface_id,
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+    return 0;
+}
+
+static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
+                                   int group_id)
+{
+    fprintf(stderr, ": type %s effect %s",
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    if (draw->bitmap_offset) {
+        fprintf(stderr, ": bitmap %d",
+                draw->bitmap_offset);
+        qxl_log_rect(&draw->bitmap_area);
+    }
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+    return 0;
+}
+
+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
+{
+    fprintf(stderr, ": %s id %d",
+            qxl_name(qxl_surface_cmd, cmd->type),
+            cmd->surface_id);
+    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
+                cmd->u.surface_create.width,
+                cmd->u.surface_create.height,
+                cmd->u.surface_create.stride,
+                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
+                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
+    }
+    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
+    }
+}
+
+int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
+{
+    QXLCursor *cursor;
+
+    fprintf(stderr, ": %s",
+            qxl_name(qxl_cursor_cmd, cmd->type));
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
+                cmd->u.set.position.x,
+                cmd->u.set.position.y,
+                cmd->u.set.visible ? "yes" : "no",
+                cmd->u.set.shape);
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
+        if (!cursor) {
+            return 1;
+        }
+        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
+                " unique 0x%" PRIx64 " data-size %d",
+                qxl_name(spice_cursor_type, cursor->header.type),
+                cursor->header.width, cursor->header.height,
+                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
+                cursor->header.unique, cursor->data_size);
+        break;
+    case QXL_CURSOR_MOVE:
+        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
+        break;
+    }
+    return 0;
+}
+
+int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
+{
+    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
+    void *data;
+    int ret;
+
+    if (!qxl->cmdlog) {
+        return 0;
+    }
+    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+            qxl->id, ring);
+    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
+            qxl_name(qxl_type, ext->cmd.type),
+            compat ? "(compat)" : "");
+
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    if (!data) {
+        return 1;
+    }
+    switch (ext->cmd.type) {
+    case QXL_CMD_DRAW:
+        if (!compat) {
+            ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
+        } else {
+            ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
+        }
+        if (ret) {
+            return ret;
+        }
+        break;
+    case QXL_CMD_SURFACE:
+        qxl_log_cmd_surface(qxl, data);
+        break;
+    case QXL_CMD_CURSOR:
+        qxl_log_cmd_cursor(qxl, data, ext->group_id);
+        break;
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
new file mode 100644 (file)
index 0000000..8cd9be4
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * qxl local rendering (aka display on sdl/vnc)
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/qxl.h"
+
+static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
+{
+    DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
+    uint8_t *dst = surface_data(surface);
+    uint8_t *src;
+    int len, i;
+
+    if (is_buffer_shared(surface)) {
+        return;
+    }
+    if (!qxl->guest_primary.data) {
+        trace_qxl_render_blit_guest_primary_initialized();
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
+    }
+    trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
+            rect->left, rect->right, rect->top, rect->bottom);
+    src = qxl->guest_primary.data;
+    if (qxl->guest_primary.qxl_stride < 0) {
+        /* qxl surface is upside down, walk src scanlines
+         * in reverse order to flip it */
+        src += (qxl->guest_primary.surface.height - rect->top - 1) *
+            qxl->guest_primary.abs_stride;
+    } else {
+        src += rect->top * qxl->guest_primary.abs_stride;
+    }
+    dst += rect->top  * qxl->guest_primary.abs_stride;
+    src += rect->left * qxl->guest_primary.bytes_pp;
+    dst += rect->left * qxl->guest_primary.bytes_pp;
+    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
+
+    for (i = rect->top; i < rect->bottom; i++) {
+        memcpy(dst, src, len);
+        dst += qxl->guest_primary.abs_stride;
+        src += qxl->guest_primary.qxl_stride;
+    }
+}
+
+void qxl_render_resize(PCIQXLDevice *qxl)
+{
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    qxl->guest_primary.qxl_stride = sc->stride;
+    qxl->guest_primary.abs_stride = abs(sc->stride);
+    qxl->guest_primary.resized++;
+    switch (sc->format) {
+    case SPICE_SURFACE_FMT_16_555:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 15;
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 16;
+        break;
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
+                qxl->guest_primary.surface.format);
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    }
+}
+
+static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
+{
+    area->left   = 0;
+    area->right  = qxl->guest_primary.surface.width;
+    area->top    = 0;
+    area->bottom = qxl->guest_primary.surface.height;
+}
+
+static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
+{
+    VGACommonState *vga = &qxl->vga;
+    DisplaySurface *surface;
+    int i;
+
+    if (qxl->guest_primary.resized) {
+        qxl->guest_primary.resized = 0;
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
+        qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
+        qxl->num_dirty_rects = 1;
+        trace_qxl_render_guest_primary_resized(
+               qxl->guest_primary.surface.width,
+               qxl->guest_primary.surface.height,
+               qxl->guest_primary.qxl_stride,
+               qxl->guest_primary.bytes_pp,
+               qxl->guest_primary.bits_pp);
+        if (qxl->guest_primary.qxl_stride > 0) {
+            surface = qemu_create_displaysurface_from
+                (qxl->guest_primary.surface.width,
+                 qxl->guest_primary.surface.height,
+                 qxl->guest_primary.bits_pp,
+                 qxl->guest_primary.abs_stride,
+                 qxl->guest_primary.data,
+                 false);
+        } else {
+            surface = qemu_create_displaysurface
+                (qxl->guest_primary.surface.width,
+                 qxl->guest_primary.surface.height);
+        }
+        dpy_gfx_replace_surface(vga->con, surface);
+    }
+    for (i = 0; i < qxl->num_dirty_rects; i++) {
+        if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
+            break;
+        }
+        qxl_blit(qxl, qxl->dirty+i);
+        dpy_gfx_update(vga->con,
+                       qxl->dirty[i].left, qxl->dirty[i].top,
+                       qxl->dirty[i].right - qxl->dirty[i].left,
+                       qxl->dirty[i].bottom - qxl->dirty[i].top);
+    }
+    qxl->num_dirty_rects = 0;
+}
+
+/*
+ * use ssd.lock to protect render_update_cookie_num.
+ * qxl_render_update is called by io thread or vcpu thread, and the completion
+ * callbacks are called by spice_server thread, defering to bh called from the
+ * io thread.
+ */
+void qxl_render_update(PCIQXLDevice *qxl)
+{
+    QXLCookie *cookie;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+
+    if (!runstate_is_running() || !qxl->guest_primary.commands) {
+        qxl_render_update_area_unlocked(qxl);
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+
+    qxl->guest_primary.commands = 0;
+    qxl->render_update_cookie_num++;
+    qemu_mutex_unlock(&qxl->ssd.lock);
+    cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
+                            0);
+    qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
+    qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
+                          0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
+}
+
+void qxl_render_update_area_bh(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+    qxl_render_update_area_unlocked(qxl);
+    qemu_mutex_unlock(&qxl->ssd.lock);
+}
+
+void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
+{
+    qemu_mutex_lock(&qxl->ssd.lock);
+    trace_qxl_render_update_area_done(cookie);
+    qemu_bh_schedule(qxl->update_area_bh);
+    qxl->render_update_cookie_num--;
+    qemu_mutex_unlock(&qxl->ssd.lock);
+    g_free(cookie);
+}
+
+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
+{
+    QEMUCursor *c;
+    uint8_t *image, *mask;
+    size_t size;
+
+    c = cursor_alloc(cursor->header.width, cursor->header.height);
+    c->hot_x = cursor->header.hot_spot_x;
+    c->hot_y = cursor->header.hot_spot_y;
+    switch (cursor->header.type) {
+    case SPICE_CURSOR_TYPE_ALPHA:
+        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
+        memcpy(c->data, cursor->chunk.data, size);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/alpha");
+        }
+        break;
+    case SPICE_CURSOR_TYPE_MONO:
+        mask  = cursor->chunk.data;
+        image = mask + cursor_get_mono_bpl(c) * c->width;
+        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/mono");
+        }
+        break;
+    default:
+        fprintf(stderr, "%s: not implemented: type %d\n",
+                __FUNCTION__, cursor->header.type);
+        goto fail;
+    }
+    return c;
+
+fail:
+    cursor_put(c);
+    return NULL;
+}
+
+
+/* called from spice server thread context only */
+int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+{
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    QXLCursor *cursor;
+    QEMUCursor *c;
+
+    if (!cmd) {
+        return 1;
+    }
+
+    if (!dpy_cursor_define_supported(qxl->vga.con)) {
+        return 0;
+    }
+
+    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
+        fprintf(stderr, "%s", __FUNCTION__);
+        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
+        fprintf(stderr, "\n");
+    }
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
+        if (!cursor) {
+            return 1;
+        }
+        if (cursor->chunk.data_size != cursor->data_size) {
+            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
+            return 1;
+        }
+        c = qxl_cursor(qxl, cursor);
+        if (c == NULL) {
+            c = cursor_builtin_left_ptr();
+        }
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.cursor) {
+            cursor_put(qxl->ssd.cursor);
+        }
+        qxl->ssd.cursor = c;
+        qxl->ssd.mouse_x = cmd->u.set.position.x;
+        qxl->ssd.mouse_y = cmd->u.set.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    case QXL_CURSOR_MOVE:
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qxl->ssd.mouse_x = cmd->u.position.x;
+        qxl->ssd.mouse_y = cmd->u.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    }
+    return 0;
+}
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
new file mode 100644 (file)
index 0000000..b66b414
--- /dev/null
@@ -0,0 +1,2365 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
+ * maintained by Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <zlib.h>
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "qemu/queue.h"
+#include "monitor/monitor.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+#include "hw/qxl.h"
+
+/*
+ * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
+ * such can be changed by the guest, so to avoid a guest trigerrable
+ * abort we just qxl_set_guest_bug and set the return to NULL. Still
+ * it may happen as a result of emulator bug as well.
+ */
+#undef SPICE_RING_PROD_ITEM
+#define SPICE_RING_PROD_ITEM(qxl, r, ret) {                             \
+        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
+        if (prod >= ARRAY_SIZE((r)->items)) {                           \
+            qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
+                          "%u >= %zu", prod, ARRAY_SIZE((r)->items));   \
+            ret = NULL;                                                 \
+        } else {                                                        \
+            ret = &(r)->items[prod].el;                                 \
+        }                                                               \
+    }
+
+#undef SPICE_RING_CONS_ITEM
+#define SPICE_RING_CONS_ITEM(qxl, r, ret) {                             \
+        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
+        if (cons >= ARRAY_SIZE((r)->items)) {                           \
+            qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \
+                          "%u >= %zu", cons, ARRAY_SIZE((r)->items));   \
+            ret = NULL;                                                 \
+        } else {                                                        \
+            ret = &(r)->items[cons].el;                                 \
+        }                                                               \
+    }
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
+
+#define QXL_MODE(_x, _y, _b, _o)                  \
+    {   .x_res = _x,                              \
+        .y_res = _y,                              \
+        .bits  = _b,                              \
+        .stride = (_x) * (_b) / 8,                \
+        .x_mili = PIXEL_SIZE * (_x),              \
+        .y_mili = PIXEL_SIZE * (_y),              \
+        .orientation = _o,                        \
+    }
+
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
+    QXL_MODE(x_res, y_res, 16, orientation),      \
+    QXL_MODE(x_res, y_res, 32, orientation)
+
+#define QXL_MODE_EX(x_res, y_res)                 \
+    QXL_MODE_16_32(x_res, y_res, 0),              \
+    QXL_MODE_16_32(x_res, y_res, 1)
+
+static QXLMode qxl_modes[] = {
+    QXL_MODE_EX(640, 480),
+    QXL_MODE_EX(800, 480),
+    QXL_MODE_EX(800, 600),
+    QXL_MODE_EX(832, 624),
+    QXL_MODE_EX(960, 640),
+    QXL_MODE_EX(1024, 600),
+    QXL_MODE_EX(1024, 768),
+    QXL_MODE_EX(1152, 864),
+    QXL_MODE_EX(1152, 870),
+    QXL_MODE_EX(1280, 720),
+    QXL_MODE_EX(1280, 760),
+    QXL_MODE_EX(1280, 768),
+    QXL_MODE_EX(1280, 800),
+    QXL_MODE_EX(1280, 960),
+    QXL_MODE_EX(1280, 1024),
+    QXL_MODE_EX(1360, 768),
+    QXL_MODE_EX(1366, 768),
+    QXL_MODE_EX(1400, 1050),
+    QXL_MODE_EX(1440, 900),
+    QXL_MODE_EX(1600, 900),
+    QXL_MODE_EX(1600, 1200),
+    QXL_MODE_EX(1680, 1050),
+    QXL_MODE_EX(1920, 1080),
+    /* these modes need more than 8 MB video memory */
+    QXL_MODE_EX(1920, 1200),
+    QXL_MODE_EX(1920, 1440),
+    QXL_MODE_EX(2048, 1536),
+    QXL_MODE_EX(2560, 1440),
+    QXL_MODE_EX(2560, 1600),
+    /* these modes need more than 16 MB video memory */
+    QXL_MODE_EX(2560, 2048),
+    QXL_MODE_EX(2800, 2100),
+    QXL_MODE_EX(3200, 2400),
+};
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
+static void qxl_reset_memslots(PCIQXLDevice *d);
+static void qxl_reset_surfaces(PCIQXLDevice *d);
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+
+void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+{
+    trace_qxl_set_guest_bug(qxl->id);
+    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+    qxl->guest_bug = 1;
+    if (qxl->guestdebug) {
+        va_list ap;
+        va_start(ap, msg);
+        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
+        vfprintf(stderr, msg, ap);
+        fprintf(stderr, "\n");
+        va_end(ap);
+    }
+}
+
+static void qxl_clear_guest_bug(PCIQXLDevice *qxl)
+{
+    qxl->guest_bug = 0;
+}
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async, struct QXLCookie *cookie)
+{
+    trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right,
+                                area->top, area->bottom);
+    trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects,
+                                     clear_dirty_region);
+    if (async == QXL_SYNC) {
+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
+                        dirty_rects, num_dirty_rects, clear_dirty_region);
+    } else {
+        assert(cookie != NULL);
+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
+                                    clear_dirty_region, (uintptr_t)cookie);
+    }
+}
+
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
+                                                    uint32_t id)
+{
+    trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_surfaces.cmds[id] = 0;
+    qxl->guest_surfaces.count--;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+                                           qxl_async_io async)
+{
+    QXLCookie *cookie;
+
+    trace_qxl_spice_destroy_surface_wait(qxl->id, id, async);
+    if (async) {
+        cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                QXL_IO_DESTROY_SURFACE_ASYNC);
+        cookie->u.surface_id = id;
+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
+    } else {
+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+        qxl_spice_destroy_surface_wait_complete(qxl, id);
+    }
+}
+
+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count,
+                                         qxl->num_free_res);
+    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl,
+        (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                  QXL_IO_FLUSH_SURFACES_ASYNC));
+}
+
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count)
+{
+    trace_qxl_spice_loadvm_commands(qxl->id, ext, count);
+    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
+}
+
+void qxl_spice_oom(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_oom(qxl->id);
+    qxl->ssd.worker->oom(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_memslots(qxl->id);
+    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+}
+
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_destroy_surfaces_complete(qxl->id);
+    qemu_mutex_lock(&qxl->track_lock);
+    memset(qxl->guest_surfaces.cmds, 0,
+           sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
+    qxl->guest_surfaces.count = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
+{
+    trace_qxl_spice_destroy_surfaces(qxl->id, async);
+    if (async) {
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_DESTROY_ALL_SURFACES_ASYNC));
+    } else {
+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+        qxl_spice_destroy_surfaces_complete(qxl);
+    }
+}
+
+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
+{
+    trace_qxl_spice_monitors_config(qxl->id);
+    if (replay) {
+        /*
+         * don't use QXL_COOKIE_TYPE_IO:
+         *  - we are not running yet (post_load), we will assert
+         *    in send_events
+         *  - this is not a guest io, but a reply, so async_io isn't set.
+         */
+        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+                qxl->guest_monitors_config,
+                MEMSLOT_GROUP_GUEST,
+                (uintptr_t)qxl_cookie_new(
+                    QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
+                    0));
+    } else {
+        qxl->guest_monitors_config = qxl->ram->monitors_config;
+        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+                qxl->ram->monitors_config,
+                MEMSLOT_GROUP_GUEST,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_MONITORS_CONFIG_ASYNC));
+    }
+}
+
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_image_cache(qxl->id);
+    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_cursor(qxl->id);
+    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_cursor = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+    if (qxl->ssd.cursor) {
+        cursor_put(qxl->ssd.cursor);
+    }
+    qxl->ssd.cursor = cursor_builtin_hidden();
+}
+
+
+static inline uint32_t msb_mask(uint32_t val)
+{
+    uint32_t mask;
+
+    do {
+        mask = ~(val - 1) & val;
+        val &= ~mask;
+    } while (mask < val);
+
+    return mask;
+}
+
+static ram_addr_t qxl_rom_size(void)
+{
+    uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
+                                 sizeof(qxl_modes);
+    uint32_t rom_size = 8192; /* two pages */
+
+    required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE);
+    required_rom_size = msb_mask(required_rom_size * 2 - 1);
+    assert(required_rom_size <= rom_size);
+    return rom_size;
+}
+
+static void init_qxl_rom(PCIQXLDevice *d)
+{
+    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
+    QXLModes *modes = (QXLModes *)(rom + 1);
+    uint32_t ram_header_size;
+    uint32_t surface0_area_size;
+    uint32_t num_pages;
+    uint32_t fb;
+    int i, n;
+
+    memset(rom, 0, d->rom_size);
+
+    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
+    rom->id            = cpu_to_le32(d->id);
+    rom->log_level     = cpu_to_le32(d->guestdebug);
+    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
+
+    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
+    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
+    rom->slots_start   = 1;
+    rom->slots_end     = NUM_MEMSLOTS - 1;
+    rom->n_surfaces    = cpu_to_le32(d->ssd.num_surfaces);
+
+    for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
+        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
+        if (fb > d->vgamem_size) {
+            continue;
+        }
+        modes->modes[n].id          = cpu_to_le32(i);
+        modes->modes[n].x_res       = cpu_to_le32(qxl_modes[i].x_res);
+        modes->modes[n].y_res       = cpu_to_le32(qxl_modes[i].y_res);
+        modes->modes[n].bits        = cpu_to_le32(qxl_modes[i].bits);
+        modes->modes[n].stride      = cpu_to_le32(qxl_modes[i].stride);
+        modes->modes[n].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
+        modes->modes[n].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
+        modes->modes[n].orientation = cpu_to_le32(qxl_modes[i].orientation);
+        n++;
+    }
+    modes->n_modes     = cpu_to_le32(n);
+
+    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
+    surface0_area_size = ALIGN(d->vgamem_size, 4096);
+    num_pages          = d->vga.vram_size;
+    num_pages         -= ram_header_size;
+    num_pages         -= surface0_area_size;
+    num_pages          = num_pages / TARGET_PAGE_SIZE;
+
+    rom->draw_area_offset   = cpu_to_le32(0);
+    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
+    rom->pages_offset       = cpu_to_le32(surface0_area_size);
+    rom->num_pages          = cpu_to_le32(num_pages);
+    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
+
+    d->shadow_rom = *rom;
+    d->rom        = rom;
+    d->modes      = modes;
+}
+
+static void init_qxl_ram(PCIQXLDevice *d)
+{
+    uint8_t *buf;
+    uint64_t *item;
+
+    buf = d->vga.vram_ptr;
+    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
+    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
+    d->ram->int_pending = cpu_to_le32(0);
+    d->ram->int_mask    = cpu_to_le32(0);
+    d->ram->update_surface = 0;
+    SPICE_RING_INIT(&d->ram->cmd_ring);
+    SPICE_RING_INIT(&d->ram->cursor_ring);
+    SPICE_RING_INIT(&d->ram->release_ring);
+    SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
+    assert(item);
+    *item = 0;
+    qxl_ring_set_dirty(d);
+}
+
+/* can be called from spice server thread context */
+static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
+{
+    memory_region_set_dirty(mr, addr, end - addr);
+}
+
+static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
+{
+    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
+}
+
+/* called from spice server thread context only */
+static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
+{
+    void *base = qxl->vga.vram_ptr;
+    intptr_t offset;
+
+    offset = ptr - base;
+    offset &= ~(TARGET_PAGE_SIZE-1);
+    assert(offset < qxl->vga.vram_size);
+    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
+}
+
+/* can be called from spice server thread context */
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
+{
+    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
+    ram_addr_t end  = qxl->vga.vram_size;
+    qxl_set_dirty(&qxl->vga.vram, addr, end);
+}
+
+/*
+ * keep track of some command state, for savevm/loadvm.
+ * called from spice server thread context only
+ */
+static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+{
+    switch (le32_to_cpu(ext->cmd.type)) {
+    case QXL_CMD_SURFACE:
+    {
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+
+        if (!cmd) {
+            return 1;
+        }
+        uint32_t id = le32_to_cpu(cmd->surface_id);
+
+        if (id >= qxl->ssd.num_surfaces) {
+            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
+                              qxl->ssd.num_surfaces);
+            return 1;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_CREATE &&
+            (cmd->u.surface_create.stride & 0x03) != 0) {
+            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
+                              cmd->u.surface_create.stride);
+            return 1;
+        }
+        qemu_mutex_lock(&qxl->track_lock);
+        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+            qxl->guest_surfaces.count++;
+            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
+                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+            qxl->guest_surfaces.cmds[id] = 0;
+            qxl->guest_surfaces.count--;
+        }
+        qemu_mutex_unlock(&qxl->track_lock);
+        break;
+    }
+    case QXL_CMD_CURSOR:
+    {
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+
+        if (!cmd) {
+            return 1;
+        }
+        if (cmd->type == QXL_CURSOR_SET) {
+            qemu_mutex_lock(&qxl->track_lock);
+            qxl->guest_cursor = ext->cmd.data;
+            qemu_mutex_unlock(&qxl->track_lock);
+        }
+        break;
+    }
+    }
+    return 0;
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_attach_worker(qxl->id);
+    qxl->ssd.worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_set_compression_level(qxl->id, level);
+    qxl->shadow_rom.compression_level = cpu_to_le32(level);
+    qxl->rom->compression_level = cpu_to_le32(level);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_set_mm_time(qxl->id, mm_time);
+    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
+    qxl->rom->mm_clock = cpu_to_le32(mm_time);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_get_init_info(qxl->id);
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
+    info->n_surfaces = qxl->ssd.num_surfaces;
+}
+
+static const char *qxl_mode_to_string(int mode)
+{
+    switch (mode) {
+    case QXL_MODE_COMPAT:
+        return "compat";
+    case QXL_MODE_NATIVE:
+        return "native";
+    case QXL_MODE_UNDEFINED:
+        return "undefined";
+    case QXL_MODE_VGA:
+        return "vga";
+    }
+    return "INVALID";
+}
+
+static const char *io_port_to_string(uint32_t io_port)
+{
+    if (io_port >= QXL_IO_RANGE_SIZE) {
+        return "out of range";
+    }
+    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
+        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
+        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
+        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
+        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
+        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
+        [QXL_IO_RESET]                  = "QXL_IO_RESET",
+        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
+        [QXL_IO_LOG]                    = "QXL_IO_LOG",
+        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
+        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
+        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
+        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
+        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
+        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
+        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
+        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
+        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
+        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
+        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
+        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
+                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
+        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
+    };
+    return io_port_to_string[io_port];
+}
+
+/* called from spice server thread context only */
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    SimpleSpiceUpdate *update;
+    QXLCommandRing *ring;
+    QXLCommand *cmd;
+    int notify, ret;
+
+    trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode));
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        ret = false;
+        qemu_mutex_lock(&qxl->ssd.lock);
+        update = QTAILQ_FIRST(&qxl->ssd.updates);
+        if (update != NULL) {
+            QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
+            *ext = update->ext;
+            ret = true;
+        }
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        if (ret) {
+            trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
+            qxl_log_command(qxl, "vga", ext);
+        }
+        return ret;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cmd_ring;
+        if (qxl->guest_bug || SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
+        if (!cmd) {
+            return false;
+        }
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "cmd", ext);
+        trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    trace_qxl_ring_command_req_notification(qxl->id);
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context only */
+static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
+{
+    QXLReleaseRing *ring = &d->ram->release_ring;
+    uint64_t *item;
+    int notify;
+
+#define QXL_FREE_BUNCH_SIZE 32
+
+    if (ring->prod - ring->cons + 1 == ring->num_items) {
+        /* ring full -- can't push */
+        return;
+    }
+    if (!flush && d->oom_running) {
+        /* collect everything from oom handler before pushing */
+        return;
+    }
+    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
+        /* collect a bit more before pushing */
+        return;
+    }
+
+    SPICE_RING_PUSH(ring, notify);
+    trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode),
+           d->guest_surfaces.count, d->num_free_res,
+           d->last_release, notify ? "yes" : "no");
+    trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons,
+           ring->num_items, ring->prod, ring->cons);
+    if (notify) {
+        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+    }
+    SPICE_RING_PROD_ITEM(d, ring, item);
+    if (!item) {
+        return;
+    }
+    *item = 0;
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    qxl_ring_set_dirty(d);
+}
+
+/* called from spice server thread context only */
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLReleaseRing *ring;
+    uint64_t *item, id;
+
+    if (ext.group_id == MEMSLOT_GROUP_HOST) {
+        /* host group -> vga mode update request */
+        qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id);
+        return;
+    }
+
+    /*
+     * ext->info points into guest-visible memory
+     * pci bar 0, $command.release_info
+     */
+    ring = &qxl->ram->release_ring;
+    SPICE_RING_PROD_ITEM(qxl, ring, item);
+    if (!item) {
+        return;
+    }
+    if (*item == 0) {
+        /* stick head into the ring */
+        id = ext.info->id;
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+        *item = id;
+        qxl_ring_set_dirty(qxl);
+    } else {
+        /* append item to the list */
+        qxl->last_release->next = ext.info->id;
+        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+    }
+    qxl->last_release = ext.info;
+    qxl->num_free_res++;
+    trace_qxl_ring_res_put(qxl->id, qxl->num_free_res);
+    qxl_push_free_res(qxl, 0);
+}
+
+/* called from spice server thread context only */
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCursorRing *ring;
+    QXLCommand *cmd;
+    int notify;
+
+    trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode));
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cursor_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
+        if (!cmd) {
+            return false;
+        }
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "csr", ext);
+        if (qxl->id == 0) {
+            qxl_render_cursor(qxl, ext);
+        }
+        trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    trace_qxl_ring_cursor_req_notification(qxl->id);
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context */
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    /*
+     * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in
+     * use by xf86-video-qxl and is defined out in the qxl windows driver.
+     * Probably was at some earlier version that is prior to git start (2009),
+     * and is still guest trigerrable.
+     */
+    fprintf(stderr, "%s: deprecated\n", __func__);
+}
+
+/* called from spice server thread context only */
+static int interface_flush_resources(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int ret;
+
+    ret = qxl->num_free_res;
+    if (ret) {
+        qxl_push_free_res(qxl, 1);
+    }
+    return ret;
+}
+
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
+
+/* called from spice server thread context only */
+static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
+{
+    uint32_t current_async;
+
+    qemu_mutex_lock(&qxl->async_lock);
+    current_async = qxl->current_async;
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qemu_mutex_unlock(&qxl->async_lock);
+
+    trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie);
+    if (!cookie) {
+        fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__);
+        return;
+    }
+    if (cookie && current_async != cookie->io) {
+        fprintf(stderr,
+                "qxl: %s: error: current_async = %d != %"
+                PRId64 " = cookie->io\n", __func__, current_async, cookie->io);
+    }
+    switch (current_async) {
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+    case QXL_IO_UPDATE_AREA_ASYNC:
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+        break;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        qxl_create_guest_primary_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        qxl_spice_destroy_surfaces_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
+        break;
+    default:
+        fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
+                current_async);
+    }
+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
+}
+
+/* called from spice server thread context only */
+static void interface_update_area_complete(QXLInstance *sin,
+        uint32_t surface_id,
+        QXLRect *dirty, uint32_t num_updated_rects)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int i;
+    int qxl_i;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+    if (surface_id != 0 || !qxl->render_update_cookie_num) {
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+    trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
+            dirty->right, dirty->top, dirty->bottom);
+    trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects);
+    if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) {
+        /*
+         * overflow - treat this as a full update. Not expected to be common.
+         */
+        trace_qxl_interface_update_area_complete_overflow(qxl->id,
+                                                          QXL_NUM_DIRTY_RECTS);
+        qxl->guest_primary.resized = 1;
+    }
+    if (qxl->guest_primary.resized) {
+        /*
+         * Don't bother copying or scheduling the bh since we will flip
+         * the whole area anyway on completion of the update_area async call
+         */
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+    qxl_i = qxl->num_dirty_rects;
+    for (i = 0; i < num_updated_rects; i++) {
+        qxl->dirty[qxl_i++] = dirty[i];
+    }
+    qxl->num_dirty_rects += num_updated_rects;
+    trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
+                                                         qxl->num_dirty_rects);
+    qemu_bh_schedule(qxl->update_area_bh);
+    qemu_mutex_unlock(&qxl->ssd.lock);
+}
+
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
+
+    switch (cookie->type) {
+    case QXL_COOKIE_TYPE_IO:
+        interface_async_complete_io(qxl, cookie);
+        g_free(cookie);
+        break;
+    case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
+        qxl_render_update_area_done(qxl, cookie);
+        break;
+    case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
+        break;
+    default:
+        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
+                __func__, cookie->type);
+        g_free(cookie);
+    }
+}
+
+/* called from spice server thread context only */
+static void interface_set_client_capabilities(QXLInstance *sin,
+                                              uint8_t client_present,
+                                              uint8_t caps[58])
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    if (qxl->revision < 4) {
+        trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id,
+                                                              qxl->revision);
+        return;
+    }
+
+    if (runstate_check(RUN_STATE_INMIGRATE) ||
+        runstate_check(RUN_STATE_POSTMIGRATE)) {
+        return;
+    }
+
+    qxl->shadow_rom.client_present = client_present;
+    memcpy(qxl->shadow_rom.client_capabilities, caps,
+           sizeof(qxl->shadow_rom.client_capabilities));
+    qxl->rom->client_present = client_present;
+    memcpy(qxl->rom->client_capabilities, caps,
+           sizeof(qxl->rom->client_capabilities));
+    qxl_rom_set_dirty(qxl);
+
+    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
+}
+
+static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
+{
+    /*
+     * zlib xors the seed with 0xffffffff, and xors the result
+     * again with 0xffffffff; Both are not done with linux's crc32,
+     * which we want to be compatible with, so undo that.
+     */
+    return crc32(0xffffffff, p, len) ^ 0xffffffff;
+}
+
+/* called from main context only */
+static int interface_client_monitors_config(QXLInstance *sin,
+                                        VDAgentMonitorsConfig *monitors_config)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
+    int i;
+
+    if (qxl->revision < 4) {
+        trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
+                                                               qxl->revision);
+        return 0;
+    }
+    /*
+     * Older windows drivers set int_mask to 0 when their ISR is called,
+     * then later set it to ~0. So it doesn't relate to the actual interrupts
+     * handled. However, they are old, so clearly they don't support this
+     * interrupt
+     */
+    if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
+        !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
+        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
+                                                            qxl->ram->int_mask,
+                                                            monitors_config);
+        return 0;
+    }
+    if (!monitors_config) {
+        return 1;
+    }
+    memset(&rom->client_monitors_config, 0,
+           sizeof(rom->client_monitors_config));
+    rom->client_monitors_config.count = monitors_config->num_of_monitors;
+    /* monitors_config->flags ignored */
+    if (rom->client_monitors_config.count >=
+            ARRAY_SIZE(rom->client_monitors_config.heads)) {
+        trace_qxl_client_monitors_config_capped(qxl->id,
+                                monitors_config->num_of_monitors,
+                                ARRAY_SIZE(rom->client_monitors_config.heads));
+        rom->client_monitors_config.count =
+            ARRAY_SIZE(rom->client_monitors_config.heads);
+    }
+    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
+        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
+        QXLURect *rect = &rom->client_monitors_config.heads[i];
+        /* monitor->depth ignored */
+        rect->left = monitor->x;
+        rect->top = monitor->y;
+        rect->right = monitor->x + monitor->width;
+        rect->bottom = monitor->y + monitor->height;
+    }
+    rom->client_monitors_config_crc = qxl_crc32(
+            (const uint8_t *)&rom->client_monitors_config,
+            sizeof(rom->client_monitors_config));
+    trace_qxl_client_monitors_config_crc(qxl->id,
+            sizeof(rom->client_monitors_config),
+            rom->client_monitors_config_crc);
+
+    trace_qxl_interrupt_client_monitors_config(qxl->id,
+                        rom->client_monitors_config.count,
+                        rom->client_monitors_config.heads);
+    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
+    return 1;
+}
+
+static const QXLInterface qxl_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qxl gpu",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+    .async_complete          = interface_async_complete,
+    .update_area_complete    = interface_update_area_complete,
+    .set_client_capabilities = interface_set_client_capabilities,
+    .client_monitors_config = interface_client_monitors_config,
+};
+
+static void qxl_enter_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_VGA) {
+        return;
+    }
+    trace_qxl_enter_vga_mode(d->id);
+    qemu_spice_create_host_primary(&d->ssd);
+    d->mode = QXL_MODE_VGA;
+    vga_dirty_log_start(&d->vga);
+    vga_hw_update();
+}
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode != QXL_MODE_VGA) {
+        return;
+    }
+    trace_qxl_exit_vga_mode(d->id);
+    vga_dirty_log_stop(&d->vga);
+    qxl_destroy_primary(d, QXL_SYNC);
+}
+
+static void qxl_update_irq(PCIQXLDevice *d)
+{
+    uint32_t pending = le32_to_cpu(d->ram->int_pending);
+    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
+    int level = !!(pending & mask);
+    qemu_set_irq(d->pci.irq[0], level);
+    qxl_ring_set_dirty(d);
+}
+
+static void qxl_check_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->ram;
+    int spice_display_running = qemu_spice_display_is_running(&d->ssd);
+
+    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+}
+
+static void qxl_reset_state(PCIQXLDevice *d)
+{
+    QXLRom *rom = d->rom;
+
+    qxl_check_state(d);
+    d->shadow_rom.update_id = cpu_to_le32(0);
+    *rom = d->shadow_rom;
+    qxl_rom_set_dirty(d);
+    init_qxl_ram(d);
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_soft_reset(PCIQXLDevice *d)
+{
+    trace_qxl_soft_reset(d->id);
+    qxl_check_state(d);
+    qxl_clear_guest_bug(d);
+    d->current_async = QXL_UNDEFINED_IO;
+
+    if (d->id == 0) {
+        qxl_enter_vga_mode(d);
+    } else {
+        d->mode = QXL_MODE_UNDEFINED;
+    }
+}
+
+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+{
+    trace_qxl_hard_reset(d->id, loadvm);
+
+    qxl_spice_reset_cursor(d);
+    qxl_spice_reset_image_cache(d);
+    qxl_reset_surfaces(d);
+    qxl_reset_memslots(d);
+
+    /* pre loadvm reset must not touch QXLRam.  This lives in
+     * device memory, is migrated together with RAM and thus
+     * already loaded at this point */
+    if (!loadvm) {
+        qxl_reset_state(d);
+    }
+    qemu_spice_create_host_memslot(&d->ssd);
+    qxl_soft_reset(d);
+}
+
+static void qxl_reset_handler(DeviceState *dev)
+{
+    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
+
+    qxl_hard_reset(d, 0);
+}
+
+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *vga = opaque;
+    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
+
+    trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val);
+    if (qxl->mode != QXL_MODE_VGA) {
+        qxl_destroy_primary(qxl, QXL_SYNC);
+        qxl_soft_reset(qxl);
+    }
+    vga_ioport_write(opaque, addr, val);
+}
+
+static const MemoryRegionPortio qxl_vga_portio_list[] = {
+    { 0x04,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
+
+static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
+                           qxl_async_io async)
+{
+    static const int regions[] = {
+        QXL_RAM_RANGE_INDEX,
+        QXL_VRAM_RANGE_INDEX,
+        QXL_VRAM64_RANGE_INDEX,
+    };
+    uint64_t guest_start;
+    uint64_t guest_end;
+    int pci_region;
+    pcibus_t pci_start;
+    pcibus_t pci_end;
+    intptr_t virt_start;
+    QXLDevMemSlot memslot;
+    int i;
+
+    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
+    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
+
+    trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end);
+
+    if (slot_id >= NUM_MEMSLOTS) {
+        qxl_set_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__,
+                      slot_id, NUM_MEMSLOTS);
+        return 1;
+    }
+    if (guest_start > guest_end) {
+        qxl_set_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64
+                         " > 0x%" PRIx64, __func__, guest_start, guest_end);
+        return 1;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
+        pci_region = regions[i];
+        pci_start = d->pci.io_regions[pci_region].addr;
+        pci_end = pci_start + d->pci.io_regions[pci_region].size;
+        /* mapped? */
+        if (pci_start == -1) {
+            continue;
+        }
+        /* start address in range ? */
+        if (guest_start < pci_start || guest_start > pci_end) {
+            continue;
+        }
+        /* end address in range ? */
+        if (guest_end > pci_end) {
+            continue;
+        }
+        /* passed */
+        break;
+    }
+    if (i == ARRAY_SIZE(regions)) {
+        qxl_set_guest_bug(d, "%s: finished loop without match", __func__);
+        return 1;
+    }
+
+    switch (pci_region) {
+    case QXL_RAM_RANGE_INDEX:
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
+        break;
+    case QXL_VRAM_RANGE_INDEX:
+    case 4 /* vram 64bit */:
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
+        break;
+    default:
+        /* should not happen */
+        qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region);
+        return 1;
+    }
+
+    memslot.slot_id = slot_id;
+    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
+    memslot.virt_start = virt_start + (guest_start - pci_start);
+    memslot.virt_end   = virt_start + (guest_end   - pci_start);
+    memslot.addr_delta = memslot.virt_start - delta;
+    memslot.generation = d->rom->slot_generation = 0;
+    qxl_rom_set_dirty(d);
+
+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
+    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
+    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
+    d->guest_slots[slot_id].delta = delta;
+    d->guest_slots[slot_id].active = 1;
+    return 0;
+}
+
+static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
+{
+    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
+    d->guest_slots[slot_id].active = 0;
+}
+
+static void qxl_reset_memslots(PCIQXLDevice *d)
+{
+    qxl_spice_reset_memslots(d);
+    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+}
+
+static void qxl_reset_surfaces(PCIQXLDevice *d)
+{
+    trace_qxl_reset_surfaces(d->id);
+    d->mode = QXL_MODE_UNDEFINED;
+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
+}
+
+/* can be also called from spice server thread context */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
+{
+    uint64_t phys   = le64_to_cpu(pqxl);
+    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
+    uint64_t offset = phys & 0xffffffffffff;
+
+    switch (group_id) {
+    case MEMSLOT_GROUP_HOST:
+        return (void *)(intptr_t)offset;
+    case MEMSLOT_GROUP_GUEST:
+        if (slot >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
+                              NUM_MEMSLOTS);
+            return NULL;
+        }
+        if (!qxl->guest_slots[slot].active) {
+            qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
+            return NULL;
+        }
+        if (offset < qxl->guest_slots[slot].delta) {
+            qxl_set_guest_bug(qxl,
+                          "slot %d offset %"PRIu64" < delta %"PRIu64"\n",
+                          slot, offset, qxl->guest_slots[slot].delta);
+            return NULL;
+        }
+        offset -= qxl->guest_slots[slot].delta;
+        if (offset > qxl->guest_slots[slot].size) {
+            qxl_set_guest_bug(qxl,
+                          "slot %d offset %"PRIu64" > size %"PRIu64"\n",
+                          slot, offset, qxl->guest_slots[slot].size);
+            return NULL;
+        }
+        return qxl->guest_slots[slot].ptr + offset;
+    }
+    return NULL;
+}
+
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
+{
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
+                                     qxl_async_io async)
+{
+    QXLDevSurfaceCreate surface;
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+    int size;
+    int requested_height = le32_to_cpu(sc->height);
+    int requested_stride = le32_to_cpu(sc->stride);
+
+    size = abs(requested_stride) * requested_height;
+    if (size > qxl->vgamem_size) {
+        qxl_set_guest_bug(qxl, "%s: requested primary larger then framebuffer"
+                               " size", __func__);
+        return;
+    }
+
+    if (qxl->mode == QXL_MODE_NATIVE) {
+        qxl_set_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE",
+                      __func__);
+    }
+    qxl_exit_vga_mode(qxl);
+
+    surface.format     = le32_to_cpu(sc->format);
+    surface.height     = le32_to_cpu(sc->height);
+    surface.mem        = le64_to_cpu(sc->mem);
+    surface.position   = le32_to_cpu(sc->position);
+    surface.stride     = le32_to_cpu(sc->stride);
+    surface.width      = le32_to_cpu(sc->width);
+    surface.type       = le32_to_cpu(sc->type);
+    surface.flags      = le32_to_cpu(sc->flags);
+    trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem,
+                                   sc->format, sc->position);
+    trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
+                                        sc->flags);
+
+    if ((surface.stride & 0x3) != 0) {
+        qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
+                          surface.stride);
+        return;
+    }
+
+    surface.mouse_mode = true;
+    surface.group_id   = MEMSLOT_GROUP_GUEST;
+    if (loadvm) {
+        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
+
+    qxl->mode = QXL_MODE_NATIVE;
+    qxl->cmdflags = 0;
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
+
+    if (async == QXL_SYNC) {
+        qxl_create_guest_primary_complete(qxl);
+    }
+}
+
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
+ * done (in QXL_SYNC case), 0 otherwise. */
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
+{
+    if (d->mode == QXL_MODE_UNDEFINED) {
+        return 0;
+    }
+    trace_qxl_destroy_primary(d->id);
+    d->mode = QXL_MODE_UNDEFINED;
+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+    qxl_spice_reset_cursor(d);
+    return 1;
+}
+
+static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+{
+    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
+    QXLMode *mode = d->modes->modes + modenr;
+    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    QXLMemSlot slot = {
+        .mem_start = start,
+        .mem_end = end
+    };
+    QXLSurfaceCreate surface = {
+        .width      = mode->x_res,
+        .height     = mode->y_res,
+        .stride     = -mode->x_res * 4,
+        .format     = SPICE_SURFACE_FMT_32_xRGB,
+        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
+        .mouse_mode = true,
+        .mem        = devmem + d->shadow_rom.draw_area_offset,
+    };
+
+    trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits,
+                       devmem);
+    if (!loadvm) {
+        qxl_hard_reset(d, 0);
+    }
+
+    d->guest_slots[0].slot = slot;
+    assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0);
+
+    d->guest_primary.surface = surface;
+    qxl_create_guest_primary(d, 0, QXL_SYNC);
+
+    d->mode = QXL_MODE_COMPAT;
+    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
+    if (mode->bits == 16) {
+        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
+    }
+    d->shadow_rom.mode = cpu_to_le32(modenr);
+    d->rom->mode = cpu_to_le32(modenr);
+    qxl_rom_set_dirty(d);
+}
+
+static void ioport_write(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+    PCIQXLDevice *d = opaque;
+    uint32_t io_port = addr;
+    qxl_async_io async = QXL_SYNC;
+    uint32_t orig_io_port = io_port;
+
+    if (d->guest_bug && io_port != QXL_IO_RESET) {
+        return;
+    }
+
+    if (d->revision <= QXL_REVISION_STABLE_V10 &&
+        io_port > QXL_IO_FLUSH_RELEASE) {
+        qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
+            io_port, d->revision);
+        return;
+    }
+
+    switch (io_port) {
+    case QXL_IO_RESET:
+    case QXL_IO_SET_MODE:
+    case QXL_IO_MEMSLOT_ADD:
+    case QXL_IO_MEMSLOT_DEL:
+    case QXL_IO_CREATE_PRIMARY:
+    case QXL_IO_UPDATE_IRQ:
+    case QXL_IO_LOG:
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        break;
+    default:
+        if (d->mode != QXL_MODE_VGA) {
+            break;
+        }
+        trace_qxl_io_unexpected_vga_mode(d->id,
+            addr, val, io_port_to_string(io_port));
+        /* be nice to buggy guest drivers */
+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+            io_port < QXL_IO_RANGE_SIZE) {
+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        }
+        return;
+    }
+
+    /* we change the io_port to avoid ifdeffery in the main switch */
+    orig_io_port = io_port;
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA_ASYNC:
+        io_port = QXL_IO_UPDATE_AREA;
+        goto async_common;
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+        io_port = QXL_IO_MEMSLOT_ADD;
+        goto async_common;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        io_port = QXL_IO_CREATE_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+        io_port = QXL_IO_DESTROY_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
+        goto async_common;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
+        goto async_common;
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+async_common:
+        async = QXL_ASYNC;
+        qemu_mutex_lock(&d->async_lock);
+        if (d->current_async != QXL_UNDEFINED_IO) {
+            qxl_set_guest_bug(d, "%d async started before last (%d) complete",
+                io_port, d->current_async);
+            qemu_mutex_unlock(&d->async_lock);
+            return;
+        }
+        d->current_async = orig_io_port;
+        qemu_mutex_unlock(&d->async_lock);
+        break;
+    default:
+        break;
+    }
+    trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size,
+                       async);
+
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA:
+    {
+        QXLCookie *cookie = NULL;
+        QXLRect update = d->ram->update_area;
+
+        if (d->ram->update_surface > d->ssd.num_surfaces) {
+            qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
+                              d->ram->update_surface);
+            break;
+        }
+        if (update.left >= update.right || update.top >= update.bottom ||
+            update.left < 0 || update.top < 0) {
+            qxl_set_guest_bug(d,
+                    "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
+                    update.left, update.top, update.right, update.bottom);
+            break;
+        }
+        if (async == QXL_ASYNC) {
+            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                    QXL_IO_UPDATE_AREA_ASYNC);
+            cookie->u.area = update;
+        }
+        qxl_spice_update_area(d, d->ram->update_surface,
+                              cookie ? &cookie->u.area : &update,
+                              NULL, 0, 0, async, cookie);
+        break;
+    }
+    case QXL_IO_NOTIFY_CMD:
+        qemu_spice_wakeup(&d->ssd);
+        break;
+    case QXL_IO_NOTIFY_CURSOR:
+        qemu_spice_wakeup(&d->ssd);
+        break;
+    case QXL_IO_UPDATE_IRQ:
+        qxl_update_irq(d);
+        break;
+    case QXL_IO_NOTIFY_OOM:
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        d->oom_running = 1;
+        qxl_spice_oom(d);
+        d->oom_running = 0;
+        break;
+    case QXL_IO_SET_MODE:
+        qxl_set_mode(d, val, 0);
+        break;
+    case QXL_IO_LOG:
+        trace_qxl_io_log(d->id, d->ram->log_buf);
+        if (d->guestdebug) {
+            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
+                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
+        }
+        break;
+    case QXL_IO_RESET:
+        qxl_hard_reset(d, 0);
+        break;
+    case QXL_IO_MEMSLOT_ADD:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
+            break;
+        }
+        if (d->guest_slots[val].active) {
+            qxl_set_guest_bug(d,
+                        "QXL_IO_MEMSLOT_ADD: memory slot already active");
+            break;
+        }
+        d->guest_slots[val].slot = d->ram->mem_slot;
+        qxl_add_memslot(d, val, 0, async);
+        break;
+    case QXL_IO_MEMSLOT_DEL:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
+            break;
+        }
+        qxl_del_memslot(d, val);
+        break;
+    case QXL_IO_CREATE_PRIMARY:
+        if (val != 0) {
+            qxl_set_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        d->guest_primary.surface = d->ram->create_surface;
+        qxl_create_guest_primary(d, 0, async);
+        break;
+    case QXL_IO_DESTROY_PRIMARY:
+        if (val != 0) {
+            qxl_set_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        if (!qxl_destroy_primary(d, async)) {
+            trace_qxl_io_destroy_primary_ignored(d->id,
+                                                 qxl_mode_to_string(d->mode));
+            goto cancel_async;
+        }
+        break;
+    case QXL_IO_DESTROY_SURFACE_WAIT:
+        if (val >= d->ssd.num_surfaces) {
+            qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
+                             "%" PRIu64 " >= NUM_SURFACES", async, val);
+            goto cancel_async;
+        }
+        qxl_spice_destroy_surface_wait(d, val, async);
+        break;
+    case QXL_IO_FLUSH_RELEASE: {
+        QXLReleaseRing *ring = &d->ram->release_ring;
+        if (ring->prod - ring->cons + 1 == ring->num_items) {
+            fprintf(stderr,
+                "ERROR: no flush, full release ring [p%d,%dc]\n",
+                ring->prod, ring->cons);
+        }
+        qxl_push_free_res(d, 1 /* flush */);
+        break;
+    }
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+        qxl_spice_flush_surfaces_async(d);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES:
+        d->mode = QXL_MODE_UNDEFINED;
+        qxl_spice_destroy_surfaces(d, async);
+        break;
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+        qxl_spice_monitors_config_async(d, 0);
+        break;
+    default:
+        qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
+    }
+    return;
+cancel_async:
+    if (async) {
+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        qemu_mutex_lock(&d->async_lock);
+        d->current_async = QXL_UNDEFINED_IO;
+        qemu_mutex_unlock(&d->async_lock);
+    }
+}
+
+static uint64_t ioport_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    trace_qxl_io_read_unexpected(qxl->id);
+    return 0xff;
+}
+
+static const MemoryRegionOps qxl_io_ops = {
+    .read = ioport_read,
+    .write = ioport_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void pipe_read(void *opaque)
+{
+    PCIQXLDevice *d = opaque;
+    char dummy;
+    int len;
+
+    do {
+        len = read(d->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qxl_update_irq(d);
+}
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+{
+    uint32_t old_pending;
+    uint32_t le_events = cpu_to_le32(events);
+
+    trace_qxl_send_events(d->id, events);
+    if (!qemu_spice_display_is_running(&d->ssd)) {
+        /* spice-server tracks guest running state and should not do this */
+        fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
+                __func__);
+        trace_qxl_send_events_vm_stopped(d->id, events);
+        return;
+    }
+    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
+    if ((old_pending & le_events) == le_events) {
+        return;
+    }
+    if (qemu_thread_is_self(&d->main)) {
+        qxl_update_irq(d);
+    } else {
+        if (write(d->pipe[1], d, 1) != 1) {
+            dprint(d, 1, "%s: write to pipe failed\n", __func__);
+        }
+    }
+}
+
+static void init_pipe_signaling(PCIQXLDevice *d)
+{
+    if (pipe(d->pipe) < 0) {
+        fprintf(stderr, "%s:%s: qxl pipe creation failed\n",
+                __FILE__, __func__);
+        exit(1);
+    }
+    fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
+    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
+    fcntl(d->pipe[0], F_SETOWN, getpid());
+
+    qemu_thread_get_self(&d->main);
+    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
+}
+
+/* graphics console */
+
+static void qxl_hw_update(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        vga->update(vga);
+        break;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_invalidate(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    vga->invalidate(vga);
+}
+
+static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
+                               Error **errp)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        ppm_save(filename, qxl->ssd.ds, errp);
+        break;
+    case QXL_MODE_VGA:
+        vga->screen_dump(vga, filename, cswitch, errp);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        vga->text_update(vga, chardata);
+        return;
+    }
+}
+
+static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
+{
+    uintptr_t vram_start;
+    int i;
+
+    if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
+        return;
+    }
+
+    /* dirty the primary surface */
+    qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
+                  qxl->shadow_rom.surface0_area_size);
+
+    vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
+
+    /* dirty the off-screen surfaces */
+    for (i = 0; i < qxl->ssd.num_surfaces; i++) {
+        QXLSurfaceCmd *cmd;
+        intptr_t surface_offset;
+        int surface_size;
+
+        if (qxl->guest_surfaces.cmds[i] == 0) {
+            continue;
+        }
+
+        cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
+                            MEMSLOT_GROUP_GUEST);
+        assert(cmd);
+        assert(cmd->type == QXL_SURFACE_CMD_CREATE);
+        surface_offset = (intptr_t)qxl_phys2virt(qxl,
+                                                 cmd->u.surface_create.data,
+                                                 MEMSLOT_GROUP_GUEST);
+        assert(surface_offset);
+        surface_offset -= vram_start;
+        surface_size = cmd->u.surface_create.height *
+                       abs(cmd->u.surface_create.stride);
+        trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
+        qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
+    }
+}
+
+static void qxl_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    if (running) {
+        /*
+         * if qxl_send_events was called from spice server context before
+         * migration ended, qxl_update_irq for these events might not have been
+         * called
+         */
+         qxl_update_irq(qxl);
+    } else {
+        /* make sure surfaces are saved before migration */
+        qxl_dirty_surfaces(qxl);
+    }
+}
+
+/* display change listener */
+
+static void display_update(DisplayChangeListener *dcl,
+                           int x, int y, int w, int h)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_update(&qxl->ssd, x, y, w, h);
+    }
+}
+
+static void display_switch(DisplayChangeListener *dcl,
+                           struct DisplaySurface *surface)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    qxl->ssd.ds = surface;
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_switch(&qxl->ssd, surface);
+    }
+}
+
+static void display_refresh(DisplayChangeListener *dcl)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_refresh(&qxl->ssd);
+    } else {
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
+        qemu_mutex_unlock(&qxl->ssd.lock);
+    }
+}
+
+static DisplayChangeListenerOps display_listener_ops = {
+    .dpy_name        = "spice/qxl",
+    .dpy_gfx_update  = display_update,
+    .dpy_gfx_switch  = display_switch,
+    .dpy_refresh     = display_refresh,
+};
+
+static void qxl_init_ramsize(PCIQXLDevice *qxl)
+{
+    /* vga mode framebuffer / primary surface (bar 0, first part) */
+    if (qxl->vgamem_size_mb < 8) {
+        qxl->vgamem_size_mb = 8;
+    }
+    qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024;
+
+    /* vga ram (bar 0, total) */
+    if (qxl->ram_size_mb != -1) {
+        qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vga.vram_size < qxl->vgamem_size * 2) {
+        qxl->vga.vram_size = qxl->vgamem_size * 2;
+    }
+
+    /* vram32 (surfaces, 32bit, bar 1) */
+    if (qxl->vram32_size_mb != -1) {
+        qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024;
+    }
+    if (qxl->vram32_size < 4096) {
+        qxl->vram32_size = 4096;
+    }
+
+    /* vram (surfaces, 64bit, bar 4+5) */
+    if (qxl->vram_size_mb != -1) {
+        qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vram_size < qxl->vram32_size) {
+        qxl->vram_size = qxl->vram32_size;
+    }
+
+    if (qxl->revision == 1) {
+        qxl->vram32_size = 4096;
+        qxl->vram_size = 4096;
+    }
+    qxl->vgamem_size = msb_mask(qxl->vgamem_size * 2 - 1);
+    qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+    qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1);
+    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
+}
+
+static int qxl_init_common(PCIQXLDevice *qxl)
+{
+    uint8_t* config = qxl->pci.config;
+    uint32_t pci_device_rev;
+    uint32_t io_size;
+
+    qxl->mode = QXL_MODE_UNDEFINED;
+    qxl->generation = 1;
+    qxl->num_memslots = NUM_MEMSLOTS;
+    qemu_mutex_init(&qxl->track_lock);
+    qemu_mutex_init(&qxl->async_lock);
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qxl->guest_bug = 0;
+
+    switch (qxl->revision) {
+    case 1: /* spice 0.4 -- qxl-1 */
+        pci_device_rev = QXL_REVISION_STABLE_V04;
+        io_size = 8;
+        break;
+    case 2: /* spice 0.6 -- qxl-2 */
+        pci_device_rev = QXL_REVISION_STABLE_V06;
+        io_size = 16;
+        break;
+    case 3: /* qxl-3 */
+        pci_device_rev = QXL_REVISION_STABLE_V10;
+        io_size = 32; /* PCI region size must be pow2 */
+        break;
+    case 4: /* qxl-4 */
+        pci_device_rev = QXL_REVISION_STABLE_V12;
+        io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
+        break;
+    default:
+        error_report("Invalid revision %d for qxl device (max %d)",
+                     qxl->revision, QXL_DEFAULT_REVISION);
+        return -1;
+    }
+
+    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
+    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+
+    qxl->rom_size = qxl_rom_size();
+    memory_region_init_ram(&qxl->rom_bar, "qxl.vrom", qxl->rom_size);
+    vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
+    init_qxl_rom(qxl);
+    init_qxl_ram(qxl);
+
+    qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
+    memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
+    vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
+    memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
+                             0, qxl->vram32_size);
+
+    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
+                          "qxl-ioports", io_size);
+    if (qxl->id == 0) {
+        vga_dirty_log_start(&qxl->vga);
+    }
+    memory_region_set_flush_coalesced(&qxl->io_bar);
+
+
+    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
+
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
+
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
+
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar);
+
+    if (qxl->vram32_size < qxl->vram_size) {
+        /*
+         * Make the 64bit vram bar show up only in case it is
+         * configured to be larger than the 32bit vram bar.
+         */
+        pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH,
+                         &qxl->vram_bar);
+    }
+
+    /* print pci bar details */
+    dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
+           qxl->id == 0 ? "pri" : "sec",
+           qxl->vga.vram_size / (1024*1024));
+    dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
+           qxl->vram32_size / (1024*1024));
+    dprint(qxl, 1, "vram/64: %d MB %s\n",
+           qxl->vram_size / (1024*1024),
+           qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
+
+    qxl->ssd.qxl.base.sif = &qxl_interface.base;
+    qxl->ssd.qxl.id = qxl->id;
+    if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) {
+        error_report("qxl interface %d.%d not supported by spice-server",
+                     SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR);
+        return -1;
+    }
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+
+    init_pipe_signaling(qxl);
+    qxl_reset_state(qxl);
+
+    qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
+
+    return 0;
+}
+
+static int qxl_init_primary(PCIDevice *dev)
+{
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    VGACommonState *vga = &qxl->vga;
+    PortioList *qxl_vga_port_list = g_new(PortioList, 1);
+    DisplayState *ds;
+    int rc;
+
+    qxl->id = 0;
+    qxl_init_ramsize(qxl);
+    vga->vram_size_mb = qxl->vga.vram_size >> 20;
+    vga_common_init(vga);
+    vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
+    portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
+    portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
+
+    vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
+                                    qxl_hw_screen_dump, qxl_hw_text_update,
+                                    qxl);
+    qxl->ssd.con = vga->con,
+    qemu_spice_display_init_common(&qxl->ssd);
+
+    rc = qxl_init_common(qxl);
+    if (rc != 0) {
+        return rc;
+    }
+
+    qxl->ssd.dcl.ops = &display_listener_ops;
+    ds = qemu_console_displaystate(vga->con);
+    register_displaychangelistener(ds, &qxl->ssd.dcl);
+    return rc;
+}
+
+static int qxl_init_secondary(PCIDevice *dev)
+{
+    static int device_id = 1;
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+
+    qxl->id = device_id++;
+    qxl_init_ramsize(qxl);
+    memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size);
+    vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
+    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
+
+    return qxl_init_common(qxl);
+}
+
+static void qxl_pre_save(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+
+    trace_qxl_pre_save(d->id);
+    if (d->last_release == NULL) {
+        d->last_release_offset = 0;
+    } else {
+        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
+    }
+    assert(d->last_release_offset < d->vga.vram_size);
+}
+
+static int qxl_pre_load(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+
+    trace_qxl_pre_load(d->id);
+    qxl_hard_reset(d, 1);
+    qxl_exit_vga_mode(d);
+    return 0;
+}
+
+static void qxl_create_memslots(PCIQXLDevice *d)
+{
+    int i;
+
+    for (i = 0; i < NUM_MEMSLOTS; i++) {
+        if (!d->guest_slots[i].active) {
+            continue;
+        }
+        qxl_add_memslot(d, i, 0, QXL_SYNC);
+    }
+}
+
+static int qxl_post_load(void *opaque, int version)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+    QXLCommandExt *cmds;
+    int in, out, newmode;
+
+    assert(d->last_release_offset < d->vga.vram_size);
+    if (d->last_release_offset == 0) {
+        d->last_release = NULL;
+    } else {
+        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
+    }
+
+    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
+
+    trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode));
+    newmode = d->mode;
+    d->mode = QXL_MODE_UNDEFINED;
+
+    switch (newmode) {
+    case QXL_MODE_UNDEFINED:
+        qxl_create_memslots(d);
+        break;
+    case QXL_MODE_VGA:
+        qxl_create_memslots(d);
+        qxl_enter_vga_mode(d);
+        break;
+    case QXL_MODE_NATIVE:
+        qxl_create_memslots(d);
+        qxl_create_guest_primary(d, 1, QXL_SYNC);
+
+        /* replay surface-create and cursor-set commands */
+        cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
+        for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
+            if (d->guest_surfaces.cmds[in] == 0) {
+                continue;
+            }
+            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
+            cmds[out].cmd.type = QXL_CMD_SURFACE;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        if (d->guest_cursor) {
+            cmds[out].cmd.data = d->guest_cursor;
+            cmds[out].cmd.type = QXL_CMD_CURSOR;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        qxl_spice_loadvm_commands(d, cmds, out);
+        g_free(cmds);
+        if (d->guest_monitors_config) {
+            qxl_spice_monitors_config_async(d, 1);
+        }
+        break;
+    case QXL_MODE_COMPAT:
+        /* note: no need to call qxl_create_memslots, qxl_set_mode
+         * creates the mem slot. */
+        qxl_set_mode(d, d->shadow_rom.mode, 1);
+        break;
+    }
+    return 0;
+}
+
+#define QXL_SAVE_VERSION 21
+
+static bool qxl_monitors_config_needed(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    return qxl->guest_monitors_config != 0;
+}
+
+
+static VMStateDescription qxl_memslot = {
+    .name               = "qxl-memslot",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
+        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
+        VMSTATE_UINT32(active,         struct guest_slots),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_surface = {
+    .name               = "qxl-surface",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(width,      QXLSurfaceCreate),
+        VMSTATE_UINT32(height,     QXLSurfaceCreate),
+        VMSTATE_INT32(stride,      QXLSurfaceCreate),
+        VMSTATE_UINT32(format,     QXLSurfaceCreate),
+        VMSTATE_UINT32(position,   QXLSurfaceCreate),
+        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
+        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
+        VMSTATE_UINT32(type,       QXLSurfaceCreate),
+        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_vmstate_monitors_config = {
+    .name               = "qxl/monitors-config",
+    .version_id         = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static VMStateDescription qxl_vmstate = {
+    .name               = "qxl",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .pre_save           = qxl_pre_save,
+    .pre_load           = qxl_pre_load,
+    .post_load          = qxl_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
+        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
+        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
+        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
+        VMSTATE_UINT32(mode, PCIQXLDevice),
+        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+                             qxl_memslot, struct guest_slots),
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+                       qxl_surface, QXLSurfaceCreate),
+        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
+        VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
+                             ssd.num_surfaces, 0,
+                             vmstate_info_uint64, uint64_t),
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &qxl_vmstate_monitors_config,
+            .needed = qxl_monitors_config_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+static Property qxl_properties[] = {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
+        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
+        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
+        DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
+        DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
+static void qxl_primary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = qxl_init_primary;
+    k->romfile = "vgabios-qxl.bin";
+    k->vendor_id = REDHAT_PCI_VENDOR_ID;
+    k->device_id = QXL_DEVICE_ID_STABLE;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->desc = "Spice QXL GPU (primary, vga compatible)";
+    dc->reset = qxl_reset_handler;
+    dc->vmsd = &qxl_vmstate;
+    dc->props = qxl_properties;
+}
+
+static const TypeInfo qxl_primary_info = {
+    .name          = "qxl-vga",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_primary_class_init,
+};
+
+static void qxl_secondary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = qxl_init_secondary;
+    k->vendor_id = REDHAT_PCI_VENDOR_ID;
+    k->device_id = QXL_DEVICE_ID_STABLE;
+    k->class_id = PCI_CLASS_DISPLAY_OTHER;
+    dc->desc = "Spice QXL GPU (secondary)";
+    dc->reset = qxl_reset_handler;
+    dc->vmsd = &qxl_vmstate;
+    dc->props = qxl_properties;
+}
+
+static const TypeInfo qxl_secondary_info = {
+    .name          = "qxl",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_secondary_class_init,
+};
+
+static void qxl_register_types(void)
+{
+    type_register_static(&qxl_primary_info);
+    type_register_static(&qxl_secondary_info);
+}
+
+type_init(qxl_register_types)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
new file mode 100644 (file)
index 0000000..d9fcead
--- /dev/null
@@ -0,0 +1,1450 @@
+/*
+ * QEMU SM501 Device
+ *
+ * Copyright (c) 2008 Shin-ichiro KAWASAKI
+ *
+ * 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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "hw/hw.h"
+#include "hw/char/serial.h"
+#include "ui/console.h"
+#include "hw/arm/devices.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-addr.h"
+#include "qemu/range.h"
+#include "ui/pixel_ops.h"
+
+/*
+ * Status: 2010/05/07
+ *   - Minimum implementation for Linux console : mmio regs and CRT layer.
+ *   - 2D grapihcs acceleration partially supported : only fill rectangle.
+ *
+ * TODO:
+ *   - Panel support
+ *   - Touch panel support
+ *   - USB support
+ *   - UART support
+ *   - More 2D graphics engine support
+ *   - Performance tuning
+ */
+
+//#define DEBUG_SM501
+//#define DEBUG_BITBLT
+
+#ifdef DEBUG_SM501
+#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define SM501_DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+
+#define MMIO_BASE_OFFSET 0x3e00000
+
+/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
+
+/* System Configuration area */
+/* System config base */
+#define SM501_SYS_CONFIG               (0x000000)
+
+/* config 1 */
+#define SM501_SYSTEM_CONTROL           (0x000000)
+
+#define SM501_SYSCTRL_PANEL_TRISTATE   (1<<0)
+#define SM501_SYSCTRL_MEM_TRISTATE     (1<<1)
+#define SM501_SYSCTRL_CRT_TRISTATE     (1<<2)
+
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_1        (0<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_2        (1<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_4        (2<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_8        (3<<4)
+
+#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
+#define SM501_SYSCTRL_PCI_RETRY_DISABLE        (1<<7)
+#define SM501_SYSCTRL_PCI_SUBSYS_LOCK  (1<<11)
+#define SM501_SYSCTRL_PCI_BURST_READ_EN        (1<<15)
+
+/* miscellaneous control */
+
+#define SM501_MISC_CONTROL             (0x000004)
+
+#define SM501_MISC_BUS_SH              (0x0)
+#define SM501_MISC_BUS_PCI             (0x1)
+#define SM501_MISC_BUS_XSCALE          (0x2)
+#define SM501_MISC_BUS_NEC             (0x6)
+#define SM501_MISC_BUS_MASK            (0x7)
+
+#define SM501_MISC_VR_62MB             (1<<3)
+#define SM501_MISC_CDR_RESET           (1<<7)
+#define SM501_MISC_USB_LB              (1<<8)
+#define SM501_MISC_USB_SLAVE           (1<<9)
+#define SM501_MISC_BL_1                        (1<<10)
+#define SM501_MISC_MC                  (1<<11)
+#define SM501_MISC_DAC_POWER           (1<<12)
+#define SM501_MISC_IRQ_INVERT          (1<<16)
+#define SM501_MISC_SH                  (1<<17)
+
+#define SM501_MISC_HOLD_EMPTY          (0<<18)
+#define SM501_MISC_HOLD_8              (1<<18)
+#define SM501_MISC_HOLD_16             (2<<18)
+#define SM501_MISC_HOLD_24             (3<<18)
+#define SM501_MISC_HOLD_32             (4<<18)
+#define SM501_MISC_HOLD_MASK           (7<<18)
+
+#define SM501_MISC_FREQ_12             (1<<24)
+#define SM501_MISC_PNL_24BIT           (1<<25)
+#define SM501_MISC_8051_LE             (1<<26)
+
+
+
+#define SM501_GPIO31_0_CONTROL         (0x000008)
+#define SM501_GPIO63_32_CONTROL                (0x00000C)
+#define SM501_DRAM_CONTROL             (0x000010)
+
+/* command list */
+#define SM501_ARBTRTN_CONTROL          (0x000014)
+
+/* command list */
+#define SM501_COMMAND_LIST_STATUS      (0x000024)
+
+/* interrupt debug */
+#define SM501_RAW_IRQ_STATUS           (0x000028)
+#define SM501_RAW_IRQ_CLEAR            (0x000028)
+#define SM501_IRQ_STATUS               (0x00002C)
+#define SM501_IRQ_MASK                 (0x000030)
+#define SM501_DEBUG_CONTROL            (0x000034)
+
+/* power management */
+#define SM501_POWERMODE_P2X_SRC                (1<<29)
+#define SM501_POWERMODE_V2X_SRC                (1<<20)
+#define SM501_POWERMODE_M_SRC          (1<<12)
+#define SM501_POWERMODE_M1_SRC         (1<<4)
+
+#define SM501_CURRENT_GATE             (0x000038)
+#define SM501_CURRENT_CLOCK            (0x00003C)
+#define SM501_POWER_MODE_0_GATE                (0x000040)
+#define SM501_POWER_MODE_0_CLOCK       (0x000044)
+#define SM501_POWER_MODE_1_GATE                (0x000048)
+#define SM501_POWER_MODE_1_CLOCK       (0x00004C)
+#define SM501_SLEEP_MODE_GATE          (0x000050)
+#define SM501_POWER_MODE_CONTROL       (0x000054)
+
+/* power gates for units within the 501 */
+#define SM501_GATE_HOST                        (0)
+#define SM501_GATE_MEMORY              (1)
+#define SM501_GATE_DISPLAY             (2)
+#define SM501_GATE_2D_ENGINE           (3)
+#define SM501_GATE_CSC                 (4)
+#define SM501_GATE_ZVPORT              (5)
+#define SM501_GATE_GPIO                        (6)
+#define SM501_GATE_UART0               (7)
+#define SM501_GATE_UART1               (8)
+#define SM501_GATE_SSP                 (10)
+#define SM501_GATE_USB_HOST            (11)
+#define SM501_GATE_USB_GADGET          (12)
+#define SM501_GATE_UCONTROLLER         (17)
+#define SM501_GATE_AC97                        (18)
+
+/* panel clock */
+#define SM501_CLOCK_P2XCLK             (24)
+/* crt clock */
+#define SM501_CLOCK_V2XCLK             (16)
+/* main clock */
+#define SM501_CLOCK_MCLK               (8)
+/* SDRAM controller clock */
+#define SM501_CLOCK_M1XCLK             (0)
+
+/* config 2 */
+#define SM501_PCI_MASTER_BASE          (0x000058)
+#define SM501_ENDIAN_CONTROL           (0x00005C)
+#define SM501_DEVICEID                 (0x000060)
+/* 0x050100A0 */
+
+#define SM501_DEVICEID_SM501           (0x05010000)
+#define SM501_DEVICEID_IDMASK          (0xffff0000)
+#define SM501_DEVICEID_REVMASK         (0x000000ff)
+
+#define SM501_PLLCLOCK_COUNT           (0x000064)
+#define SM501_MISC_TIMING              (0x000068)
+#define SM501_CURRENT_SDRAM_CLOCK      (0x00006C)
+
+#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
+
+/* GPIO base */
+#define SM501_GPIO                     (0x010000)
+#define SM501_GPIO_DATA_LOW            (0x00)
+#define SM501_GPIO_DATA_HIGH           (0x04)
+#define SM501_GPIO_DDR_LOW             (0x08)
+#define SM501_GPIO_DDR_HIGH            (0x0C)
+#define SM501_GPIO_IRQ_SETUP           (0x10)
+#define SM501_GPIO_IRQ_STATUS          (0x14)
+#define SM501_GPIO_IRQ_RESET           (0x14)
+
+/* I2C controller base */
+#define SM501_I2C                      (0x010040)
+#define SM501_I2C_BYTE_COUNT           (0x00)
+#define SM501_I2C_CONTROL              (0x01)
+#define SM501_I2C_STATUS               (0x02)
+#define SM501_I2C_RESET                        (0x02)
+#define SM501_I2C_SLAVE_ADDRESS                (0x03)
+#define SM501_I2C_DATA                 (0x04)
+
+/* SSP base */
+#define SM501_SSP                      (0x020000)
+
+/* Uart 0 base */
+#define SM501_UART0                    (0x030000)
+
+/* Uart 1 base */
+#define SM501_UART1                    (0x030020)
+
+/* USB host port base */
+#define SM501_USB_HOST                 (0x040000)
+
+/* USB slave/gadget base */
+#define SM501_USB_GADGET               (0x060000)
+
+/* USB slave/gadget data port base */
+#define SM501_USB_GADGET_DATA          (0x070000)
+
+/* Display controller/video engine base */
+#define SM501_DC                       (0x080000)
+
+/* common defines for the SM501 address registers */
+#define SM501_ADDR_FLIP                        (1<<31)
+#define SM501_ADDR_EXT                 (1<<27)
+#define SM501_ADDR_CS1                 (1<<26)
+#define SM501_ADDR_MASK                        (0x3f << 26)
+
+#define SM501_FIFO_MASK                        (0x3 << 16)
+#define SM501_FIFO_1                   (0x0 << 16)
+#define SM501_FIFO_3                   (0x1 << 16)
+#define SM501_FIFO_7                   (0x2 << 16)
+#define SM501_FIFO_11                  (0x3 << 16)
+
+/* common registers for panel and the crt */
+#define SM501_OFF_DC_H_TOT             (0x000)
+#define SM501_OFF_DC_V_TOT             (0x008)
+#define SM501_OFF_DC_H_SYNC            (0x004)
+#define SM501_OFF_DC_V_SYNC            (0x00C)
+
+#define SM501_DC_PANEL_CONTROL         (0x000)
+
+#define SM501_DC_PANEL_CONTROL_FPEN    (1<<27)
+#define SM501_DC_PANEL_CONTROL_BIAS    (1<<26)
+#define SM501_DC_PANEL_CONTROL_DATA    (1<<25)
+#define SM501_DC_PANEL_CONTROL_VDD     (1<<24)
+#define SM501_DC_PANEL_CONTROL_DP      (1<<23)
+
+#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
+
+#define SM501_DC_PANEL_CONTROL_DE      (1<<20)
+
+#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN8        (1<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
+
+#define SM501_DC_PANEL_CONTROL_CP      (1<<14)
+#define SM501_DC_PANEL_CONTROL_VSP     (1<<13)
+#define SM501_DC_PANEL_CONTROL_HSP     (1<<12)
+#define SM501_DC_PANEL_CONTROL_CK      (1<<9)
+#define SM501_DC_PANEL_CONTROL_TE      (1<<8)
+#define SM501_DC_PANEL_CONTROL_VPD     (1<<7)
+#define SM501_DC_PANEL_CONTROL_VP      (1<<6)
+#define SM501_DC_PANEL_CONTROL_HPD     (1<<5)
+#define SM501_DC_PANEL_CONTROL_HP      (1<<4)
+#define SM501_DC_PANEL_CONTROL_GAMMA   (1<<3)
+#define SM501_DC_PANEL_CONTROL_EN      (1<<2)
+
+#define SM501_DC_PANEL_CONTROL_8BPP    (0<<0)
+#define SM501_DC_PANEL_CONTROL_16BPP   (1<<0)
+#define SM501_DC_PANEL_CONTROL_32BPP   (2<<0)
+
+
+#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
+#define SM501_DC_PANEL_COLOR_KEY       (0x008)
+#define SM501_DC_PANEL_FB_ADDR         (0x00C)
+#define SM501_DC_PANEL_FB_OFFSET       (0x010)
+#define SM501_DC_PANEL_FB_WIDTH                (0x014)
+#define SM501_DC_PANEL_FB_HEIGHT       (0x018)
+#define SM501_DC_PANEL_TL_LOC          (0x01C)
+#define SM501_DC_PANEL_BR_LOC          (0x020)
+#define SM501_DC_PANEL_H_TOT           (0x024)
+#define SM501_DC_PANEL_H_SYNC          (0x028)
+#define SM501_DC_PANEL_V_TOT           (0x02C)
+#define SM501_DC_PANEL_V_SYNC          (0x030)
+#define SM501_DC_PANEL_CUR_LINE                (0x034)
+
+#define SM501_DC_VIDEO_CONTROL         (0x040)
+#define SM501_DC_VIDEO_FB0_ADDR                (0x044)
+#define SM501_DC_VIDEO_FB_WIDTH                (0x048)
+#define SM501_DC_VIDEO_FB0_LAST_ADDR   (0x04C)
+#define SM501_DC_VIDEO_TL_LOC          (0x050)
+#define SM501_DC_VIDEO_BR_LOC          (0x054)
+#define SM501_DC_VIDEO_SCALE           (0x058)
+#define SM501_DC_VIDEO_INIT_SCALE      (0x05C)
+#define SM501_DC_VIDEO_YUV_CONSTANTS   (0x060)
+#define SM501_DC_VIDEO_FB1_ADDR                (0x064)
+#define SM501_DC_VIDEO_FB1_LAST_ADDR   (0x068)
+
+#define SM501_DC_VIDEO_ALPHA_CONTROL   (0x080)
+#define SM501_DC_VIDEO_ALPHA_FB_ADDR   (0x084)
+#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
+#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR      (0x08C)
+#define SM501_DC_VIDEO_ALPHA_TL_LOC    (0x090)
+#define SM501_DC_VIDEO_ALPHA_BR_LOC    (0x094)
+#define SM501_DC_VIDEO_ALPHA_SCALE     (0x098)
+#define SM501_DC_VIDEO_ALPHA_INIT_SCALE        (0x09C)
+#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY        (0x0A0)
+#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP      (0x0A4)
+
+#define SM501_DC_PANEL_HWC_BASE                (0x0F0)
+#define SM501_DC_PANEL_HWC_ADDR                (0x0F0)
+#define SM501_DC_PANEL_HWC_LOC         (0x0F4)
+#define SM501_DC_PANEL_HWC_COLOR_1_2   (0x0F8)
+#define SM501_DC_PANEL_HWC_COLOR_3     (0x0FC)
+
+#define SM501_HWC_EN                   (1<<31)
+
+#define SM501_OFF_HWC_ADDR             (0x00)
+#define SM501_OFF_HWC_LOC              (0x04)
+#define SM501_OFF_HWC_COLOR_1_2                (0x08)
+#define SM501_OFF_HWC_COLOR_3          (0x0C)
+
+#define SM501_DC_ALPHA_CONTROL         (0x100)
+#define SM501_DC_ALPHA_FB_ADDR         (0x104)
+#define SM501_DC_ALPHA_FB_OFFSET       (0x108)
+#define SM501_DC_ALPHA_TL_LOC          (0x10C)
+#define SM501_DC_ALPHA_BR_LOC          (0x110)
+#define SM501_DC_ALPHA_CHROMA_KEY      (0x114)
+#define SM501_DC_ALPHA_COLOR_LOOKUP    (0x118)
+
+#define SM501_DC_CRT_CONTROL           (0x200)
+
+#define SM501_DC_CRT_CONTROL_TVP       (1<<15)
+#define SM501_DC_CRT_CONTROL_CP                (1<<14)
+#define SM501_DC_CRT_CONTROL_VSP       (1<<13)
+#define SM501_DC_CRT_CONTROL_HSP       (1<<12)
+#define SM501_DC_CRT_CONTROL_VS                (1<<11)
+#define SM501_DC_CRT_CONTROL_BLANK     (1<<10)
+#define SM501_DC_CRT_CONTROL_SEL       (1<<9)
+#define SM501_DC_CRT_CONTROL_TE                (1<<8)
+#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
+#define SM501_DC_CRT_CONTROL_GAMMA     (1<<3)
+#define SM501_DC_CRT_CONTROL_ENABLE    (1<<2)
+
+#define SM501_DC_CRT_CONTROL_8BPP      (0<<0)
+#define SM501_DC_CRT_CONTROL_16BPP     (1<<0)
+#define SM501_DC_CRT_CONTROL_32BPP     (2<<0)
+
+#define SM501_DC_CRT_FB_ADDR           (0x204)
+#define SM501_DC_CRT_FB_OFFSET         (0x208)
+#define SM501_DC_CRT_H_TOT             (0x20C)
+#define SM501_DC_CRT_H_SYNC            (0x210)
+#define SM501_DC_CRT_V_TOT             (0x214)
+#define SM501_DC_CRT_V_SYNC            (0x218)
+#define SM501_DC_CRT_SIGNATURE_ANALYZER        (0x21C)
+#define SM501_DC_CRT_CUR_LINE          (0x220)
+#define SM501_DC_CRT_MONITOR_DETECT    (0x224)
+
+#define SM501_DC_CRT_HWC_BASE          (0x230)
+#define SM501_DC_CRT_HWC_ADDR          (0x230)
+#define SM501_DC_CRT_HWC_LOC           (0x234)
+#define SM501_DC_CRT_HWC_COLOR_1_2     (0x238)
+#define SM501_DC_CRT_HWC_COLOR_3       (0x23C)
+
+#define SM501_DC_PANEL_PALETTE         (0x400)
+
+#define SM501_DC_VIDEO_PALETTE         (0x800)
+
+#define SM501_DC_CRT_PALETTE           (0xC00)
+
+/* Zoom Video port base */
+#define SM501_ZVPORT                   (0x090000)
+
+/* AC97/I2S base */
+#define SM501_AC97                     (0x0A0000)
+
+/* 8051 micro controller base */
+#define SM501_UCONTROLLER              (0x0B0000)
+
+/* 8051 micro controller SRAM base */
+#define SM501_UCONTROLLER_SRAM         (0x0C0000)
+
+/* DMA base */
+#define SM501_DMA                      (0x0D0000)
+
+/* 2d engine base */
+#define SM501_2D_ENGINE                        (0x100000)
+#define SM501_2D_SOURCE                        (0x00)
+#define SM501_2D_DESTINATION           (0x04)
+#define SM501_2D_DIMENSION             (0x08)
+#define SM501_2D_CONTROL               (0x0C)
+#define SM501_2D_PITCH                 (0x10)
+#define SM501_2D_FOREGROUND            (0x14)
+#define SM501_2D_BACKGROUND            (0x18)
+#define SM501_2D_STRETCH               (0x1C)
+#define SM501_2D_COLOR_COMPARE         (0x20)
+#define SM501_2D_COLOR_COMPARE_MASK    (0x24)
+#define SM501_2D_MASK                  (0x28)
+#define SM501_2D_CLIP_TL               (0x2C)
+#define SM501_2D_CLIP_BR               (0x30)
+#define SM501_2D_MONO_PATTERN_LOW      (0x34)
+#define SM501_2D_MONO_PATTERN_HIGH     (0x38)
+#define SM501_2D_WINDOW_WIDTH          (0x3C)
+#define SM501_2D_SOURCE_BASE           (0x40)
+#define SM501_2D_DESTINATION_BASE      (0x44)
+#define SM501_2D_ALPHA                 (0x48)
+#define SM501_2D_WRAP                  (0x4C)
+#define SM501_2D_STATUS                        (0x50)
+
+#define SM501_CSC_Y_SOURCE_BASE                (0xC8)
+#define SM501_CSC_CONSTANTS            (0xCC)
+#define SM501_CSC_Y_SOURCE_X           (0xD0)
+#define SM501_CSC_Y_SOURCE_Y           (0xD4)
+#define SM501_CSC_U_SOURCE_BASE                (0xD8)
+#define SM501_CSC_V_SOURCE_BASE                (0xDC)
+#define SM501_CSC_SOURCE_DIMENSION     (0xE0)
+#define SM501_CSC_SOURCE_PITCH         (0xE4)
+#define SM501_CSC_DESTINATION          (0xE8)
+#define SM501_CSC_DESTINATION_DIMENSION        (0xEC)
+#define SM501_CSC_DESTINATION_PITCH    (0xF0)
+#define SM501_CSC_SCALE_FACTOR         (0xF4)
+#define SM501_CSC_DESTINATION_BASE     (0xF8)
+#define SM501_CSC_CONTROL              (0xFC)
+
+/* 2d engine data port base */
+#define SM501_2D_ENGINE_DATA           (0x110000)
+
+/* end of register definitions */
+
+#define SM501_HWC_WIDTH                       (64)
+#define SM501_HWC_HEIGHT                      (64)
+
+/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
+static const uint32_t sm501_mem_local_size[] = {
+       [0]     = 4*1024*1024,
+       [1]     = 8*1024*1024,
+       [2]     = 16*1024*1024,
+       [3]     = 32*1024*1024,
+       [4]     = 64*1024*1024,
+       [5]     = 2*1024*1024,
+};
+#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
+
+typedef struct SM501State {
+    /* graphic console status */
+    QemuConsole *con;
+
+    /* status & internal resources */
+    hwaddr base;
+    uint32_t local_mem_size_index;
+    uint8_t * local_mem;
+    MemoryRegion local_mem_region;
+    uint32_t last_width;
+    uint32_t last_height;
+
+    /* mmio registers */
+    uint32_t system_control;
+    uint32_t misc_control;
+    uint32_t gpio_31_0_control;
+    uint32_t gpio_63_32_control;
+    uint32_t dram_control;
+    uint32_t irq_mask;
+    uint32_t misc_timing;
+    uint32_t power_mode_control;
+
+    uint32_t uart0_ier;
+    uint32_t uart0_lcr;
+    uint32_t uart0_mcr;
+    uint32_t uart0_scr;
+
+    uint8_t dc_palette[0x400 * 3];
+
+    uint32_t dc_panel_control;
+    uint32_t dc_panel_panning_control;
+    uint32_t dc_panel_fb_addr;
+    uint32_t dc_panel_fb_offset;
+    uint32_t dc_panel_fb_width;
+    uint32_t dc_panel_fb_height;
+    uint32_t dc_panel_tl_location;
+    uint32_t dc_panel_br_location;
+    uint32_t dc_panel_h_total;
+    uint32_t dc_panel_h_sync;
+    uint32_t dc_panel_v_total;
+    uint32_t dc_panel_v_sync;
+
+    uint32_t dc_panel_hwc_addr;
+    uint32_t dc_panel_hwc_location;
+    uint32_t dc_panel_hwc_color_1_2;
+    uint32_t dc_panel_hwc_color_3;
+
+    uint32_t dc_crt_control;
+    uint32_t dc_crt_fb_addr;
+    uint32_t dc_crt_fb_offset;
+    uint32_t dc_crt_h_total;
+    uint32_t dc_crt_h_sync;
+    uint32_t dc_crt_v_total;
+    uint32_t dc_crt_v_sync;
+
+    uint32_t dc_crt_hwc_addr;
+    uint32_t dc_crt_hwc_location;
+    uint32_t dc_crt_hwc_color_1_2;
+    uint32_t dc_crt_hwc_color_3;
+
+    uint32_t twoD_source;
+    uint32_t twoD_destination;
+    uint32_t twoD_dimension;
+    uint32_t twoD_control;
+    uint32_t twoD_pitch;
+    uint32_t twoD_foreground;
+    uint32_t twoD_stretch;
+    uint32_t twoD_color_compare_mask;
+    uint32_t twoD_mask;
+    uint32_t twoD_window_width;
+    uint32_t twoD_source_base;
+    uint32_t twoD_destination_base;
+
+} SM501State;
+
+static uint32_t get_local_mem_size_index(uint32_t size)
+{
+    uint32_t norm_size = 0;
+    int i, index = 0;
+
+    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
+       uint32_t new_size = sm501_mem_local_size[i];
+       if (new_size >= size) {
+           if (norm_size == 0 || norm_size > new_size) {
+               norm_size = new_size;
+               index = i;
+           }
+       }
+    }
+
+    return index;
+}
+
+/**
+ * Check the availability of hardware cursor.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline int is_hwc_enabled(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return addr & 0x80000000;
+}
+
+/**
+ * Get the address which holds cursor pattern data.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_address(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return (addr & 0x03FFFFF0)/* >> 4*/;
+}
+
+/**
+ * Get the cursor position in y coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_y(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return (location & 0x07FF0000) >> 16;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_x(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return location & 0x000007FF;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
+ */
+static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
+{
+    uint32_t color_reg = 0;
+    uint16_t color_565 = 0;
+
+    if (index == 0) {
+        return 0;
+    }
+
+    switch (index) {
+    case 1:
+    case 2:
+        color_reg = crt ? state->dc_crt_hwc_color_1_2
+                        : state->dc_panel_hwc_color_1_2;
+        break;
+    case 3:
+        color_reg = crt ? state->dc_crt_hwc_color_3
+                        : state->dc_panel_hwc_color_3;
+        break;
+    default:
+        printf("invalid hw cursor color.\n");
+        abort();
+    }
+
+    switch (index) {
+    case 1:
+    case 3:
+        color_565 = (uint16_t)(color_reg & 0xFFFF);
+        break;
+    case 2:
+        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
+        break;
+    }
+    return color_565;
+}
+
+static int within_hwc_y_range(SM501State *state, int y, int crt)
+{
+    int hwc_y = get_hwc_y(state, crt);
+    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
+}
+
+static void sm501_2d_operation(SM501State * s)
+{
+    /* obtain operation parameters */
+    int operation = (s->twoD_control >> 16) & 0x1f;
+    int rtl = s->twoD_control & 0x8000000;
+    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+    int src_y = s->twoD_source & 0xFFFF;
+    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+    int dst_y = s->twoD_destination & 0xFFFF;
+    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
+    int operation_height = s->twoD_dimension & 0xFFFF;
+    uint32_t color = s->twoD_foreground;
+    int format_flags = (s->twoD_stretch >> 20) & 0x3;
+    int addressing = (s->twoD_stretch >> 16) & 0xF;
+
+    /* get frame buffer info */
+    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
+    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+
+    if (addressing != 0x0) {
+        printf("%s: only XY addressing is supported.\n", __func__);
+        abort();
+    }
+
+    if ((s->twoD_source_base & 0x08000000) ||
+        (s->twoD_destination_base & 0x08000000)) {
+        printf("%s: only local memory is supported.\n", __func__);
+        abort();
+    }
+
+    switch (operation) {
+    case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
+        int y, x, index_d, index_s;                                         \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                if (rtl) {                                                  \
+                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+                } else {                                                    \
+                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+                }                                                           \
+                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+            }                                                               \
+        }                                                                   \
+    }
+        switch (format_flags) {
+        case 0:
+            COPY_AREA(1, uint8_t, rtl);
+            break;
+        case 1:
+            COPY_AREA(2, uint16_t, rtl);
+            break;
+        case 2:
+            COPY_AREA(4, uint32_t, rtl);
+            break;
+        }
+        break;
+
+    case 0x01: /* fill rectangle */
+#define FILL_RECT(_bpp, _pixel_type) {                                      \
+        int y, x;                                                           \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
+            }                                                               \
+        }                                                                   \
+    }
+
+        switch (format_flags) {
+        case 0:
+            FILL_RECT(1, uint8_t);
+            break;
+        case 1:
+            FILL_RECT(2, uint16_t);
+            break;
+        case 2:
+            FILL_RECT(4, uint32_t);
+            break;
+        }
+        break;
+
+    default:
+        printf("non-implemented SM501 2D operation. %d\n", operation);
+        abort();
+        break;
+    }
+}
+
+static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
+                                         unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+       ret = s->system_control;
+       break;
+    case SM501_MISC_CONTROL:
+       ret = s->misc_control;
+       break;
+    case SM501_GPIO31_0_CONTROL:
+       ret = s->gpio_31_0_control;
+       break;
+    case SM501_GPIO63_32_CONTROL:
+       ret = s->gpio_63_32_control;
+       break;
+    case SM501_DEVICEID:
+       ret = 0x050100A0;
+       break;
+    case SM501_DRAM_CONTROL:
+       ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
+       break;
+    case SM501_IRQ_MASK:
+       ret = s->irq_mask;
+       break;
+    case SM501_MISC_TIMING:
+       /* TODO : simulate gate control */
+       ret = s->misc_timing;
+       break;
+    case SM501_CURRENT_GATE:
+       /* TODO : simulate gate control */
+       ret = 0x00021807;
+       break;
+    case SM501_CURRENT_CLOCK:
+       ret = 0x2A1A0A09;
+       break;
+    case SM501_POWER_MODE_CONTROL:
+       ret = s->power_mode_control;
+       break;
+
+    default:
+       printf("sm501 system config : not implemented register read."
+              " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_system_config_write(void *opaque, hwaddr addr,
+                                      uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
+                 (uint32_t)addr, (uint32_t)value);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+       s->system_control = value & 0xE300B8F7;
+       break;
+    case SM501_MISC_CONTROL:
+       s->misc_control = value & 0xFF7FFF20;
+       break;
+    case SM501_GPIO31_0_CONTROL:
+       s->gpio_31_0_control = value;
+       break;
+    case SM501_GPIO63_32_CONTROL:
+       s->gpio_63_32_control = value;
+       break;
+    case SM501_DRAM_CONTROL:
+       s->local_mem_size_index = (value >> 13) & 0x7;
+       /* rODO : check validity of size change */
+       s->dram_control |=  value & 0x7FFFFFC3;
+       break;
+    case SM501_IRQ_MASK:
+       s->irq_mask = value;
+       break;
+    case SM501_MISC_TIMING:
+       s->misc_timing = value & 0xF31F1FFF;
+       break;
+    case SM501_POWER_MODE_0_GATE:
+    case SM501_POWER_MODE_1_GATE:
+    case SM501_POWER_MODE_0_CLOCK:
+    case SM501_POWER_MODE_1_CLOCK:
+       /* TODO : simulate gate & clock control */
+       break;
+    case SM501_POWER_MODE_CONTROL:
+       s->power_mode_control = value & 0x00000003;
+       break;
+
+    default:
+       printf("sm501 system config : not implemented register write."
+              " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_system_config_ops = {
+    .read = sm501_system_config_read,
+    .write = sm501_system_config_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    return *(uint32_t*)&s->dc_palette[addr];
+}
+
+static void sm501_palette_write(void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
+                 (int)addr, value);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    *(uint32_t*)&s->dc_palette[addr] = value;
+}
+
+static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+
+    case SM501_DC_PANEL_CONTROL:
+       ret = s->dc_panel_control;
+       break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+       ret = s->dc_panel_panning_control;
+       break;
+    case SM501_DC_PANEL_FB_ADDR:
+       ret = s->dc_panel_fb_addr;
+       break;
+    case SM501_DC_PANEL_FB_OFFSET:
+       ret = s->dc_panel_fb_offset;
+       break;
+    case SM501_DC_PANEL_FB_WIDTH:
+       ret = s->dc_panel_fb_width;
+       break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+       ret = s->dc_panel_fb_height;
+       break;
+    case SM501_DC_PANEL_TL_LOC:
+       ret = s->dc_panel_tl_location;
+       break;
+    case SM501_DC_PANEL_BR_LOC:
+       ret = s->dc_panel_br_location;
+       break;
+
+    case SM501_DC_PANEL_H_TOT:
+       ret = s->dc_panel_h_total;
+       break;
+    case SM501_DC_PANEL_H_SYNC:
+       ret = s->dc_panel_h_sync;
+       break;
+    case SM501_DC_PANEL_V_TOT:
+       ret = s->dc_panel_v_total;
+       break;
+    case SM501_DC_PANEL_V_SYNC:
+       ret = s->dc_panel_v_sync;
+       break;
+
+    case SM501_DC_CRT_CONTROL:
+       ret = s->dc_crt_control;
+       break;
+    case SM501_DC_CRT_FB_ADDR:
+       ret = s->dc_crt_fb_addr;
+       break;
+    case SM501_DC_CRT_FB_OFFSET:
+       ret = s->dc_crt_fb_offset;
+       break;
+    case SM501_DC_CRT_H_TOT:
+       ret = s->dc_crt_h_total;
+       break;
+    case SM501_DC_CRT_H_SYNC:
+       ret = s->dc_crt_h_sync;
+       break;
+    case SM501_DC_CRT_V_TOT:
+       ret = s->dc_crt_v_total;
+       break;
+    case SM501_DC_CRT_V_SYNC:
+       ret = s->dc_crt_v_sync;
+       break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+       ret = s->dc_crt_hwc_addr;
+       break;
+    case SM501_DC_CRT_HWC_LOC:
+       ret = s->dc_crt_hwc_location;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+       ret = s->dc_crt_hwc_color_1_2;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+       ret = s->dc_crt_hwc_color_3;
+       break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
+        break;
+
+    default:
+       printf("sm501 disp ctrl : not implemented register read."
+              " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
+                 (unsigned)addr, (unsigned)value);
+
+    switch(addr) {
+    case SM501_DC_PANEL_CONTROL:
+       s->dc_panel_control = value & 0x0FFF73FF;
+       break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+       s->dc_panel_panning_control = value & 0xFF3FFF3F;
+       break;
+    case SM501_DC_PANEL_FB_ADDR:
+       s->dc_panel_fb_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_PANEL_FB_OFFSET:
+       s->dc_panel_fb_offset = value & 0x3FF03FF0;
+       break;
+    case SM501_DC_PANEL_FB_WIDTH:
+       s->dc_panel_fb_width = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+       s->dc_panel_fb_height = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_TL_LOC:
+       s->dc_panel_tl_location = value & 0x07FF07FF;
+       break;
+    case SM501_DC_PANEL_BR_LOC:
+       s->dc_panel_br_location = value & 0x07FF07FF;
+       break;
+
+    case SM501_DC_PANEL_H_TOT:
+       s->dc_panel_h_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_H_SYNC:
+       s->dc_panel_h_sync = value & 0x00FF0FFF;
+       break;
+    case SM501_DC_PANEL_V_TOT:
+       s->dc_panel_v_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_V_SYNC:
+       s->dc_panel_v_sync = value & 0x003F0FFF;
+       break;
+
+    case SM501_DC_PANEL_HWC_ADDR:
+       s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_PANEL_HWC_LOC:
+       s->dc_panel_hwc_location = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_HWC_COLOR_1_2:
+       s->dc_panel_hwc_color_1_2 = value;
+       break;
+    case SM501_DC_PANEL_HWC_COLOR_3:
+       s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
+       break;
+
+    case SM501_DC_CRT_CONTROL:
+       s->dc_crt_control = value & 0x0003FFFF;
+       break;
+    case SM501_DC_CRT_FB_ADDR:
+       s->dc_crt_fb_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_CRT_FB_OFFSET:
+       s->dc_crt_fb_offset = value & 0x3FF03FF0;
+       break;
+    case SM501_DC_CRT_H_TOT:
+       s->dc_crt_h_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_H_SYNC:
+       s->dc_crt_h_sync = value & 0x00FF0FFF;
+       break;
+    case SM501_DC_CRT_V_TOT:
+       s->dc_crt_v_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_V_SYNC:
+       s->dc_crt_v_sync = value & 0x003F0FFF;
+       break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+       s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_CRT_HWC_LOC:
+       s->dc_crt_hwc_location = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+       s->dc_crt_hwc_color_1_2 = value;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+       s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
+       break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
+        break;
+
+    default:
+       printf("sm501 disp ctrl : not implemented register write."
+              " addr=%x, val=%x\n", (int)addr, (unsigned)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_disp_ctrl_ops = {
+    .read = sm501_disp_ctrl_read,
+    .write = sm501_disp_ctrl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_2D_SOURCE_BASE:
+        ret = s->twoD_source_base;
+        break;
+    default:
+        printf("sm501 disp ctrl : not implemented register read."
+               " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_2d_engine_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
+                  (unsigned)addr, (unsigned)value);
+
+    switch(addr) {
+    case SM501_2D_SOURCE:
+        s->twoD_source = value;
+        break;
+    case SM501_2D_DESTINATION:
+        s->twoD_destination = value;
+        break;
+    case SM501_2D_DIMENSION:
+        s->twoD_dimension = value;
+        break;
+    case SM501_2D_CONTROL:
+        s->twoD_control = value;
+
+        /* do 2d operation if start flag is set. */
+        if (value & 0x80000000) {
+            sm501_2d_operation(s);
+            s->twoD_control &= ~0x80000000; /* start flag down */
+        }
+
+        break;
+    case SM501_2D_PITCH:
+        s->twoD_pitch = value;
+        break;
+    case SM501_2D_FOREGROUND:
+        s->twoD_foreground = value;
+        break;
+    case SM501_2D_STRETCH:
+        s->twoD_stretch = value;
+        break;
+    case SM501_2D_COLOR_COMPARE_MASK:
+        s->twoD_color_compare_mask = value;
+        break;
+    case SM501_2D_MASK:
+        s->twoD_mask = value;
+        break;
+    case SM501_2D_WINDOW_WIDTH:
+        s->twoD_window_width = value;
+        break;
+    case SM501_2D_SOURCE_BASE:
+        s->twoD_source_base = value;
+        break;
+    case SM501_2D_DESTINATION_BASE:
+        s->twoD_destination_base = value;
+        break;
+    default:
+        printf("sm501 2d engine : not implemented register write."
+               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_2d_engine_ops = {
+    .read = sm501_2d_engine_read,
+    .write = sm501_2d_engine_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* draw line functions for all console modes */
+
+typedef void draw_line_func(uint8_t *d, const uint8_t *s,
+                           int width, const uint32_t *pal);
+
+typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
+                                int c_y, uint8_t *d, int width);
+
+#define DEPTH 8
+#include "hw/sm501_template.h"
+
+#define DEPTH 15
+#include "hw/sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "hw/sm501_template.h"
+
+#define DEPTH 16
+#include "hw/sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "hw/sm501_template.h"
+
+#define DEPTH 32
+#include "hw/sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "hw/sm501_template.h"
+
+static draw_line_func * draw_line8_funcs[] = {
+    draw_line8_8,
+    draw_line8_15,
+    draw_line8_16,
+    draw_line8_32,
+    draw_line8_32bgr,
+    draw_line8_15bgr,
+    draw_line8_16bgr,
+};
+
+static draw_line_func * draw_line16_funcs[] = {
+    draw_line16_8,
+    draw_line16_15,
+    draw_line16_16,
+    draw_line16_32,
+    draw_line16_32bgr,
+    draw_line16_15bgr,
+    draw_line16_16bgr,
+};
+
+static draw_line_func * draw_line32_funcs[] = {
+    draw_line32_8,
+    draw_line32_15,
+    draw_line32_16,
+    draw_line32_32,
+    draw_line32_32bgr,
+    draw_line32_15bgr,
+    draw_line32_16bgr,
+};
+
+static draw_hwc_line_func * draw_hwc_line_funcs[] = {
+    draw_hwc_line_8,
+    draw_hwc_line_15,
+    draw_hwc_line_16,
+    draw_hwc_line_32,
+    draw_hwc_line_32bgr,
+    draw_hwc_line_15bgr,
+    draw_hwc_line_16bgr,
+};
+
+static inline int get_depth_index(DisplaySurface *surface)
+{
+    switch (surface_bits_per_pixel(surface)) {
+    default:
+    case 8:
+       return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(surface)) {
+            return 4;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static void sm501_draw_crt(SM501State * s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y;
+    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
+
+    uint8_t  * src = s->local_mem;
+    int src_bpp = 0;
+    int dst_bpp = surface_bytes_per_pixel(surface);
+    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
+                                                   - SM501_DC_PANEL_PALETTE];
+    uint8_t hwc_palette[3 * 3];
+    int ds_depth_index = get_depth_index(surface);
+    draw_line_func * draw_line = NULL;
+    draw_hwc_line_func * draw_hwc_line = NULL;
+    int full_update = 0;
+    int y_start = -1;
+    ram_addr_t page_min = ~0l;
+    ram_addr_t page_max = 0l;
+    ram_addr_t offset = 0;
+
+    /* choose draw_line function */
+    switch (s->dc_crt_control & 3) {
+    case SM501_DC_CRT_CONTROL_8BPP:
+       src_bpp = 1;
+       draw_line = draw_line8_funcs[ds_depth_index];
+       break;
+    case SM501_DC_CRT_CONTROL_16BPP:
+       src_bpp = 2;
+       draw_line = draw_line16_funcs[ds_depth_index];
+       break;
+    case SM501_DC_CRT_CONTROL_32BPP:
+       src_bpp = 4;
+       draw_line = draw_line32_funcs[ds_depth_index];
+       break;
+    default:
+       printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
+              s->dc_crt_control);
+        abort();
+       break;
+    }
+
+    /* set up to draw hardware cursor */
+    if (is_hwc_enabled(s, 1)) {
+        int i;
+
+        /* get cursor palette */
+        for (i = 0; i < 3; i++) {
+            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
+            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
+            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
+            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
+        }
+
+        /* choose cursor draw line function */
+        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
+    }
+
+    /* adjust console size */
+    if (s->last_width != width || s->last_height != height) {
+        qemu_console_resize(s->con, width, height);
+        surface = qemu_console_surface(s->con);
+       s->last_width = width;
+       s->last_height = height;
+       full_update = 1;
+    }
+
+    /* draw each line according to conditions */
+    for (y = 0; y < height; y++) {
+       int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
+       int update = full_update || update_hwc;
+        ram_addr_t page0 = offset;
+        ram_addr_t page1 = offset + width * src_bpp - 1;
+
+       /* check dirty flags for each line */
+        update = memory_region_get_dirty(&s->local_mem_region, page0,
+                                         page1 - page0, DIRTY_MEMORY_VGA);
+
+       /* draw line and change status */
+       if (update) {
+            uint8_t *d = surface_data(surface);
+            d +=  y * width * dst_bpp;
+
+            /* draw graphics layer */
+            draw_line(d, src, width, palette);
+
+            /* draw haredware cursor */
+            if (update_hwc) {
+                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
+            }
+
+           if (y_start < 0)
+               y_start = y;
+           if (page0 < page_min)
+               page_min = page0;
+           if (page1 > page_max)
+               page_max = page1;
+       } else {
+           if (y_start >= 0) {
+               /* flush to display */
+                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+               y_start = -1;
+           }
+       }
+
+       src += width * src_bpp;
+       offset += width * src_bpp;
+    }
+
+    /* complete flush to display */
+    if (y_start >= 0)
+        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+
+    /* clear dirty flags */
+    if (page_min != ~0l) {
+       memory_region_reset_dirty(&s->local_mem_region,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    }
+}
+
+static void sm501_update_display(void *opaque)
+{
+    SM501State * s = (SM501State *)opaque;
+
+    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
+       sm501_draw_crt(s);
+}
+
+void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
+{
+    SM501State * s;
+    DeviceState *dev;
+    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
+
+    /* allocate management data region */
+    s = (SM501State *)g_malloc0(sizeof(SM501State));
+    s->base = base;
+    s->local_mem_size_index
+       = get_local_mem_size_index(local_mem_bytes);
+    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
+                 s->local_mem_size_index);
+    s->system_control = 0x00100000;
+    s->misc_control = 0x00001000; /* assumes SH, active=low */
+    s->dc_panel_control = 0x00010000;
+    s->dc_crt_control = 0x00010000;
+
+    /* allocate local memory */
+    memory_region_init_ram(&s->local_mem_region, "sm501.local",
+                           local_mem_bytes);
+    vmstate_register_ram_global(&s->local_mem_region);
+    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
+    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
+
+    /* map mmio */
+    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
+                          "sm501-system-config", 0x6c);
+    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
+                                sm501_system_config);
+    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
+                          "sm501-disp-ctrl", 0x1000);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_DC,
+                                sm501_disp_ctrl);
+    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
+                          "sm501-2d-engine", 0x54);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                sm501_2d_engine);
+
+    /* bridge to usb host emulation module */
+    dev = qdev_create(NULL, "sysbus-ohci");
+    qdev_prop_set_uint32(dev, "num-ports", 2);
+    qdev_prop_set_taddr(dev, "dma-offset", base);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
+                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    /* bridge to serial emulation module */
+    if (chr) {
+        serial_mm_init(address_space_mem,
+                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+                       NULL, /* TODO : chain irq to IRL */
+                       115200, chr, DEVICE_NATIVE_ENDIAN);
+    }
+
+    /* create qemu graphic console */
+    s->con = graphic_console_init(sm501_update_display, NULL,
+                                  NULL, NULL, s);
+}
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
new file mode 100644 (file)
index 0000000..2d5fa89
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Toshiba TC6393XB I/O Controller.
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
+ * Toshiba e-Series PDAs.
+ *
+ * Most features are currently unsupported!!!
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * 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/hw.h"
+#include "hw/arm/devices.h"
+#include "hw/block/flash.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "sysemu/blockdev.h"
+
+#define IRQ_TC6393_NAND                0
+#define IRQ_TC6393_MMC         1
+#define IRQ_TC6393_OHCI                2
+#define IRQ_TC6393_SERIAL      3
+#define IRQ_TC6393_FB          4
+
+#define        TC6393XB_NR_IRQS        8
+
+#define TC6393XB_GPIOS  16
+
+#define SCR_REVID      0x08            /* b Revision ID        */
+#define SCR_ISR                0x50            /* b Interrupt Status   */
+#define SCR_IMR                0x52            /* b Interrupt Mask     */
+#define SCR_IRR                0x54            /* b Interrupt Routing  */
+#define SCR_GPER       0x60            /* w GP Enable          */
+#define SCR_GPI_SR(i)  (0x64 + (i))    /* b3 GPI Status        */
+#define SCR_GPI_IMR(i) (0x68 + (i))    /* b3 GPI INT Mask      */
+#define SCR_GPI_EDER(i)        (0x6c + (i))    /* b3 GPI Edge Detect Enable */
+#define SCR_GPI_LIR(i) (0x70 + (i))    /* b3 GPI Level Invert  */
+#define SCR_GPO_DSR(i) (0x78 + (i))    /* b3 GPO Data Set      */
+#define SCR_GPO_DOECR(i) (0x7c + (i))  /* b3 GPO Data OE Control */
+#define SCR_GP_IARCR(i)        (0x80 + (i))    /* b3 GP Internal Active Register Control */
+#define SCR_GP_IARLCR(i) (0x84 + (i))  /* b3 GP INTERNAL Active Register Level Control */
+#define SCR_GPI_BCR(i) (0x88 + (i))    /* b3 GPI Buffer Control */
+#define SCR_GPA_IARCR  0x8c            /* w GPa Internal Active Register Control */
+#define SCR_GPA_IARLCR 0x90            /* w GPa Internal Active Register Level Control */
+#define SCR_GPA_BCR    0x94            /* w GPa Buffer Control */
+#define SCR_CCR                0x98            /* w Clock Control      */
+#define SCR_PLL2CR     0x9a            /* w PLL2 Control       */
+#define SCR_PLL1CR     0x9c            /* l PLL1 Control       */
+#define SCR_DIARCR     0xa0            /* b Device Internal Active Register Control */
+#define SCR_DBOCR      0xa1            /* b Device Buffer Off Control */
+#define SCR_FER                0xe0            /* b Function Enable    */
+#define SCR_MCR                0xe4            /* w Mode Control       */
+#define SCR_CONFIG     0xfc            /* b Configuration Control */
+#define SCR_DEBUG      0xff            /* b Debug              */
+
+#define NAND_CFG_COMMAND    0x04    /* w Command        */
+#define NAND_CFG_BASE       0x10    /* l Control Base Address */
+#define NAND_CFG_INTP       0x3d    /* b Interrupt Pin  */
+#define NAND_CFG_INTE       0x48    /* b Int Enable     */
+#define NAND_CFG_EC         0x4a    /* b Event Control  */
+#define NAND_CFG_ICC        0x4c    /* b Internal Clock Control */
+#define NAND_CFG_ECCC       0x5b    /* b ECC Control    */
+#define NAND_CFG_NFTC       0x60    /* b NAND Flash Transaction Control */
+#define NAND_CFG_NFM        0x61    /* b NAND Flash Monitor */
+#define NAND_CFG_NFPSC      0x62    /* b NAND Flash Power Supply Control */
+#define NAND_CFG_NFDC       0x63    /* b NAND Flash Detect Control */
+
+#define NAND_DATA   0x00        /* l Data       */
+#define NAND_MODE   0x04        /* b Mode       */
+#define NAND_STATUS 0x05        /* b Status     */
+#define NAND_ISR    0x06        /* b Interrupt Status */
+#define NAND_IMR    0x07        /* b Interrupt Mask */
+
+#define NAND_MODE_WP        0x80
+#define NAND_MODE_CE        0x10
+#define NAND_MODE_ALE       0x02
+#define NAND_MODE_CLE       0x01
+#define NAND_MODE_ECC_MASK  0x60
+#define NAND_MODE_ECC_EN    0x20
+#define NAND_MODE_ECC_READ  0x40
+#define NAND_MODE_ECC_RST   0x60
+
+struct TC6393xbState {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq *sub_irqs;
+    struct {
+        uint8_t ISR;
+        uint8_t IMR;
+        uint8_t IRR;
+        uint16_t GPER;
+        uint8_t GPI_SR[3];
+        uint8_t GPI_IMR[3];
+        uint8_t GPI_EDER[3];
+        uint8_t GPI_LIR[3];
+        uint8_t GP_IARCR[3];
+        uint8_t GP_IARLCR[3];
+        uint8_t GPI_BCR[3];
+        uint16_t GPA_IARCR;
+        uint16_t GPA_IARLCR;
+        uint16_t CCR;
+        uint16_t PLL2CR;
+        uint32_t PLL1CR;
+        uint8_t DIARCR;
+        uint8_t DBOCR;
+        uint8_t FER;
+        uint16_t MCR;
+        uint8_t CONFIG;
+        uint8_t DEBUG;
+    } scr;
+    uint32_t gpio_dir;
+    uint32_t gpio_level;
+    uint32_t prev_level;
+    qemu_irq handler[TC6393XB_GPIOS];
+    qemu_irq *gpio_in;
+
+    struct {
+        uint8_t mode;
+        uint8_t isr;
+        uint8_t imr;
+    } nand;
+    int nand_enable;
+    uint32_t nand_phys;
+    DeviceState *flash;
+    ECCState ecc;
+
+    QemuConsole *con;
+    MemoryRegion vram;
+    uint16_t *vram_ptr;
+    uint32_t scr_width, scr_height; /* in pixels */
+    qemu_irq l3v;
+    unsigned blank : 1,
+             blanked : 1;
+};
+
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
+{
+    return s->gpio_in;
+}
+
+static void tc6393xb_gpio_set(void *opaque, int line, int level)
+{
+//    TC6393xbState *s = opaque;
+
+    if (line > TC6393XB_GPIOS) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    // FIXME: how does the chip reflect the GPIO input level change?
+}
+
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
+                    qemu_irq handler)
+{
+    if (line >= TC6393XB_GPIOS) {
+        fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
+        return;
+    }
+
+    s->handler[line] = handler;
+}
+
+static void tc6393xb_gpio_handler_update(TC6393xbState *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
+{
+    return s->l3v;
+}
+
+static void tc6393xb_l3v(void *opaque, int line, int level)
+{
+    TC6393xbState *s = opaque;
+    s->blank = !level;
+    fprintf(stderr, "L3V: %d\n", level);
+}
+
+static void tc6393xb_sub_irq(void *opaque, int line, int level) {
+    TC6393xbState *s = opaque;
+    uint8_t isr = s->scr.ISR;
+    if (level)
+        isr |= 1 << line;
+    else
+        isr &= ~(1 << line);
+    s->scr.ISR = isr;
+    qemu_set_irq(s->irq, isr & s->scr.IMR);
+}
+
+#define SCR_REG_B(N)                            \
+    case SCR_ ##N: return s->scr.N
+#define SCR_REG_W(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;
+#define SCR_REG_L(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;    \
+    case SCR_ ##N + 2: return s->scr.N >> 16;   \
+    case SCR_ ##N + 3: return s->scr.N >> 24;
+#define SCR_REG_A(N)                            \
+    case SCR_ ##N(0): return s->scr.N[0];       \
+    case SCR_ ##N(1): return s->scr.N[1];       \
+    case SCR_ ##N(2): return s->scr.N[2]
+
+static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
+{
+    switch (addr) {
+        case SCR_REVID:
+            return 3;
+        case SCR_REVID+1:
+            return 0;
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+#define SCR_REG_B(N)                                \
+    case SCR_ ##N: s->scr.N = value; return;
+#define SCR_REG_W(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
+#define SCR_REG_L(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return;   \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return;     \
+    case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return;   \
+    case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
+#define SCR_REG_A(N)                                \
+    case SCR_ ##N(0): s->scr.N[0] = value; return;   \
+    case SCR_ ##N(1): s->scr.N[1] = value; return;   \
+    case SCR_ ##N(2): s->scr.N[2] = value; return
+
+static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
+{
+    switch (addr) {
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+static void tc6393xb_nand_irq(TC6393xbState *s) {
+    qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
+            (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
+}
+
+static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            return s->nand_enable ? 2 : 0;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            return s->nand_phys >> (addr - NAND_CFG_BASE);
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            s->nand_enable = (value & 0x2);
+            return;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
+            s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+
+static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            return nand_getio(s->flash);
+        case NAND_MODE:
+            return s->nand.mode;
+        case NAND_STATUS:
+            return 0x14;
+        case NAND_ISR:
+            return s->nand.isr;
+        case NAND_IMR:
+            return s->nand.imr;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
+//    fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
+//                                     (uint32_t) addr, value & 0xff);
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            nand_setio(s->flash, value);
+            s->nand.isr |= 1;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_MODE:
+            s->nand.mode = value;
+            nand_setpins(s->flash,
+                    value & NAND_MODE_CLE,
+                    value & NAND_MODE_ALE,
+                    !(value & NAND_MODE_CE),
+                    value & NAND_MODE_WP,
+                    0); // FIXME: gnd
+            switch (value & NAND_MODE_ECC_MASK) {
+                case NAND_MODE_ECC_RST:
+                    ecc_reset(&s->ecc);
+                    break;
+                case NAND_MODE_ECC_READ:
+                    // FIXME
+                    break;
+                case NAND_MODE_ECC_EN:
+                    ecc_reset(&s->ecc);
+            }
+            return;
+        case NAND_ISR:
+            s->nand.isr = value;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_IMR:
+            s->nand.imr = value;
+            tc6393xb_nand_irq(s);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+
+#define BITS 8
+#include "hw/tc6393xb_template.h"
+#define BITS 15
+#include "hw/tc6393xb_template.h"
+#define BITS 16
+#include "hw/tc6393xb_template.h"
+#define BITS 24
+#include "hw/tc6393xb_template.h"
+#define BITS 32
+#include "hw/tc6393xb_template.h"
+
+static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            tc6393xb_draw_graphic8(s);
+            break;
+        case 15:
+            tc6393xb_draw_graphic15(s);
+            break;
+        case 16:
+            tc6393xb_draw_graphic16(s);
+            break;
+        case 24:
+            tc6393xb_draw_graphic24(s);
+            break;
+        case 32:
+            tc6393xb_draw_graphic32(s);
+            break;
+        default:
+            printf("tc6393xb: unknown depth %d\n",
+                   surface_bits_per_pixel(surface));
+            return;
+    }
+
+    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+
+    w = s->scr_width * surface_bytes_per_pixel(surface);
+    d = surface_data(surface);
+    for(i = 0; i < s->scr_height; i++) {
+        memset(d, 0, w);
+        d += surface_stride(surface);
+    }
+
+    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_update_display(void *opaque)
+{
+    TC6393xbState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int full_update;
+
+    if (s->scr_width == 0 || s->scr_height == 0)
+        return;
+
+    full_update = 0;
+    if (s->blanked != s->blank) {
+        s->blanked = s->blank;
+        full_update = 1;
+    }
+    if (s->scr_width != surface_width(surface) ||
+        s->scr_height != surface_height(surface)) {
+        qemu_console_resize(s->con, s->scr_width, s->scr_height);
+        full_update = 1;
+    }
+    if (s->blanked)
+        tc6393xb_draw_blank(s, full_update);
+    else
+        tc6393xb_draw_graphic(s, full_update);
+}
+
+
+static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            return tc6393xb_scr_readb(s, addr & 0xff);
+        case 1:
+            return tc6393xb_nand_cfg_readb(s, addr & 0xff);
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
+//        return tc6393xb_nand_readb(s, addr & 0xff);
+        uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
+//        fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
+        return d;
+    }
+
+//    fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+
+static void tc6393xb_writeb(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size) {
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            tc6393xb_scr_writeb(s, addr & 0xff, value);
+            return;
+        case 1:
+            tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
+            return;
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable)
+        tc6393xb_nand_writeb(s, addr & 0xff, value);
+    else
+        fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
+                (uint32_t) addr, (int)value & 0xff);
+}
+
+TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
+{
+    TC6393xbState *s;
+    DriveInfo *nand;
+    static const MemoryRegionOps tc6393xb_ops = {
+        .read = tc6393xb_readb,
+        .write = tc6393xb_writeb,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+        .impl = {
+            .min_access_size = 1,
+            .max_access_size = 1,
+        },
+    };
+
+    s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
+    s->irq = irq;
+    s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
+
+    s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
+    s->blanked = 1;
+
+    s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
+
+    nand = drive_get(IF_MTD, 0, 0);
+    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
+
+    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    memory_region_init_ram(&s->vram, "tc6393xb.vram", 0x100000);
+    vmstate_register_ram_global(&s->vram);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
+    s->scr_width = 480;
+    s->scr_height = 640;
+    s->con = graphic_console_init(tc6393xb_update_display,
+            NULL, /* invalidate */
+            NULL, /* screen_dump */
+            NULL, /* text_update */
+            s);
+
+    return s;
+}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
new file mode 100644 (file)
index 0000000..c44068e
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ * QEMU TCX Frame buffer
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * 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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-addr.h"
+
+#define MAXX 1024
+#define MAXY 768
+#define TCX_DAC_NREGS 16
+#define TCX_THC_NREGS_8  0x081c
+#define TCX_THC_NREGS_24 0x1000
+#define TCX_TEC_NREGS    0x1000
+
+typedef struct TCXState {
+    SysBusDevice busdev;
+    QemuConsole *con;
+    uint8_t *vram;
+    uint32_t *vram24, *cplane;
+    MemoryRegion vram_mem;
+    MemoryRegion vram_8bit;
+    MemoryRegion vram_24bit;
+    MemoryRegion vram_cplane;
+    MemoryRegion dac;
+    MemoryRegion tec;
+    MemoryRegion thc24;
+    MemoryRegion thc8;
+    ram_addr_t vram24_offset, cplane_offset;
+    uint32_t vram_size;
+    uint32_t palette[256];
+    uint8_t r[256], g[256], b[256];
+    uint16_t width, height, depth;
+    uint8_t dac_index, dac_state;
+} TCXState;
+
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+
+static void tcx_set_dirty(TCXState *s)
+{
+    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
+}
+
+static void tcx24_set_dirty(TCXState *s)
+{
+    memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
+    memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
+}
+
+static void update_palette_entries(TCXState *s, int start, int end)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i;
+
+    for (i = start; i < end; i++) {
+        switch (surface_bits_per_pixel(surface)) {
+        default:
+        case 8:
+            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 15:
+            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 16:
+            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 32:
+            if (is_surface_bgr(surface)) {
+                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+            } else {
+                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
+            }
+            break;
+        }
+    }
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+}
+
+static void tcx_draw_line32(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint32_t *p = (uint32_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line16(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint16_t *p = (uint16_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line8(TCXState *s1, uint8_t *d,
+                           const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *d++ = s1->palette[val];
+    }
+}
+
+/*
+  XXX Could be much more optimal:
+  * detect if line/page/whole screen is in 24 bit mode
+  * if destination is also BGR, use memcpy
+  */
+static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
+                                     const uint8_t *s, int width,
+                                     const uint32_t *cplane,
+                                     const uint32_t *s24)
+{
+    DisplaySurface *surface = qemu_console_surface(s1->con);
+    int x, bgr, r, g, b;
+    uint8_t val, *p8;
+    uint32_t *p = (uint32_t *)d;
+    uint32_t dval;
+
+    bgr = is_surface_bgr(surface);
+    for(x = 0; x < width; x++, s++, s24++) {
+        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
+            // 24-bit direct, BGR order
+            p8 = (uint8_t *)s24;
+            p8++;
+            b = *p8++;
+            g = *p8++;
+            r = *p8;
+            if (bgr)
+                dval = rgb_to_pixel32bgr(r, g, b);
+            else
+                dval = rgb_to_pixel32(r, g, b);
+        } else {
+            val = *s;
+            dval = s1->palette[val];
+        }
+        *p++ = dval;
+    }
+}
+
+static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    int ret;
+
+    ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
+                                   DIRTY_MEMORY_VGA);
+    ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
+                                   DIRTY_MEMORY_VGA);
+    return ret;
+}
+
+static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
+                               ram_addr_t page_max, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page_min, page_max + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page24 + page_min * 4,
+                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              cpage + page_min * 4,
+                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+}
+
+/* Fixed line length 1024 allows us to do nice tricks not possible on
+   VGA... */
+static void tcx_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    DisplaySurface *surface = qemu_console_surface(ts->con);
+    ram_addr_t page, page_min, page_max;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
+
+    if (surface_bits_per_pixel(surface) == 0) {
+        return;
+    }
+
+    page = 0;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    s = ts->vram;
+    dd = surface_stride(surface);
+    ds = 1024;
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 32:
+        f = tcx_draw_line32;
+        break;
+    case 15:
+    case 16:
+        f = tcx_draw_line16;
+        break;
+    default:
+    case 8:
+        f = tcx_draw_line8;
+        break;
+    case 0:
+        return;
+    }
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
+        if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
+                                    DIRTY_MEMORY_VGA)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(ts->con, 0, y_start,
+                               ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(ts->con, 0, y_start,
+                       ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        memory_region_reset_dirty(&ts->vram_mem,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    }
+}
+
+static void tcx24_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    DisplaySurface *surface = qemu_console_surface(ts->con);
+    ram_addr_t page, page_min, page_max, cpage, page24;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    uint32_t *cptr, *s24;
+
+    if (surface_bits_per_pixel(surface) != 32) {
+            return;
+    }
+
+    page = 0;
+    page24 = ts->vram24_offset;
+    cpage = ts->cplane_offset;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    s = ts->vram;
+    s24 = ts->vram24;
+    cptr = ts->cplane;
+    dd = surface_stride(surface);
+    ds = 1024;
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
+            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
+        if (check_dirty(ts, page, page24, cpage)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(ts->con, 0, y_start,
+                               ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+            cptr += ds * 4;
+            s24 += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(ts->con, 0, y_start,
+                       ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        reset_dirty(ts, page_min, page_max, page24, cpage);
+    }
+}
+
+static void tcx_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    qemu_console_resize(s->con, s->width, s->height);
+}
+
+static void tcx24_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    tcx24_set_dirty(s);
+    qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_tcx_post_load(void *opaque, int version_id)
+{
+    TCXState *s = opaque;
+
+    update_palette_entries(s, 0, 256);
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tcx = {
+    .name ="tcx",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = vmstate_tcx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(height, TCXState),
+        VMSTATE_UINT16(width, TCXState),
+        VMSTATE_UINT16(depth, TCXState),
+        VMSTATE_BUFFER(r, TCXState),
+        VMSTATE_BUFFER(g, TCXState),
+        VMSTATE_BUFFER(b, TCXState),
+        VMSTATE_UINT8(dac_index, TCXState),
+        VMSTATE_UINT8(dac_state, TCXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tcx_reset(DeviceState *d)
+{
+    TCXState *s = container_of(d, TCXState, busdev.qdev);
+
+    /* Initialize palette */
+    memset(s->r, 0, 256);
+    memset(s->g, 0, 256);
+    memset(s->b, 0, 256);
+    s->r[255] = s->g[255] = s->b[255] = 255;
+    update_palette_entries(s, 0, 256);
+    memset(s->vram, 0, MAXX*MAXY);
+    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
+                              DIRTY_MEMORY_VGA);
+    s->dac_index = 0;
+    s->dac_state = 0;
+}
+
+static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    return 0;
+}
+
+static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
+                           unsigned size)
+{
+    TCXState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        s->dac_index = val >> 24;
+        s->dac_state = 0;
+        break;
+    case 4:
+        switch (s->dac_state) {
+        case 0:
+            s->r[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 1:
+            s->g[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 2:
+            s->b[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
+        default:
+            s->dac_state = 0;
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps tcx_dac_ops = {
+    .read = tcx_dac_readl,
+    .write = tcx_dac_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t dummy_readl(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    return 0;
+}
+
+static void dummy_writel(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+}
+
+static const MemoryRegionOps dummy_ops = {
+    .read = dummy_readl,
+    .write = dummy_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int tcx_init1(SysBusDevice *dev)
+{
+    TCXState *s = FROM_SYSBUS(TCXState, dev);
+    ram_addr_t vram_offset = 0;
+    int size;
+    uint8_t *vram_base;
+
+    memory_region_init_ram(&s->vram_mem, "tcx.vram",
+                           s->vram_size * (1 + 4 + 4));
+    vmstate_register_ram_global(&s->vram_mem);
+    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
+
+    /* 8-bit plane */
+    s->vram = vram_base;
+    size = s->vram_size;
+    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
+                             &s->vram_mem, vram_offset, size);
+    sysbus_init_mmio(dev, &s->vram_8bit);
+    vram_offset += size;
+    vram_base += size;
+
+    /* DAC */
+    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
+    sysbus_init_mmio(dev, &s->dac);
+
+    /* TEC (dummy) */
+    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
+    sysbus_init_mmio(dev, &s->tec);
+    /* THC: NetBSD writes here even with 8-bit display: dummy */
+    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
+                          TCX_THC_NREGS_24);
+    sysbus_init_mmio(dev, &s->thc24);
+
+    if (s->depth == 24) {
+        /* 24-bit plane */
+        size = s->vram_size * 4;
+        s->vram24 = (uint32_t *)vram_base;
+        s->vram24_offset = vram_offset;
+        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio(dev, &s->vram_24bit);
+        vram_offset += size;
+        vram_base += size;
+
+        /* Control plane */
+        size = s->vram_size * 4;
+        s->cplane = (uint32_t *)vram_base;
+        s->cplane_offset = vram_offset;
+        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio(dev, &s->vram_cplane);
+
+        s->con = graphic_console_init(tcx24_update_display,
+                                      tcx24_invalidate_display,
+                                      tcx24_screen_dump, NULL, s);
+    } else {
+        /* THC 8 bit (dummy) */
+        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
+                              TCX_THC_NREGS_8);
+        sysbus_init_mmio(dev, &s->thc8);
+
+        s->con = graphic_console_init(tcx_update_display,
+                                      tcx_invalidate_display,
+                                      tcx_screen_dump, NULL, s);
+    }
+
+    qemu_console_resize(s->con, s->width, s->height);
+    return 0;
+}
+
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    int ret, y, x;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = s->vram;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++) {
+            v = *d;
+            ret = fputc(s->r[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            ret = fputc(s->g[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            ret = fputc(s->b[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            d++;
+        }
+        d1 += MAXX;
+    }
+
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+                              Error **errp)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    uint32_t *s24, *cptr, dval;
+    int ret, y, x;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = s->vram;
+    s24 = s->vram24;
+    cptr = s->cplane;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++, d++, s24++) {
+            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
+                dval = *s24 & 0x00ffffff;
+                ret = fputc((dval >> 16) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((dval >> 8) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(dval & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+            } else {
+                v = *d;
+                ret = fputc(s->r[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->g[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->b[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+            }
+        }
+        d1 += MAXX;
+    }
+
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static Property tcx_properties[] = {
+    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
+    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
+    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tcx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tcx_init1;
+    dc->reset = tcx_reset;
+    dc->vmsd = &vmstate_tcx;
+    dc->props = tcx_properties;
+}
+
+static const TypeInfo tcx_info = {
+    .name          = "SUNW,tcx",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TCXState),
+    .class_init    = tcx_class_init,
+};
+
+static void tcx_register_types(void)
+{
+    type_register_static(&tcx_info);
+}
+
+type_init(tcx_register_types)
diff --git a/hw/display/vga.c b/hw/display/vga.c
new file mode 100644 (file)
index 0000000..dc31fd5
--- /dev/null
@@ -0,0 +1,2457 @@
+/*
+ * QEMU VGA Emulator.
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/hw.h"
+#include "hw/vga.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "hw/vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/xen/xen.h"
+#include "trace.h"
+
+//#define DEBUG_VGA
+//#define DEBUG_VGA_MEM
+//#define DEBUG_VGA_REG
+
+//#define DEBUG_BOCHS_VBE
+
+/* 16 state changes per vertical frame @60 Hz */
+#define VGA_TEXT_CURSOR_PERIOD_MS       (1000 * 2 * 16 / 60)
+
+/*
+ * Video Graphics Array (VGA)
+ *
+ * Chipset docs for original IBM VGA:
+ * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
+ *
+ * FreeVGA site:
+ * http://www.osdever.net/FreeVGA/home.htm
+ *
+ * Standard VGA features and Bochs VBE extensions are implemented.
+ */
+
+/* force some bits to zero */
+const uint8_t sr_mask[8] = {
+    0x03,
+    0x3d,
+    0x0f,
+    0x3f,
+    0x0e,
+    0x00,
+    0x00,
+    0xff,
+};
+
+const uint8_t gr_mask[16] = {
+    0x0f, /* 0x00 */
+    0x0f, /* 0x01 */
+    0x0f, /* 0x02 */
+    0x1f, /* 0x03 */
+    0x03, /* 0x04 */
+    0x7b, /* 0x05 */
+    0x0f, /* 0x06 */
+    0x0f, /* 0x07 */
+    0xff, /* 0x08 */
+    0x00, /* 0x09 */
+    0x00, /* 0x0a */
+    0x00, /* 0x0b */
+    0x00, /* 0x0c */
+    0x00, /* 0x0d */
+    0x00, /* 0x0e */
+    0x00, /* 0x0f */
+};
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) (x)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define BIG 1
+#else
+#define BIG 0
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
+#else
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+#endif
+
+static const uint32_t mask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+static uint32_t expand4[256];
+static uint16_t expand2[256];
+static uint8_t expand4to8[16];
+
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+
+static void vga_update_memory_access(VGACommonState *s)
+{
+    MemoryRegion *region, *old_region = s->chain4_alias;
+    hwaddr base, offset, size;
+
+    s->chain4_alias = NULL;
+
+    if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
+        VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+        offset = 0;
+        switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
+        case 0:
+            base = 0xa0000;
+            size = 0x20000;
+            break;
+        case 1:
+            base = 0xa0000;
+            size = 0x10000;
+            offset = s->bank_offset;
+            break;
+        case 2:
+            base = 0xb0000;
+            size = 0x8000;
+            break;
+        case 3:
+        default:
+            base = 0xb8000;
+            size = 0x8000;
+            break;
+        }
+        base += isa_mem_base;
+        region = g_malloc(sizeof(*region));
+        memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
+        memory_region_add_subregion_overlap(s->legacy_address_space, base,
+                                            region, 2);
+        s->chain4_alias = region;
+    }
+    if (old_region) {
+        memory_region_del_subregion(s->legacy_address_space, old_region);
+        memory_region_destroy(old_region);
+        g_free(old_region);
+        s->plane_updated = 0xf;
+    }
+}
+
+static void vga_dumb_update_retrace_info(VGACommonState *s)
+{
+    (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+    int htotal_chars;
+    int hretr_start_char;
+    int hretr_skew_chars;
+    int hretr_end_char;
+
+    int vtotal_lines;
+    int vretr_start_line;
+    int vretr_end_line;
+
+    int dots;
+#if 0
+    int div2, sldiv2;
+#endif
+    int clocking_mode;
+    int clock_sel;
+    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+    int64_t chars_per_sec;
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+    htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+    hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+    hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+    hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
+
+    vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+                    (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+                      ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+    vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+        ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+          ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+    vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
+
+    clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+    clock_sel = (s->msr >> 2) & 3;
+    dots = (s->msr & 1) ? 8 : 9;
+
+    chars_per_sec = clk_hz[clock_sel] / dots;
+
+    htotal_chars <<= clocking_mode;
+
+    r->total_chars = vtotal_lines * htotal_chars;
+    if (r->freq) {
+        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+    } else {
+        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+    }
+
+    r->vstart = vretr_start_line;
+    r->vend = r->vstart + vretr_end_line + 1;
+
+    r->hstart = hretr_start_char + hretr_skew_chars;
+    r->hend = r->hstart + hretr_end_char + 1;
+    r->htotal = htotal_chars;
+
+#if 0
+    div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+    sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
+    printf (
+        "hz=%f\n"
+        "htotal = %d\n"
+        "hretr_start = %d\n"
+        "hretr_skew = %d\n"
+        "hretr_end = %d\n"
+        "vtotal = %d\n"
+        "vretr_start = %d\n"
+        "vretr_end = %d\n"
+        "div2 = %d sldiv2 = %d\n"
+        "clocking_mode = %d\n"
+        "clock_sel = %d %d\n"
+        "dots = %d\n"
+        "ticks/char = %" PRId64 "\n"
+        "\n",
+        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+        htotal_chars,
+        hretr_start_char,
+        hretr_skew_chars,
+        hretr_end_char,
+        vtotal_lines,
+        vretr_start_line,
+        vretr_end_line,
+        div2, sldiv2,
+        clocking_mode,
+        clock_sel,
+        clk_hz[clock_sel],
+        dots,
+        r->ticks_per_char
+        );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGACommonState *s)
+{
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+    if (r->total_chars) {
+        int cur_line, cur_line_char, cur_char;
+        int64_t cur_tick;
+
+        cur_tick = qemu_get_clock_ns(vm_clock);
+
+        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+        cur_line = cur_char / r->htotal;
+
+        if (cur_line >= r->vstart && cur_line <= r->vend) {
+            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+        } else {
+            cur_line_char = cur_char % r->htotal;
+            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+                val |= ST01_DISP_ENABLE;
+            }
+        }
+
+        return val;
+    } else {
+        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+    }
+}
+
+static uint8_t vga_dumb_retrace(VGACommonState *s)
+{
+    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
+int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
+{
+    if (s->msr & VGA_MIS_COLOR) {
+        /* Color */
+        return (addr >= 0x3b0 && addr <= 0x3bf);
+    } else {
+        /* Monochrome */
+        return (addr >= 0x3d0 && addr <= 0x3df);
+    }
+}
+
+uint32_t vga_ioport_read(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    int val, index;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (vga_ioport_invalid(s, addr)) {
+        val = 0xff;
+    } else {
+        switch(addr) {
+        case VGA_ATT_W:
+            if (s->ar_flip_flop == 0) {
+                val = s->ar_index;
+            } else {
+                val = 0;
+            }
+            break;
+        case VGA_ATT_R:
+            index = s->ar_index & 0x1f;
+            if (index < VGA_ATT_C) {
+                val = s->ar[index];
+            } else {
+                val = 0;
+            }
+            break;
+        case VGA_MIS_W:
+            val = s->st00;
+            break;
+        case VGA_SEQ_I:
+            val = s->sr_index;
+            break;
+        case VGA_SEQ_D:
+            val = s->sr[s->sr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+            break;
+        case VGA_PEL_IR:
+            val = s->dac_state;
+            break;
+        case VGA_PEL_IW:
+            val = s->dac_write_index;
+            break;
+        case VGA_PEL_D:
+            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
+            if (++s->dac_sub_index == 3) {
+                s->dac_sub_index = 0;
+                s->dac_read_index++;
+            }
+            break;
+        case VGA_FTC_R:
+            val = s->fcr;
+            break;
+        case VGA_MIS_R:
+            val = s->msr;
+            break;
+        case VGA_GFX_I:
+            val = s->gr_index;
+            break;
+        case VGA_GFX_D:
+            val = s->gr[s->gr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+            break;
+        case VGA_CRT_IM:
+        case VGA_CRT_IC:
+            val = s->cr_index;
+            break;
+        case VGA_CRT_DM:
+        case VGA_CRT_DC:
+            val = s->cr[s->cr_index];
+#ifdef DEBUG_VGA_REG
+            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+            break;
+        case VGA_IS1_RM:
+        case VGA_IS1_RC:
+            /* just toggle to fool polling */
+            val = s->st01 = s->retrace(s);
+            s->ar_flip_flop = 0;
+            break;
+        default:
+            val = 0x00;
+            break;
+        }
+    }
+#if defined(DEBUG_VGA)
+    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    int index;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    /* check port range access depending on color/monochrome mode */
+    if (vga_ioport_invalid(s, addr)) {
+        return;
+    }
+#ifdef DEBUG_VGA
+    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+
+    switch(addr) {
+    case VGA_ATT_W:
+        if (s->ar_flip_flop == 0) {
+            val &= 0x3f;
+            s->ar_index = val;
+        } else {
+            index = s->ar_index & 0x1f;
+            switch(index) {
+            case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
+                s->ar[index] = val & 0x3f;
+                break;
+            case VGA_ATC_MODE:
+                s->ar[index] = val & ~0x10;
+                break;
+            case VGA_ATC_OVERSCAN:
+                s->ar[index] = val;
+                break;
+            case VGA_ATC_PLANE_ENABLE:
+                s->ar[index] = val & ~0xc0;
+                break;
+            case VGA_ATC_PEL:
+                s->ar[index] = val & ~0xf0;
+                break;
+            case VGA_ATC_COLOR_PAGE:
+                s->ar[index] = val & ~0xf0;
+                break;
+            default:
+                break;
+            }
+        }
+        s->ar_flip_flop ^= 1;
+        break;
+    case VGA_MIS_W:
+        s->msr = val & ~0x10;
+        s->update_retrace_info(s);
+        break;
+    case VGA_SEQ_I:
+        s->sr_index = val & 7;
+        break;
+    case VGA_SEQ_D:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
+        if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
+            s->update_retrace_info(s);
+        }
+        vga_update_memory_access(s);
+        break;
+    case VGA_PEL_IR:
+        s->dac_read_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 3;
+        break;
+    case VGA_PEL_IW:
+        s->dac_write_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 0;
+        break;
+    case VGA_PEL_D:
+        s->dac_cache[s->dac_sub_index] = val;
+        if (++s->dac_sub_index == 3) {
+            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
+            s->dac_sub_index = 0;
+            s->dac_write_index++;
+        }
+        break;
+    case VGA_GFX_I:
+        s->gr_index = val & 0x0f;
+        break;
+    case VGA_GFX_D:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
+        vga_update_memory_access(s);
+        break;
+    case VGA_CRT_IM:
+    case VGA_CRT_IC:
+        s->cr_index = val;
+        break;
+    case VGA_CRT_DM:
+    case VGA_CRT_DC:
+#ifdef DEBUG_VGA_REG
+        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+        /* handle CR0-7 protection */
+        if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
+            s->cr_index <= VGA_CRTC_OVERFLOW) {
+            /* can always write bit 4 of CR7 */
+            if (s->cr_index == VGA_CRTC_OVERFLOW) {
+                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
+                    (val & 0x10);
+            }
+            return;
+        }
+        s->cr[s->cr_index] = val;
+
+        switch(s->cr_index) {
+        case VGA_CRTC_H_TOTAL:
+        case VGA_CRTC_H_SYNC_START:
+        case VGA_CRTC_H_SYNC_END:
+        case VGA_CRTC_V_TOTAL:
+        case VGA_CRTC_OVERFLOW:
+        case VGA_CRTC_V_SYNC_END:
+        case VGA_CRTC_MODE:
+            s->update_retrace_info(s);
+            break;
+        }
+        break;
+    case VGA_IS1_RM:
+    case VGA_IS1_RC:
+        s->fcr = val & 0x10;
+        break;
+    }
+}
+
+static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+    val = s->vbe_index;
+    return val;
+}
+
+uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+
+    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
+        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
+            switch(s->vbe_index) {
+                /* XXX: do not hardcode ? */
+            case VBE_DISPI_INDEX_XRES:
+                val = VBE_DISPI_MAX_XRES;
+                break;
+            case VBE_DISPI_INDEX_YRES:
+                val = VBE_DISPI_MAX_YRES;
+                break;
+            case VBE_DISPI_INDEX_BPP:
+                val = VBE_DISPI_MAX_BPP;
+                break;
+            default:
+                val = s->vbe_regs[s->vbe_index];
+                break;
+            }
+        } else {
+            val = s->vbe_regs[s->vbe_index];
+        }
+    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
+        val = s->vram_size / (64 * 1024);
+    } else {
+        val = 0;
+    }
+#ifdef DEBUG_BOCHS_VBE
+    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+    return val;
+}
+
+void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    s->vbe_index = val;
+}
+
+void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+
+    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
+#ifdef DEBUG_BOCHS_VBE
+        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+        switch(s->vbe_index) {
+        case VBE_DISPI_INDEX_ID:
+            if (val == VBE_DISPI_ID0 ||
+                val == VBE_DISPI_ID1 ||
+                val == VBE_DISPI_ID2 ||
+                val == VBE_DISPI_ID3 ||
+                val == VBE_DISPI_ID4) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_XRES:
+            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_YRES:
+            if (val <= VBE_DISPI_MAX_YRES) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BPP:
+            if (val == 0)
+                val = 8;
+            if (val == 4 || val == 8 || val == 15 ||
+                val == 16 || val == 24 || val == 32) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BANK:
+            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+              val &= (s->vbe_bank_mask >> 2);
+            } else {
+              val &= s->vbe_bank_mask;
+            }
+            s->vbe_regs[s->vbe_index] = val;
+            s->bank_offset = (val << 16);
+            vga_update_memory_access(s);
+            break;
+        case VBE_DISPI_INDEX_ENABLE:
+            if ((val & VBE_DISPI_ENABLED) &&
+                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+                int h, shift_control;
+
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
+                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
+                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
+                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
+                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
+
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
+                else
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
+                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr = 0;
+
+                /* clear the screen (should be done in BIOS) */
+                if (!(val & VBE_DISPI_NOCLEARMEM)) {
+                    memset(s->vram_ptr, 0,
+                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
+                }
+
+                /* we initialize the VGA graphic mode (should be done
+                   in BIOS) */
+                /* graphic mode + memory map 1 */
+                s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+                    VGA_GR06_GRAPHICS_MODE;
+                s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+                s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
+                /* width */
+                s->cr[VGA_CRTC_H_DISP] =
+                    (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+                /* height (only meaningful if < 1024) */
+                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
+                s->cr[VGA_CRTC_V_DISP_END] = h;
+                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
+                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
+                /* line compare to 1023 */
+                s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+                s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+                s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
+
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+                    shift_control = 0;
+                    s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+                } else {
+                    shift_control = 2;
+                    /* set chain 4 mode */
+                    s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+                    /* activate all planes */
+                    s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+                }
+                s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+                    (shift_control << 5);
+                s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
+            } else {
+                /* XXX: the bios should do that */
+                s->bank_offset = 0;
+            }
+            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
+            s->vbe_regs[s->vbe_index] = val;
+            vga_update_memory_access(s);
+            break;
+        case VBE_DISPI_INDEX_VIRT_WIDTH:
+            {
+                int w, h, line_offset;
+
+                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
+                    return;
+                w = val;
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    line_offset = w >> 1;
+                else
+                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                h = s->vram_size / line_offset;
+                /* XXX: support weird bochs semantics ? */
+                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
+                    return;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
+                s->vbe_line_offset = line_offset;
+            }
+            break;
+        case VBE_DISPI_INDEX_X_OFFSET:
+        case VBE_DISPI_INDEX_Y_OFFSET:
+            {
+                int x;
+                s->vbe_regs[s->vbe_index] = val;
+                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
+                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_start_addr += x >> 1;
+                else
+                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr >>= 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
+{
+    int memory_map_mode, plane;
+    uint32_t ret;
+
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return 0xff;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    }
+
+    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+        /* chain 4 mode : simplest access */
+        ret = s->vram_ptr[addr];
+    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
+        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
+    } else {
+        /* standard VGA latched access */
+        s->latch = ((uint32_t *)s->vram_ptr)[addr];
+
+        if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
+            /* read mode 0 */
+            plane = s->gr[VGA_GFX_PLANE_READ];
+            ret = GET_PLANE(s->latch, plane);
+        } else {
+            /* read mode 1 */
+            ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
+                mask16[s->gr[VGA_GFX_COMPARE_MASK]];
+            ret |= ret >> 16;
+            ret |= ret >> 8;
+            ret = (~ret) & 0xff;
+        }
+    }
+    return ret;
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
+{
+    int memory_map_mode, plane, write_mode, b, func_select, mask;
+    uint32_t write_mask, bit_mask, set_mask;
+
+#ifdef DEBUG_VGA_MEM
+    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
+#endif
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    }
+
+    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+        /* chain 4 mode : simplest access */
+        plane = addr & 3;
+        mask = (1 << plane);
+        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            memory_region_set_dirty(&s->vram, addr, 1);
+        }
+    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
+        mask = (1 << plane);
+        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+            addr = ((addr & ~1) << 1) | plane;
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            memory_region_set_dirty(&s->vram, addr, 1);
+        }
+    } else {
+        /* standard VGA latched access */
+        write_mode = s->gr[VGA_GFX_MODE] & 3;
+        switch(write_mode) {
+        default:
+        case 0:
+            /* rotate */
+            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
+            val = ((val >> b) | (val << (8 - b))) & 0xff;
+            val |= val << 8;
+            val |= val << 16;
+
+            /* apply set/reset mask */
+            set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
+            val = (val & ~set_mask) |
+                (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
+            bit_mask = s->gr[VGA_GFX_BIT_MASK];
+            break;
+        case 1:
+            val = s->latch;
+            goto do_write;
+        case 2:
+            val = mask16[val & 0x0f];
+            bit_mask = s->gr[VGA_GFX_BIT_MASK];
+            break;
+        case 3:
+            /* rotate */
+            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
+            val = (val >> b) | (val << (8 - b));
+
+            bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
+            val = mask16[s->gr[VGA_GFX_SR_VALUE]];
+            break;
+        }
+
+        /* apply logical operation */
+        func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
+        switch(func_select) {
+        case 0:
+        default:
+            /* nothing to do */
+            break;
+        case 1:
+            /* and */
+            val &= s->latch;
+            break;
+        case 2:
+            /* or */
+            val |= s->latch;
+            break;
+        case 3:
+            /* xor */
+            val ^= s->latch;
+            break;
+        }
+
+        /* apply bit mask */
+        bit_mask |= bit_mask << 8;
+        bit_mask |= bit_mask << 16;
+        val = (val & bit_mask) | (s->latch & ~bit_mask);
+
+    do_write:
+        /* mask data according to sr[2] */
+        mask = s->sr[VGA_SEQ_PLANE_WRITE];
+        s->plane_updated |= mask; /* only used to detect font change */
+        write_mask = mask16[mask];
+        ((uint32_t *)s->vram_ptr)[addr] =
+            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
+            (val & write_mask);
+#ifdef DEBUG_VGA_MEM
+        printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
+               addr * 4, write_mask, val);
+#endif
+        memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
+    }
+}
+
+typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
+                                  const uint8_t *font_ptr, int h,
+                                  uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+                                const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "hw/vga_template.h"
+
+#define DEPTH 15
+#include "hw/vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "hw/vga_template.h"
+
+#define DEPTH 16
+#include "hw/vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "hw/vga_template.h"
+
+#define DEPTH 32
+#include "hw/vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "hw/vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel8(r, g, b);
+    col |= col << 8;
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32(r, g, b);
+    return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32bgr(r, g, b);
+    return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    for(i = 0; i < 16; i++) {
+        v = s->ar[i];
+        if (s->ar[VGA_ATC_MODE] & 0x80) {
+            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
+        } else {
+            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
+        }
+        v = v * 3;
+        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                              c6_to_8(s->palette[v + 1]),
+                              c6_to_8(s->palette[v + 2]));
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+    }
+    return full_update;
+}
+
+/* return true if the palette was modified */
+static int update_palette256(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    v = 0;
+    for(i = 0; i < 256; i++) {
+        if (s->dac_8bit) {
+          col = s->rgb_to_pixel(s->palette[v],
+                                s->palette[v + 1],
+                                s->palette[v + 2]);
+        } else {
+          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                                c6_to_8(s->palette[v + 1]),
+                                c6_to_8(s->palette[v + 2]));
+        }
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+        v += 3;
+    }
+    return full_update;
+}
+
+static void vga_get_offsets(VGACommonState *s,
+                            uint32_t *pline_offset,
+                            uint32_t *pstart_addr,
+                            uint32_t *pline_compare)
+{
+    uint32_t start_addr, line_offset, line_compare;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        line_offset = s->vbe_line_offset;
+        start_addr = s->vbe_start_addr;
+        line_compare = 65535;
+    } else {
+        /* compute line_offset in bytes */
+        line_offset = s->cr[VGA_CRTC_OFFSET];
+        line_offset <<= 3;
+
+        /* starting address */
+        start_addr = s->cr[VGA_CRTC_START_LO] |
+            (s->cr[VGA_CRTC_START_HI] << 8);
+
+        /* line compare */
+        line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
+            ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
+    }
+    *pline_offset = line_offset;
+    *pstart_addr = start_addr;
+    *pline_compare = line_compare;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGACommonState *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
+
+    full_update = 0;
+
+    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+    if (line_offset != s->line_offset ||
+        start_addr != s->start_addr ||
+        line_compare != s->line_compare) {
+        s->line_offset = line_offset;
+        s->start_addr = start_addr;
+        s->line_compare = line_compare;
+        full_update = 1;
+    }
+    return full_update;
+}
+
+#define NB_DEPTHS 7
+
+static inline int get_depth_index(DisplaySurface *s)
+{
+    switch (surface_bits_per_pixel(s)) {
+    default:
+    case 8:
+        return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(s)) {
+            return 4;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
+    vga_draw_glyph8_8,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+};
+
+static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
+    vga_draw_glyph16_8,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+};
+
+static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
+    vga_draw_glyph9_8,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+                                    int *pcwidth, int *pcheight)
+{
+    int width, cwidth, height, cheight;
+
+    /* total width & height */
+    cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+    cwidth = 8;
+    if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+        cwidth = 9;
+    }
+    if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+        cwidth = 16; /* NOTE: no 18 pixel wide */
+    }
+    width = (s->cr[VGA_CRTC_H_DISP] + 1);
+    if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+        /* ugly hack for CGA 160x100x16 - explain me the logic */
+        height = 100;
+    } else {
+        height = s->cr[VGA_CRTC_V_DISP_END] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+        height = (height + 1) / cheight;
+    }
+
+    *pwidth = width;
+    *pheight = height;
+    *pcwidth = cwidth;
+    *pcheight = cheight;
+}
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
+    rgb_to_pixel8_dup,
+    rgb_to_pixel15_dup,
+    rgb_to_pixel16_dup,
+    rgb_to_pixel32_dup,
+    rgb_to_pixel32bgr_dup,
+    rgb_to_pixel15bgr_dup,
+    rgb_to_pixel16bgr_dup,
+};
+
+/*
+ * Text mode update
+ * Missing:
+ * - double scan
+ * - double width
+ * - underline
+ * - flashing
+ */
+static void vga_draw_text(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+    int cx_min, cx_max, linesize, x_incr, line, line1;
+    uint32_t offset, fgcol, bgcol, v, cursor_offset;
+    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
+    const uint8_t *font_ptr, *font_base[2];
+    int dup9, line_offset, depth_index;
+    uint32_t *palette;
+    uint32_t *ch_attr_ptr;
+    vga_draw_glyph8_func *vga_draw_glyph8;
+    vga_draw_glyph9_func *vga_draw_glyph9;
+    int64_t now = qemu_get_clock_ms(vm_clock);
+
+    /* compute font data address (in plane 2) */
+    v = s->sr[VGA_SEQ_CHARACTER_MAP];
+    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
+    if (offset != s->font_offsets[0]) {
+        s->font_offsets[0] = offset;
+        full_update = 1;
+    }
+    font_base[0] = s->vram_ptr + offset;
+
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    font_base[1] = s->vram_ptr + offset;
+    if (offset != s->font_offsets[1]) {
+        s->font_offsets[1] = offset;
+        full_update = 1;
+    }
+    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
+        /* if the plane 2 was modified since the last display, it
+           indicates the font may have been modified */
+        s->plane_updated = 0;
+        full_update = 1;
+    }
+    full_update |= update_basic_params(s);
+
+    line_offset = s->line_offset;
+
+    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+    if ((height * width) <= 1) {
+        /* better than nothing: exit if transient size is too small */
+        return;
+    }
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
+    if (width != s->last_width || height != s->last_height ||
+        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+        s->last_scr_width = width * cw;
+        s->last_scr_height = height * cheight;
+        qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+        surface = qemu_console_surface(s->con);
+        dpy_text_resize(s->con, width, height);
+        s->last_depth = 0;
+        s->last_width = width;
+        s->last_height = height;
+        s->last_ch = cheight;
+        s->last_cw = cw;
+        full_update = 1;
+    }
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+    full_update |= update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * surface_bytes_per_pixel(surface);
+
+    if (full_update) {
+        s->full_update_text = 1;
+    }
+    if (s->full_update_gfx) {
+        s->full_update_gfx = 0;
+        full_update |= 1;
+    }
+
+    cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+                     s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+    if (cursor_offset != s->cursor_offset ||
+        s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+        s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
+      /* if the cursor position changed, we update the old and new
+         chars */
+        if (s->cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[s->cursor_offset] = -1;
+        if (cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[cursor_offset] = -1;
+        s->cursor_offset = cursor_offset;
+        s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+        s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
+    }
+    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
+    if (now >= s->cursor_blink_time) {
+        s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
+        s->cursor_visible_phase = !s->cursor_visible_phase;
+    }
+
+    depth_index = get_depth_index(surface);
+    if (cw == 16)
+        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
+    else
+        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
+    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
+
+    dest = surface_data(surface);
+    linesize = surface_stride(surface);
+    ch_attr_ptr = s->last_ch_attr;
+    line = 0;
+    offset = s->start_addr * 4;
+    for(cy = 0; cy < height; cy++) {
+        d1 = dest;
+        src = s->vram_ptr + offset;
+        cx_min = width;
+        cx_max = -1;
+        for(cx = 0; cx < width; cx++) {
+            ch_attr = *(uint16_t *)src;
+            if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
+                if (cx < cx_min)
+                    cx_min = cx;
+                if (cx > cx_max)
+                    cx_max = cx;
+                *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+                ch = ch_attr >> 8;
+                cattr = ch_attr & 0xff;
+#else
+                ch = ch_attr & 0xff;
+                cattr = ch_attr >> 8;
+#endif
+                font_ptr = font_base[(cattr >> 3) & 1];
+                font_ptr += 32 * 4 * ch;
+                bgcol = palette[cattr >> 4];
+                fgcol = palette[cattr & 0x0f];
+                if (cw != 9) {
+                    vga_draw_glyph8(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol);
+                } else {
+                    dup9 = 0;
+                    if (ch >= 0xb0 && ch <= 0xdf &&
+                        (s->ar[VGA_ATC_MODE] & 0x04)) {
+                        dup9 = 1;
+                    }
+                    vga_draw_glyph9(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol, dup9);
+                }
+                if (src == cursor_ptr &&
+                    !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
+                    s->cursor_visible_phase) {
+                    int line_start, line_last, h;
+                    /* draw the cursor */
+                    line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
+                    line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
+                    /* XXX: check that */
+                    if (line_last > cheight - 1)
+                        line_last = cheight - 1;
+                    if (line_last >= line_start && line_start < cheight) {
+                        h = line_last - line_start + 1;
+                        d = d1 + linesize * line_start;
+                        if (cw != 9) {
+                            vga_draw_glyph8(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol);
+                        } else {
+                            vga_draw_glyph9(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol, 1);
+                        }
+                    }
+                }
+            }
+            d1 += x_incr;
+            src += 4;
+            ch_attr_ptr++;
+        }
+        if (cx_max != -1) {
+            dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
+                           (cx_max - cx_min + 1) * cw, cheight);
+        }
+        dest += linesize * cheight;
+        line1 = line + cheight;
+        offset += line_offset;
+        if (line < s->line_compare && line1 >= s->line_compare) {
+            offset = 0;
+        }
+        line = line1;
+    }
+}
+
+enum {
+    VGA_DRAW_LINE2,
+    VGA_DRAW_LINE2D2,
+    VGA_DRAW_LINE4,
+    VGA_DRAW_LINE4D2,
+    VGA_DRAW_LINE8D2,
+    VGA_DRAW_LINE8,
+    VGA_DRAW_LINE15,
+    VGA_DRAW_LINE16,
+    VGA_DRAW_LINE24,
+    VGA_DRAW_LINE32,
+    VGA_DRAW_LINE_NB,
+};
+
+static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
+    vga_draw_line2_8,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+    vga_draw_line2_32,
+    vga_draw_line2_32,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+
+    vga_draw_line2d2_8,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+
+    vga_draw_line4_8,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+    vga_draw_line4_32,
+    vga_draw_line4_32,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+
+    vga_draw_line4d2_8,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+
+    vga_draw_line8d2_8,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+
+    vga_draw_line8_8,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+    vga_draw_line8_32,
+    vga_draw_line8_32,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+
+    vga_draw_line15_8,
+    vga_draw_line15_15,
+    vga_draw_line15_16,
+    vga_draw_line15_32,
+    vga_draw_line15_32bgr,
+    vga_draw_line15_15bgr,
+    vga_draw_line15_16bgr,
+
+    vga_draw_line16_8,
+    vga_draw_line16_15,
+    vga_draw_line16_16,
+    vga_draw_line16_32,
+    vga_draw_line16_32bgr,
+    vga_draw_line16_15bgr,
+    vga_draw_line16_16bgr,
+
+    vga_draw_line24_8,
+    vga_draw_line24_15,
+    vga_draw_line24_16,
+    vga_draw_line24_32,
+    vga_draw_line24_32bgr,
+    vga_draw_line24_15bgr,
+    vga_draw_line24_16bgr,
+
+    vga_draw_line32_8,
+    vga_draw_line32_15,
+    vga_draw_line32_16,
+    vga_draw_line32_32,
+    vga_draw_line32_32bgr,
+    vga_draw_line32_15bgr,
+    vga_draw_line32_16bgr,
+};
+
+static int vga_get_bpp(VGACommonState *s)
+{
+    int ret;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+    } else {
+        ret = 0;
+    }
+    return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+    } else {
+        width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
+        height = s->cr[VGA_CRTC_V_DISP_END] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+        height = (height + 1);
+    }
+    *pwidth = width;
+    *pheight = height;
+}
+
+void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
+{
+    int y;
+    if (y1 >= VGA_MAX_HEIGHT)
+        return;
+    if (y2 >= VGA_MAX_HEIGHT)
+        y2 = VGA_MAX_HEIGHT;
+    for(y = y1; y < y2; y++) {
+        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
+    }
+}
+
+void vga_sync_dirty_bitmap(VGACommonState *s)
+{
+    memory_region_sync_dirty_bitmap(&s->vram);
+}
+
+void vga_dirty_log_start(VGACommonState *s)
+{
+    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
+}
+
+void vga_dirty_log_stop(VGACommonState *s)
+{
+    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y1, y, update, linesize, y_start, double_scan, mask, depth;
+    int width, height, shift_control, line_offset, bwidth, bits;
+    ram_addr_t page0, page1, page_min, page_max;
+    int disp_width, multi_scan, multi_run;
+    uint8_t *d;
+    uint32_t v, addr1, addr;
+    vga_draw_line_func *vga_draw_line;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    static const bool byteswap = false;
+#else
+    static const bool byteswap = true;
+#endif
+
+    full_update |= update_basic_params(s);
+
+    if (!full_update)
+        vga_sync_dirty_bitmap(s);
+
+    s->get_resolution(s, &width, &height);
+    disp_width = width;
+
+    shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+    double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
+    if (shift_control != 1) {
+        multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+            - 1;
+    } else {
+        /* in CGA modes, multi_scan is ignored */
+        /* XXX: is it correct ? */
+        multi_scan = double_scan;
+    }
+    multi_run = multi_scan;
+    if (shift_control != s->shift_control ||
+        double_scan != s->double_scan) {
+        full_update = 1;
+        s->shift_control = shift_control;
+        s->double_scan = double_scan;
+    }
+
+    if (shift_control == 0) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            disp_width <<= 1;
+        }
+    } else if (shift_control == 1) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            disp_width <<= 1;
+        }
+    }
+
+    depth = s->get_bpp(s);
+    if (s->line_offset != s->last_line_offset ||
+        disp_width != s->last_width ||
+        height != s->last_height ||
+        s->last_depth != depth) {
+        if (depth == 32 || (depth == 16 && !byteswap)) {
+            surface = qemu_create_displaysurface_from(disp_width,
+                    height, depth, s->line_offset,
+                    s->vram_ptr + (s->start_addr * 4), byteswap);
+            dpy_gfx_replace_surface(s->con, surface);
+        } else {
+            qemu_console_resize(s->con, disp_width, height);
+            surface = qemu_console_surface(s->con);
+        }
+        s->last_scr_width = disp_width;
+        s->last_scr_height = height;
+        s->last_width = disp_width;
+        s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
+        full_update = 1;
+    } else if (is_buffer_shared(surface) &&
+               (full_update || surface_data(surface) != s->vram_ptr
+                + (s->start_addr * 4))) {
+        DisplaySurface *surface;
+        surface = qemu_create_displaysurface_from(disp_width,
+                height, depth, s->line_offset,
+                s->vram_ptr + (s->start_addr * 4), byteswap);
+        dpy_gfx_replace_surface(s->con, surface);
+    }
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+
+    if (shift_control == 0) {
+        full_update |= update_palette16(s);
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            v = VGA_DRAW_LINE4D2;
+        } else {
+            v = VGA_DRAW_LINE4;
+        }
+        bits = 4;
+    } else if (shift_control == 1) {
+        full_update |= update_palette16(s);
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            v = VGA_DRAW_LINE2D2;
+        } else {
+            v = VGA_DRAW_LINE2;
+        }
+        bits = 4;
+    } else {
+        switch(s->get_bpp(s)) {
+        default:
+        case 0:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8D2;
+            bits = 4;
+            break;
+        case 8:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8;
+            bits = 8;
+            break;
+        case 15:
+            v = VGA_DRAW_LINE15;
+            bits = 16;
+            break;
+        case 16:
+            v = VGA_DRAW_LINE16;
+            bits = 16;
+            break;
+        case 24:
+            v = VGA_DRAW_LINE24;
+            bits = 24;
+            break;
+        case 32:
+            v = VGA_DRAW_LINE32;
+            bits = 32;
+            break;
+        }
+    }
+    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS +
+                                        get_depth_index(surface)];
+
+    if (!is_buffer_shared(surface) && s->cursor_invalidate) {
+        s->cursor_invalidate(s);
+    }
+
+    line_offset = s->line_offset;
+#if 0
+    printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
+           width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
+           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
+#endif
+    addr1 = (s->start_addr * 4);
+    bwidth = (width * bits + 7) / 8;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    linesize = surface_stride(surface);
+    y1 = 0;
+    for(y = 0; y < height; y++) {
+        addr = addr1;
+        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
+            int shift;
+            /* CGA compatibility handling */
+            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
+            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+        }
+        if (!(s->cr[VGA_CRTC_MODE] & 2)) {
+            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
+        }
+        update = full_update;
+        page0 = addr;
+        page1 = addr + bwidth - 1;
+        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
+                                          DIRTY_MEMORY_VGA);
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+        if (update) {
+            if (y_start < 0)
+                y_start = y;
+            if (page0 < page_min)
+                page_min = page0;
+            if (page1 > page_max)
+                page_max = page1;
+            if (!(is_buffer_shared(surface))) {
+                vga_draw_line(s, d, s->vram_ptr + addr, width);
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
+            }
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(s->con, 0, y_start,
+                               disp_width, y - y_start);
+                y_start = -1;
+            }
+        }
+        if (!multi_run) {
+            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
+            if ((y1 & mask) == mask)
+                addr1 += line_offset;
+            y1++;
+            multi_run = multi_scan;
+        } else {
+            multi_run--;
+        }
+        /* line compare acts on the displayed lines */
+        if (y == s->line_compare)
+            addr1 = 0;
+        d += linesize;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(s->con, 0, y_start,
+                       disp_width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        memory_region_reset_dirty(&s->vram,
+                                  page_min,
+                                  page_max - page_min,
+                                  DIRTY_MEMORY_VGA);
+    }
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w, val;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+    if (surface_bits_per_pixel(surface) == 8) {
+        val = s->rgb_to_pixel(0, 0, 0);
+    } else {
+        val = 0;
+    }
+    w = s->last_scr_width * surface_bytes_per_pixel(surface);
+    d = surface_data(surface);
+    for(i = 0; i < s->last_scr_height; i++) {
+        memset(d, val, w);
+        d += surface_stride(surface);
+    }
+    dpy_gfx_update(s->con, 0, 0,
+                   s->last_scr_width, s->last_scr_height);
+}
+
+#define GMODE_TEXT     0
+#define GMODE_GRAPH    1
+#define GMODE_BLANK 2
+
+static void vga_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int full_update, graphic_mode;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (surface_bits_per_pixel(surface) == 0) {
+        /* nothing to do */
+    } else {
+        full_update = 0;
+        if (!(s->ar_index & 0x20)) {
+            graphic_mode = GMODE_BLANK;
+        } else {
+            graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+        }
+        if (graphic_mode != s->graphic_mode) {
+            s->graphic_mode = graphic_mode;
+            s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
+            full_update = 1;
+        }
+        switch(graphic_mode) {
+        case GMODE_TEXT:
+            vga_draw_text(s, full_update);
+            break;
+        case GMODE_GRAPH:
+            vga_draw_graphic(s, full_update);
+            break;
+        case GMODE_BLANK:
+        default:
+            vga_draw_blank(s, full_update);
+            break;
+        }
+    }
+}
+
+/* force a full display refresh */
+static void vga_invalidate_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+
+    s->last_width = -1;
+    s->last_height = -1;
+}
+
+void vga_common_reset(VGACommonState *s)
+{
+    s->sr_index = 0;
+    memset(s->sr, '\0', sizeof(s->sr));
+    s->gr_index = 0;
+    memset(s->gr, '\0', sizeof(s->gr));
+    s->ar_index = 0;
+    memset(s->ar, '\0', sizeof(s->ar));
+    s->ar_flip_flop = 0;
+    s->cr_index = 0;
+    memset(s->cr, '\0', sizeof(s->cr));
+    s->msr = 0;
+    s->fcr = 0;
+    s->st00 = 0;
+    s->st01 = 0;
+    s->dac_state = 0;
+    s->dac_sub_index = 0;
+    s->dac_read_index = 0;
+    s->dac_write_index = 0;
+    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
+    s->dac_8bit = 0;
+    memset(s->palette, '\0', sizeof(s->palette));
+    s->bank_offset = 0;
+    s->vbe_index = 0;
+    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
+    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
+    s->vbe_start_addr = 0;
+    s->vbe_line_offset = 0;
+    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
+    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
+    s->graphic_mode = -1; /* force full update */
+    s->shift_control = 0;
+    s->double_scan = 0;
+    s->line_offset = 0;
+    s->line_compare = 0;
+    s->start_addr = 0;
+    s->plane_updated = 0;
+    s->last_cw = 0;
+    s->last_ch = 0;
+    s->last_width = 0;
+    s->last_height = 0;
+    s->last_scr_width = 0;
+    s->last_scr_height = 0;
+    s->cursor_start = 0;
+    s->cursor_end = 0;
+    s->cursor_offset = 0;
+    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
+    memset(s->last_palette, '\0', sizeof(s->last_palette));
+    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        break;
+    case VGA_RETRACE_PRECISE:
+        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
+        break;
+    }
+    vga_update_memory_access(s);
+}
+
+static void vga_reset(void *opaque)
+{
+    VGACommonState *s =  opaque;
+    vga_common_reset(s);
+}
+
+#define TEXTMODE_X(x)  ((x) % width)
+#define TEXTMODE_Y(x)  ((x) / width)
+#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
+        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+    VGACommonState *s =  opaque;
+    int graphic_mode, i, cursor_offset, cursor_visible;
+    int cw, cheight, width, height, size, c_min, c_max;
+    uint32_t *src;
+    console_ch_t *dst, val;
+    char msg_buffer[80];
+    int full_update = 0;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (!(s->ar_index & 0x20)) {
+        graphic_mode = GMODE_BLANK;
+    } else {
+        graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+    }
+    if (graphic_mode != s->graphic_mode) {
+        s->graphic_mode = graphic_mode;
+        full_update = 1;
+    }
+    if (s->last_width == -1) {
+        s->last_width = 0;
+        full_update = 1;
+    }
+
+    switch (graphic_mode) {
+    case GMODE_TEXT:
+        /* TODO: update palette */
+        full_update |= update_basic_params(s);
+
+        /* total width & height */
+        cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+        cw = 8;
+        if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+            cw = 9;
+        }
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+            cw = 16; /* NOTE: no 18 pixel wide */
+        }
+        width = (s->cr[VGA_CRTC_H_DISP] + 1);
+        if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
+            /* ugly hack for CGA 160x100x16 - explain me the logic */
+            height = 100;
+        } else {
+            height = s->cr[VGA_CRTC_V_DISP_END] |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+            height = (height + 1) / cheight;
+        }
+
+        size = (height * width);
+        if (size > CH_ATTR_SIZE) {
+            if (!full_update)
+                return;
+
+            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
+                     width, height);
+            break;
+        }
+
+        if (width != s->last_width || height != s->last_height ||
+            cw != s->last_cw || cheight != s->last_ch) {
+            s->last_scr_width = width * cw;
+            s->last_scr_height = height * cheight;
+            qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+            dpy_text_resize(s->con, width, height);
+            s->last_depth = 0;
+            s->last_width = width;
+            s->last_height = height;
+            s->last_ch = cheight;
+            s->last_cw = cw;
+            full_update = 1;
+        }
+
+        if (full_update) {
+            s->full_update_gfx = 1;
+        }
+        if (s->full_update_text) {
+            s->full_update_text = 0;
+            full_update |= 1;
+        }
+
+        /* Update "hardware" cursor */
+        cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+                         s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
+        if (cursor_offset != s->cursor_offset ||
+            s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+            s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
+            cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
+            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
+                dpy_text_cursor(s->con,
+                                TEXTMODE_X(cursor_offset),
+                                TEXTMODE_Y(cursor_offset));
+            else
+                dpy_text_cursor(s->con, -1, -1);
+            s->cursor_offset = cursor_offset;
+            s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+            s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
+        }
+
+        src = (uint32_t *) s->vram_ptr + s->start_addr;
+        dst = chardata;
+
+        if (full_update) {
+            for (i = 0; i < size; src ++, dst ++, i ++)
+                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+
+            dpy_text_update(s->con, 0, 0, width, height);
+        } else {
+            c_max = 0;
+
+            for (i = 0; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                    break;
+                }
+            }
+            c_min = i;
+            for (; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                }
+            }
+
+            if (c_min <= c_max) {
+                i = TEXTMODE_Y(c_min);
+                dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+            }
+        }
+
+        return;
+    case GMODE_GRAPH:
+        if (!full_update)
+            return;
+
+        s->get_resolution(s, &width, &height);
+        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
+                 width, height);
+        break;
+    case GMODE_BLANK:
+    default:
+        if (!full_update)
+            return;
+
+        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
+        break;
+    }
+
+    /* Display a message */
+    s->last_width = 60;
+    s->last_height = height = 3;
+    dpy_text_cursor(s->con, -1, -1);
+    dpy_text_resize(s->con, s->last_width, height);
+
+    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
+        console_write_ch(dst ++, ' ');
+
+    size = strlen(msg_buffer);
+    width = (s->last_width - size) / 2;
+    dst = chardata + s->last_width + width;
+    for (i = 0; i < size; i ++)
+        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+
+    dpy_text_update(s->con, 0, 0, s->last_width, height);
+}
+
+static uint64_t vga_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_readb(s, addr);
+}
+
+static void vga_mem_write(void *opaque, hwaddr addr,
+                          uint64_t data, unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_writeb(s, addr, data);
+}
+
+const MemoryRegionOps vga_mem_ops = {
+    .read = vga_mem_read,
+    .write = vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int vga_common_post_load(void *opaque, int version_id)
+{
+    VGACommonState *s = opaque;
+
+    /* force refresh */
+    s->graphic_mode = -1;
+    return 0;
+}
+
+const VMStateDescription vmstate_vga_common = {
+    .name = "vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = vga_common_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(latch, VGACommonState),
+        VMSTATE_UINT8(sr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
+        VMSTATE_UINT8(gr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
+        VMSTATE_UINT8(ar_index, VGACommonState),
+        VMSTATE_BUFFER(ar, VGACommonState),
+        VMSTATE_INT32(ar_flip_flop, VGACommonState),
+        VMSTATE_UINT8(cr_index, VGACommonState),
+        VMSTATE_BUFFER(cr, VGACommonState),
+        VMSTATE_UINT8(msr, VGACommonState),
+        VMSTATE_UINT8(fcr, VGACommonState),
+        VMSTATE_UINT8(st00, VGACommonState),
+        VMSTATE_UINT8(st01, VGACommonState),
+
+        VMSTATE_UINT8(dac_state, VGACommonState),
+        VMSTATE_UINT8(dac_sub_index, VGACommonState),
+        VMSTATE_UINT8(dac_read_index, VGACommonState),
+        VMSTATE_UINT8(dac_write_index, VGACommonState),
+        VMSTATE_BUFFER(dac_cache, VGACommonState),
+        VMSTATE_BUFFER(palette, VGACommonState),
+
+        VMSTATE_INT32(bank_offset, VGACommonState),
+        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
+        VMSTATE_UINT16(vbe_index, VGACommonState),
+        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
+        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
+        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
+        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void vga_common_init(VGACommonState *s)
+{
+    int i, j, v, b;
+
+    for(i = 0;i < 256; i++) {
+        v = 0;
+        for(j = 0; j < 8; j++) {
+            v |= ((i >> j) & 1) << (j * 4);
+        }
+        expand4[i] = v;
+
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            v |= ((i >> (2 * j)) & 3) << (j * 4);
+        }
+        expand2[i] = v;
+    }
+    for(i = 0; i < 16; i++) {
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            b = ((i >> j) & 1);
+            v |= b << (2 * j);
+            v |= b << (2 * j + 1);
+        }
+        expand4to8[i] = v;
+    }
+
+    /* valid range: 1 MB -> 256 MB */
+    s->vram_size = 1024 * 1024;
+    while (s->vram_size < (s->vram_size_mb << 20) &&
+           s->vram_size < (256 << 20)) {
+        s->vram_size <<= 1;
+    }
+    s->vram_size_mb = s->vram_size >> 20;
+
+    s->is_vbe_vmstate = 1;
+    memory_region_init_ram(&s->vram, "vga.vram", s->vram_size);
+    vmstate_register_ram_global(&s->vram);
+    xen_register_framebuffer(&s->vram);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    s->get_bpp = vga_get_bpp;
+    s->get_offsets = vga_get_offsets;
+    s->get_resolution = vga_get_resolution;
+    s->update = vga_update_display;
+    s->invalidate = vga_invalidate_display;
+    s->screen_dump = vga_screen_dump;
+    s->text_update = vga_update_text;
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        s->retrace = vga_dumb_retrace;
+        s->update_retrace_info = vga_dumb_update_retrace_info;
+        break;
+
+    case VGA_RETRACE_PRECISE:
+        s->retrace = vga_precise_retrace;
+        s->update_retrace_info = vga_precise_update_retrace_info;
+        break;
+    }
+    vga_dirty_log_start(s);
+}
+
+static const MemoryRegionPortio vga_portio_list[] = {
+    { 0x04,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio vbe_portio_list[] = {
+    { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
+# ifdef TARGET_I386
+    { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# endif
+    { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+    PORTIO_END_OF_LIST(),
+};
+
+/* Used by both ISA and PCI */
+MemoryRegion *vga_init_io(VGACommonState *s,
+                          const MemoryRegionPortio **vga_ports,
+                          const MemoryRegionPortio **vbe_ports)
+{
+    MemoryRegion *vga_mem;
+
+    *vga_ports = vga_portio_list;
+    *vbe_ports = vbe_portio_list;
+
+    vga_mem = g_malloc(sizeof(*vga_mem));
+    memory_region_init_io(vga_mem, &vga_mem_ops, s,
+                          "vga-lowmem", 0x20000);
+    memory_region_set_flush_coalesced(vga_mem);
+
+    return vga_mem;
+}
+
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+              MemoryRegion *address_space_io, bool init_vga_ports)
+{
+    MemoryRegion *vga_io_memory;
+    const MemoryRegionPortio *vga_ports, *vbe_ports;
+    PortioList *vga_port_list = g_new(PortioList, 1);
+    PortioList *vbe_port_list = g_new(PortioList, 1);
+
+    qemu_register_reset(vga_reset, s);
+
+    s->bank_offset = 0;
+
+    s->legacy_address_space = address_space;
+
+    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+    memory_region_add_subregion_overlap(address_space,
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory,
+                                        1);
+    memory_region_set_coalescing(vga_io_memory);
+    if (init_vga_ports) {
+        portio_list_init(vga_port_list, vga_ports, s, "vga");
+        portio_list_add(vga_port_list, address_space_io, 0x3b0);
+    }
+    if (vbe_ports) {
+        portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
+        portio_list_add(vbe_port_list, address_space_io, 0x1ce);
+    }
+}
+
+void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
+{
+    /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
+     * so use an alias to avoid double-mapping the same region.
+     */
+    memory_region_init_alias(&s->vram_vbe, "vram.vbe",
+                             &s->vram, 0, memory_region_size(&s->vram));
+    /* XXX: use optimized standard vga accesses */
+    memory_region_add_subregion(system_memory,
+                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                &s->vram_vbe);
+    s->vbe_mapped = 1;
+}
+/********************************************************/
+/* vga screen dump */
+
+void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
+{
+    int width = pixman_image_get_width(ds->image);
+    int height = pixman_image_get_height(ds->image);
+    FILE *f;
+    int y;
+    int ret;
+    pixman_image_t *linebuf;
+
+    trace_ppm_save(filename, ds);
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
+    if (ret < 0) {
+        linebuf = NULL;
+        goto write_err;
+    }
+    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
+    for (y = 0; y < height; y++) {
+        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
+        clearerr(f);
+        ret = fwrite(pixman_image_get_data(linebuf), 1,
+                     pixman_image_get_stride(linebuf), f);
+        (void)ret;
+        if (ferror(f)) {
+            goto write_err;
+        }
+    }
+
+out:
+    qemu_pixman_image_unref(linebuf);
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp)
+{
+    VGACommonState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    if (cswitch) {
+        vga_invalidate_display(s);
+    }
+    vga_hw_update();
+    ppm_save(filename, surface, errp);
+}
diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c
deleted file mode 100644 (file)
index bf316c6..0000000
+++ /dev/null
@@ -1,1931 +0,0 @@
-/*
- * Samsung exynos4210 Display Controller (FIMD)
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- * Based on LCD controller for Samsung S5PC1xx-based board emulation
- * by Kirill Batuzov <batuzovk@ispras.ru>
- *
- * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "exec/cpu-all.h"
-#include "hw/sysbus.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "qemu/bswap.h"
-
-/* Debug messages configuration */
-#define EXYNOS4210_FIMD_DEBUG              0
-#define EXYNOS4210_FIMD_MODE_TRACE         0
-
-#if EXYNOS4210_FIMD_DEBUG == 0
-    #define DPRINT_L1(fmt, args...)       do { } while (0)
-    #define DPRINT_L2(fmt, args...)       do { } while (0)
-    #define DPRINT_ERROR(fmt, args...)    do { } while (0)
-#elif EXYNOS4210_FIMD_DEBUG == 1
-    #define DPRINT_L1(fmt, args...) \
-        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-    #define DPRINT_L2(fmt, args...)       do { } while (0)
-    #define DPRINT_ERROR(fmt, args...)  \
-        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#else
-    #define DPRINT_L1(fmt, args...) \
-        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-    #define DPRINT_L2(fmt, args...) \
-        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-    #define DPRINT_ERROR(fmt, args...)  \
-        do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#endif
-
-#if EXYNOS4210_FIMD_MODE_TRACE == 0
-    #define DPRINT_TRACE(fmt, args...)        do { } while (0)
-#else
-    #define DPRINT_TRACE(fmt, args...)        \
-        do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-#endif
-
-#define NUM_OF_WINDOWS              5
-#define FIMD_REGS_SIZE              0x4114
-
-/* Video main control registers */
-#define FIMD_VIDCON0                0x0000
-#define FIMD_VIDCON1                0x0004
-#define FIMD_VIDCON2                0x0008
-#define FIMD_VIDCON3                0x000C
-#define FIMD_VIDCON0_ENVID_F        (1 << 0)
-#define FIMD_VIDCON0_ENVID          (1 << 1)
-#define FIMD_VIDCON0_ENVID_MASK     ((1 << 0) | (1 << 1))
-#define FIMD_VIDCON1_ROMASK         0x07FFE000
-
-/* Video time control registers */
-#define FIMD_VIDTCON_START          0x10
-#define FIMD_VIDTCON_END            0x1C
-#define FIMD_VIDTCON2_SIZE_MASK     0x07FF
-#define FIMD_VIDTCON2_HOR_SHIFT     0
-#define FIMD_VIDTCON2_VER_SHIFT     11
-
-/* Window control registers */
-#define FIMD_WINCON_START           0x0020
-#define FIMD_WINCON_END             0x0030
-#define FIMD_WINCON_ROMASK          0x82200000
-#define FIMD_WINCON_ENWIN           (1 << 0)
-#define FIMD_WINCON_BLD_PIX         (1 << 6)
-#define FIMD_WINCON_ALPHA_MUL       (1 << 7)
-#define FIMD_WINCON_ALPHA_SEL       (1 << 1)
-#define FIMD_WINCON_SWAP            0x078000
-#define FIMD_WINCON_SWAP_SHIFT      15
-#define FIMD_WINCON_SWAP_WORD       0x1
-#define FIMD_WINCON_SWAP_HWORD      0x2
-#define FIMD_WINCON_SWAP_BYTE       0x4
-#define FIMD_WINCON_SWAP_BITS       0x8
-#define FIMD_WINCON_BUFSTAT_L       (1 << 21)
-#define FIMD_WINCON_BUFSTAT_H       (1 << 31)
-#define FIMD_WINCON_BUFSTATUS       ((1 << 21) | (1 << 31))
-#define FIMD_WINCON_BUF0_STAT       ((0 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF1_STAT       ((1 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF2_STAT       ((0 << 21) | (1 << 31))
-#define FIMD_WINCON_BUFSELECT       ((1 << 20) | (1 << 30))
-#define FIMD_WINCON_BUF0_SEL        ((0 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF1_SEL        ((1 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF2_SEL        ((0 << 20) | (1 << 30))
-#define FIMD_WINCON_BUFMODE         (1 << 14)
-#define IS_PALETTIZED_MODE(w)       (w->wincon & 0xC)
-#define PAL_MODE_WITH_ALPHA(x)       ((x) == 7)
-#define WIN_BPP_MODE(w)             ((w->wincon >> 2) & 0xF)
-#define WIN_BPP_MODE_WITH_ALPHA(w)     \
-    (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
-
-/* Shadow control register */
-#define FIMD_SHADOWCON              0x0034
-#define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
-/* Channel mapping control register */
-#define FIMD_WINCHMAP               0x003C
-
-/* Window position control registers */
-#define FIMD_VIDOSD_START           0x0040
-#define FIMD_VIDOSD_END             0x0088
-#define FIMD_VIDOSD_COORD_MASK      0x07FF
-#define FIMD_VIDOSD_HOR_SHIFT       11
-#define FIMD_VIDOSD_VER_SHIFT       0
-#define FIMD_VIDOSD_ALPHA_AEN0      0xFFF000
-#define FIMD_VIDOSD_AEN0_SHIFT      12
-#define FIMD_VIDOSD_ALPHA_AEN1      0x000FFF
-
-/* Frame buffer address registers */
-#define FIMD_VIDWADD0_START         0x00A0
-#define FIMD_VIDWADD0_END           0x00C4
-#define FIMD_VIDWADD0_END           0x00C4
-#define FIMD_VIDWADD1_START         0x00D0
-#define FIMD_VIDWADD1_END           0x00F4
-#define FIMD_VIDWADD2_START         0x0100
-#define FIMD_VIDWADD2_END           0x0110
-#define FIMD_VIDWADD2_PAGEWIDTH     0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE       0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
-#define FIMD_VIDW0ADD0_B2           0x20A0
-#define FIMD_VIDW4ADD0_B2           0x20C0
-
-/* Video interrupt control registers */
-#define FIMD_VIDINTCON0             0x130
-#define FIMD_VIDINTCON1             0x134
-
-/* Window color key registers */
-#define FIMD_WKEYCON_START          0x140
-#define FIMD_WKEYCON_END            0x15C
-#define FIMD_WKEYCON0_COMPKEY       0x00FFFFFF
-#define FIMD_WKEYCON0_CTL_SHIFT     24
-#define FIMD_WKEYCON0_DIRCON        (1 << 24)
-#define FIMD_WKEYCON0_KEYEN         (1 << 25)
-#define FIMD_WKEYCON0_KEYBLEN       (1 << 26)
-/* Window color key alpha control register */
-#define FIMD_WKEYALPHA_START        0x160
-#define FIMD_WKEYALPHA_END          0x16C
-
-/* Dithering control register */
-#define FIMD_DITHMODE               0x170
-
-/* Window alpha control registers */
-#define FIMD_VIDALPHA_ALPHA_LOWER   0x000F0F0F
-#define FIMD_VIDALPHA_ALPHA_UPPER   0x00F0F0F0
-#define FIMD_VIDWALPHA_START        0x21C
-#define FIMD_VIDWALPHA_END          0x240
-
-/* Window color map registers */
-#define FIMD_WINMAP_START           0x180
-#define FIMD_WINMAP_END             0x190
-#define FIMD_WINMAP_EN              (1 << 24)
-#define FIMD_WINMAP_COLOR_MASK      0x00FFFFFF
-
-/* Window palette control registers */
-#define FIMD_WPALCON_HIGH           0x019C
-#define FIMD_WPALCON_LOW            0x01A0
-#define FIMD_WPALCON_UPDATEEN       (1 << 9)
-#define FIMD_WPAL_W0PAL_L           0x07
-#define FIMD_WPAL_W0PAL_L_SHT        0
-#define FIMD_WPAL_W1PAL_L           0x07
-#define FIMD_WPAL_W1PAL_L_SHT       3
-#define FIMD_WPAL_W2PAL_L           0x01
-#define FIMD_WPAL_W2PAL_L_SHT       6
-#define FIMD_WPAL_W2PAL_H           0x06
-#define FIMD_WPAL_W2PAL_H_SHT       8
-#define FIMD_WPAL_W3PAL_L           0x01
-#define FIMD_WPAL_W3PAL_L_SHT       7
-#define FIMD_WPAL_W3PAL_H           0x06
-#define FIMD_WPAL_W3PAL_H_SHT       12
-#define FIMD_WPAL_W4PAL_L           0x01
-#define FIMD_WPAL_W4PAL_L_SHT       8
-#define FIMD_WPAL_W4PAL_H           0x06
-#define FIMD_WPAL_W4PAL_H_SHT       16
-
-/* Trigger control registers */
-#define FIMD_TRIGCON                0x01A4
-#define FIMD_TRIGCON_ROMASK         0x00000004
-
-/* LCD I80 Interface Control */
-#define FIMD_I80IFCON_START         0x01B0
-#define FIMD_I80IFCON_END           0x01BC
-/* Color gain control register */
-#define FIMD_COLORGAINCON           0x01C0
-/* LCD i80 Interface Command Control */
-#define FIMD_LDI_CMDCON0            0x01D0
-#define FIMD_LDI_CMDCON1            0x01D4
-/* I80 System Interface Manual Command Control */
-#define FIMD_SIFCCON0               0x01E0
-#define FIMD_SIFCCON2               0x01E8
-
-/* Hue Control Registers */
-#define FIMD_HUECOEFCR_START        0x01EC
-#define FIMD_HUECOEFCR_END          0x01F4
-#define FIMD_HUECOEFCB_START        0x01FC
-#define FIMD_HUECOEFCB_END          0x0208
-#define FIMD_HUEOFFSET              0x020C
-
-/* Video interrupt control registers */
-#define FIMD_VIDINT_INTFIFOPEND     (1 << 0)
-#define FIMD_VIDINT_INTFRMPEND      (1 << 1)
-#define FIMD_VIDINT_INTI80PEND      (1 << 2)
-#define FIMD_VIDINT_INTEN           (1 << 0)
-#define FIMD_VIDINT_INTFIFOEN       (1 << 1)
-#define FIMD_VIDINT_INTFRMEN        (1 << 12)
-#define FIMD_VIDINT_I80IFDONE       (1 << 17)
-
-/* Window blend equation control registers */
-#define FIMD_BLENDEQ_START          0x0244
-#define FIMD_BLENDEQ_END            0x0250
-#define FIMD_BLENDCON               0x0260
-#define FIMD_ALPHA_8BIT             (1 << 0)
-#define FIMD_BLENDEQ_COEF_MASK      0xF
-
-/* Window RTQOS Control Registers */
-#define FIMD_WRTQOSCON_START        0x0264
-#define FIMD_WRTQOSCON_END          0x0274
-
-/* LCD I80 Interface Command */
-#define FIMD_I80IFCMD_START         0x0280
-#define FIMD_I80IFCMD_END           0x02AC
-
-/* Shadow windows control registers */
-#define FIMD_SHD_ADD0_START         0x40A0
-#define FIMD_SHD_ADD0_END           0x40C0
-#define FIMD_SHD_ADD1_START         0x40D0
-#define FIMD_SHD_ADD1_END           0x40F0
-#define FIMD_SHD_ADD2_START         0x4100
-#define FIMD_SHD_ADD2_END           0x4110
-
-/* Palette memory */
-#define FIMD_PAL_MEM_START          0x2400
-#define FIMD_PAL_MEM_END            0x37FC
-/* Palette memory aliases for windows 0 and 1 */
-#define FIMD_PALMEM_AL_START        0x0400
-#define FIMD_PALMEM_AL_END          0x0BFC
-
-typedef struct {
-    uint8_t r, g, b;
-    /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
-    uint32_t a;
-} rgba;
-#define RGBA_SIZE  7
-
-typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
-typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
-
-struct Exynos4210fimdWindow {
-    uint32_t wincon;        /* Window control register */
-    uint32_t buf_start[3];  /* Start address for video frame buffer */
-    uint32_t buf_end[3];    /* End address for video frame buffer */
-    uint32_t keycon[2];     /* Window color key registers */
-    uint32_t keyalpha;      /* Color key alpha control register */
-    uint32_t winmap;        /* Window color map register */
-    uint32_t blendeq;       /* Window blending equation control register */
-    uint32_t rtqoscon;      /* Window RTQOS Control Registers */
-    uint32_t palette[256];  /* Palette RAM */
-    uint32_t shadow_buf_start;      /* Start address of shadow frame buffer */
-    uint32_t shadow_buf_end;        /* End address of shadow frame buffer */
-    uint32_t shadow_buf_size;       /* Virtual shadow screen width */
-
-    pixel_to_rgb_func *pixel_to_rgb;
-    void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
-            bool blend);
-    uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
-    uint16_t lefttop_x, lefttop_y;   /* VIDOSD0 register */
-    uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
-    uint32_t osdsize;                /* VIDOSD2&3 register */
-    uint32_t alpha_val[2];           /* VIDOSD2&3, VIDWALPHA registers */
-    uint16_t virtpage_width;         /* VIDWADD2 register */
-    uint16_t virtpage_offsize;       /* VIDWADD2 register */
-    MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
-    uint8_t *host_fb_addr;           /* Host pointer to window's framebuffer */
-    hwaddr fb_len;       /* Framebuffer length */
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    QemuConsole *console;
-    qemu_irq irq[3];
-
-    uint32_t vidcon[4];     /* Video main control registers 0-3 */
-    uint32_t vidtcon[4];    /* Video time control registers 0-3 */
-    uint32_t shadowcon;     /* Window shadow control register */
-    uint32_t winchmap;      /* Channel mapping control register */
-    uint32_t vidintcon[2];  /* Video interrupt control registers */
-    uint32_t dithmode;      /* Dithering control register */
-    uint32_t wpalcon[2];    /* Window palette control registers */
-    uint32_t trigcon;       /* Trigger control register */
-    uint32_t i80ifcon[4];   /* I80 interface control registers */
-    uint32_t colorgaincon;  /* Color gain control register */
-    uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
-    uint32_t sifccon[3];    /* I80 System Interface Manual Command Control */
-    uint32_t huecoef_cr[4]; /* Hue control registers */
-    uint32_t huecoef_cb[4]; /* Hue control registers */
-    uint32_t hueoffset;     /* Hue offset control register */
-    uint32_t blendcon;      /* Blending control register */
-    uint32_t i80ifcmd[12];  /* LCD I80 Interface Command */
-
-    Exynos4210fimdWindow window[5];    /* Window-specific registers */
-    uint8_t *ifb;           /* Internal frame buffer */
-    bool invalidate;        /* Image needs to be redrawn */
-    bool enabled;           /* Display controller is enabled */
-} Exynos4210fimdState;
-
-/* Perform byte/halfword/word swap of data according to WINCON */
-static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
-{
-    int i;
-    uint64_t res;
-    uint64_t x = *data;
-
-    if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
-        res = 0;
-        for (i = 0; i < 64; i++) {
-            if (x & (1ULL << (64 - i))) {
-                res |= (1ULL << i);
-            }
-        }
-        x = res;
-    }
-
-    if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
-        x = bswap64(x);
-    }
-
-    if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
-        x = ((x & 0x000000000000FFFFULL) << 48) |
-            ((x & 0x00000000FFFF0000ULL) << 16) |
-            ((x & 0x0000FFFF00000000ULL) >> 16) |
-            ((x & 0xFFFF000000000000ULL) >> 48);
-    }
-
-    if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
-        x = ((x & 0x00000000FFFFFFFFULL) << 32) |
-            ((x & 0xFFFFFFFF00000000ULL) >> 32);
-    }
-
-    *data = x;
-}
-
-/* Conversion routines of Pixel data from frame buffer area to internal RGBA
- * pixel representation.
- * Every color component internally represented as 8-bit value. If original
- * data has less than 8 bit for component, data is extended to 8 bit. For
- * example, if blue component has only two possible values 0 and 1 it will be
- * extended to 0 and 0xFF */
-
-/* One bit for alpha representation */
-#define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
-    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
-           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
-    pixel >>= (B); \
-    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
-           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
-    pixel >>= (G); \
-    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
-           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
-    pixel >>= (R); \
-    p->a = (pixel & 0x1); \
-}
-
-DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
-DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
-DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
-
-/* Alpha component is always zero */
-#define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
-    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
-           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
-    pixel >>= (B); \
-    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
-           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
-    pixel >>= (G); \
-    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
-           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
-    p->a = 0x0; \
-}
-
-DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb,  5, 6, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb,  5, 5, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb,  6, 6, 6)
-DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb,  8, 8, 8)
-
-/* Alpha component has some meaningful value */
-#define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
-    p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
-           ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
-    pixel >>= (B); \
-    p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
-           ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
-    pixel >>= (G); \
-    p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
-           ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
-    pixel >>= (R); \
-    p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
-           ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
-    p->a = p->a | (p->a << 8) | (p->a << 16); \
-}
-
-DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
-
-/* Lookup table to extent 2-bit color component to 8 bit */
-static const uint8_t pixel_lutable_2b[4] = {
-     0x0, 0x55, 0xAA, 0xFF
-};
-/* Lookup table to extent 3-bit color component to 8 bit */
-static const uint8_t pixel_lutable_3b[8] = {
-     0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
-};
-/* Special case for a232 bpp mode */
-static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
-{
-    p->b = pixel_lutable_2b[(pixel & 0x3)];
-    pixel >>= 2;
-    p->g = pixel_lutable_3b[(pixel & 0x7)];
-    pixel >>= 3;
-    p->r = pixel_lutable_2b[(pixel & 0x3)];
-    pixel >>= 2;
-    p->a = (pixel & 0x1);
-}
-
-/* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
- * for all three color components */
-static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
-{
-    uint8_t comm = (pixel >> 15) & 1;
-    p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
-    pixel >>= 5;
-    p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
-    pixel >>= 5;
-    p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
-    p->a = 0x0;
-}
-
-/* Put/get pixel to/from internal LCD Controller framebuffer */
-
-static int put_pixel_ifb(const rgba p, uint8_t *d)
-{
-    *(uint8_t *)d++ = p.r;
-    *(uint8_t *)d++ = p.g;
-    *(uint8_t *)d++ = p.b;
-    *(uint32_t *)d = p.a;
-    return RGBA_SIZE;
-}
-
-static int get_pixel_ifb(const uint8_t *s, rgba *p)
-{
-    p->r = *(uint8_t *)s++;
-    p->g = *(uint8_t *)s++;
-    p->b = *(uint8_t *)s++;
-    p->a = (*(uint32_t *)s) & 0x00FFFFFF;
-    return RGBA_SIZE;
-}
-
-static pixel_to_rgb_func *palette_data_format[8] = {
-    [0] = pixel_565_to_rgb,
-    [1] = pixel_a555_to_rgb,
-    [2] = pixel_666_to_rgb,
-    [3] = pixel_a665_to_rgb,
-    [4] = pixel_a666_to_rgb,
-    [5] = pixel_888_to_rgb,
-    [6] = pixel_a888_to_rgb,
-    [7] = pixel_8888_to_rgb
-};
-
-/* Returns Index in palette data formats table for given window number WINDOW */
-static uint32_t
-exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
-{
-    uint32_t ret;
-
-    switch (window) {
-    case 0:
-        ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
-        if (ret != 7) {
-            ret = 6 - ret;
-        }
-        break;
-    case 1:
-        ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
-        if (ret != 7) {
-            ret = 6 - ret;
-        }
-        break;
-    case 2:
-        ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
-            ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
-        break;
-    case 3:
-        ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
-            ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
-        break;
-    case 4:
-        ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
-            ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
-        break;
-    default:
-        hw_error("exynos4210.fimd: incorrect window number %d\n", window);
-        ret = 0;
-        break;
-    }
-    return ret;
-}
-
-#define FIMD_1_MINUS_COLOR(x)    \
-            ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
-                                  (0xFF0000 - ((x) & 0xFF0000)))
-#define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
-#define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
-
-/* Multiply three lower bytes of two 32-bit words with each other.
- * Each byte with values 0-255 is considered as a number with possible values
- * in a range [0 - 1] */
-static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
-{
-    uint32_t tmp;
-    uint32_t ret;
-
-    ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
-    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
-            0xFF00 : tmp << 8;
-    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
-            0xFF0000 : tmp << 16;
-    return ret;
-}
-
-/* For each corresponding bytes of two 32-bit words: (a*b + c*d)
- * Byte values 0-255 are mapped to a range [0 .. 1] */
-static inline uint32_t
-fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
-{
-    uint32_t tmp;
-    uint32_t ret;
-
-    ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
-            > 0xFF) ? 0xFF : tmp;
-    ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
-            ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
-    ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
-            ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
-                    0xFF0000 : tmp << 16;
-    return ret;
-}
-
-/* These routines cover all possible sources of window's transparent factor
- * used in blending equation. Choice of routine is affected by WPALCON
- * registers, BLENDCON register and window's WINCON register */
-
-static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return pix_a;
-}
-
-static uint32_t
-fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return EXTEND_LOWER_HALFBYTE(pix_a);
-}
-
-static uint32_t
-fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return EXTEND_UPPER_HALFBYTE(pix_a);
-}
-
-static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
-}
-
-static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
-            EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
-}
-
-static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return w->alpha_val[pix_a];
-}
-
-static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
-}
-
-static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
-}
-
-static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
-    return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
-            FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
-}
-
-/* Updates currently active alpha value get function for specified window */
-static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
-{
-    Exynos4210fimdWindow *w = &s->window[win];
-    const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
-
-    if (w->wincon & FIMD_WINCON_BLD_PIX) {
-        if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
-            /* In this case, alpha component contains meaningful value */
-            if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
-                w->get_alpha = alpha_is_8bit ?
-                        fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
-            } else {
-                w->get_alpha = alpha_is_8bit ?
-                        fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
-            }
-        } else {
-            if (IS_PALETTIZED_MODE(w) &&
-                  PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
-                /* Alpha component has 8-bit numeric value */
-                w->get_alpha = alpha_is_8bit ?
-                        fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
-            } else {
-                /* Alpha has only two possible values (AEN) */
-                w->get_alpha = alpha_is_8bit ?
-                        fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
-            }
-        }
-    } else {
-        w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
-                fimd_get_alpha_sel_ext;
-    }
-}
-
-/* Blends current window's (w) pixel (foreground pixel *ret) with background
- * window (w_blend) pixel p_bg according to formula:
- * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
- * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
- */
-static void
-exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
-{
-    rgba p_fg = *ret;
-    uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
-            (p_bg.b & 0xFF);
-    uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
-            (p_fg.b & 0xFF);
-    uint32_t alpha_fg = p_fg.a;
-    int i;
-    /* It is possible that blending equation parameters a and b do not
-     * depend on window BLENEQ register. Account for this with first_coef */
-    enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
-    uint32_t first_coef = A_COEF;
-    uint32_t blend_param[COEF_NUM];
-
-    if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
-        uint32_t colorkey = (w->keycon[1] &
-              ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
-
-        if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
-            (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
-            /* Foreground pixel is displayed */
-            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
-                alpha_fg = w->keyalpha;
-                blend_param[A_COEF] = alpha_fg;
-                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
-            } else {
-                alpha_fg = 0;
-                blend_param[A_COEF] = 0xFFFFFF;
-                blend_param[B_COEF] = 0x0;
-            }
-            first_coef = P_COEF;
-        } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
-            (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
-            /* Background pixel is displayed */
-            if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
-                alpha_fg = w->keyalpha;
-                blend_param[A_COEF] = alpha_fg;
-                blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
-            } else {
-                alpha_fg = 0;
-                blend_param[A_COEF] = 0x0;
-                blend_param[B_COEF] = 0xFFFFFF;
-            }
-            first_coef = P_COEF;
-        }
-    }
-
-    for (i = first_coef; i < COEF_NUM; i++) {
-        switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
-        case 0:
-            blend_param[i] = 0;
-            break;
-        case 1:
-            blend_param[i] = 0xFFFFFF;
-            break;
-        case 2:
-            blend_param[i] = alpha_fg;
-            break;
-        case 3:
-            blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
-            break;
-        case 4:
-            blend_param[i] = p_bg.a;
-            break;
-        case 5:
-            blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
-            break;
-        case 6:
-            blend_param[i] = w->alpha_val[0];
-            break;
-        case 10:
-            blend_param[i] = fg_color;
-            break;
-        case 11:
-            blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
-            break;
-        case 12:
-            blend_param[i] = bg_color;
-            break;
-        case 13:
-            blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
-            break;
-        default:
-            hw_error("exynos4210.fimd: blend equation coef illegal value\n");
-            break;
-        }
-    }
-
-    fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
-            fg_color, blend_param[A_COEF]);
-    ret->b = fg_color & 0xFF;
-    fg_color >>= 8;
-    ret->g = fg_color & 0xFF;
-    fg_color >>= 8;
-    ret->r = fg_color & 0xFF;
-    ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
-            p_bg.a, blend_param[Q_COEF]);
-}
-
-/* These routines read data from video frame buffer in system RAM, convert
- * this data to display controller internal representation, if necessary,
- * perform pixel blending with data, currently presented in internal buffer.
- * Result is stored in display controller internal frame buffer. */
-
-/* Draw line with index in palette table in RAM frame buffer data */
-#define DEF_DRAW_LINE_PALETTE(N) \
-static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
-               uint8_t *dst, bool blend) \
-{ \
-    int width = w->rightbot_x - w->lefttop_x + 1; \
-    uint8_t *ifb = dst; \
-    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
-    uint64_t data; \
-    rgba p, p_old; \
-    int i; \
-    do { \
-        data = ldq_raw((void *)src); \
-        src += 8; \
-        fimd_swap_data(swap, &data); \
-        for (i = (64 / (N) - 1); i >= 0; i--) { \
-            w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
-                                   ((1ULL << (N)) - 1)], &p); \
-            p.a = w->get_alpha(w, p.a); \
-            if (blend) { \
-                ifb +=  get_pixel_ifb(ifb, &p_old); \
-                exynos4210_fimd_blend_pixel(w, p_old, &p); \
-            } \
-            dst += put_pixel_ifb(p, dst); \
-        } \
-        width -= (64 / (N)); \
-    } while (width > 0); \
-}
-
-/* Draw line with direct color value in RAM frame buffer data */
-#define DEF_DRAW_LINE_NOPALETTE(N) \
-static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
-                    uint8_t *dst, bool blend) \
-{ \
-    int width = w->rightbot_x - w->lefttop_x + 1; \
-    uint8_t *ifb = dst; \
-    uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
-    uint64_t data; \
-    rgba p, p_old; \
-    int i; \
-    do { \
-        data = ldq_raw((void *)src); \
-        src += 8; \
-        fimd_swap_data(swap, &data); \
-        for (i = (64 / (N) - 1); i >= 0; i--) { \
-            w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
-            p.a = w->get_alpha(w, p.a); \
-            if (blend) { \
-                ifb += get_pixel_ifb(ifb, &p_old); \
-                exynos4210_fimd_blend_pixel(w, p_old, &p); \
-            } \
-            dst += put_pixel_ifb(p, dst); \
-        } \
-        width -= (64 / (N)); \
-    } while (width > 0); \
-}
-
-DEF_DRAW_LINE_PALETTE(1)
-DEF_DRAW_LINE_PALETTE(2)
-DEF_DRAW_LINE_PALETTE(4)
-DEF_DRAW_LINE_PALETTE(8)
-DEF_DRAW_LINE_NOPALETTE(8)  /* 8bpp mode has palette and non-palette versions */
-DEF_DRAW_LINE_NOPALETTE(16)
-DEF_DRAW_LINE_NOPALETTE(32)
-
-/* Special draw line routine for window color map case */
-static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
-                       uint8_t *dst, bool blend)
-{
-    rgba p, p_old;
-    uint8_t *ifb = dst;
-    int width = w->rightbot_x - w->lefttop_x + 1;
-    uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
-
-    do {
-        pixel_888_to_rgb(map_color, &p);
-        p.a = w->get_alpha(w, p.a);
-        if (blend) {
-            ifb += get_pixel_ifb(ifb, &p_old);
-            exynos4210_fimd_blend_pixel(w, p_old, &p);
-        }
-        dst += put_pixel_ifb(p, dst);
-    } while (--width);
-}
-
-/* Write RGB to QEMU's GraphicConsole framebuffer */
-
-static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
-{
-    uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
-    *(uint8_t *)d = pixel;
-    return 1;
-}
-
-static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
-{
-    uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
-    *(uint16_t *)d = pixel;
-    return 2;
-}
-
-static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
-{
-    uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
-    *(uint16_t *)d = pixel;
-    return 2;
-}
-
-static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
-{
-    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
-    *(uint8_t *)d++ = (pixel >>  0) & 0xFF;
-    *(uint8_t *)d++ = (pixel >>  8) & 0xFF;
-    *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
-    return 3;
-}
-
-static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
-{
-    uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
-    *(uint32_t *)d = pixel;
-    return 4;
-}
-
-/* Routine to copy pixel from internal buffer to QEMU buffer */
-static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
-static inline void fimd_update_putpix_qemu(int bpp)
-{
-    switch (bpp) {
-    case 8:
-        put_pixel_toqemu = put_to_qemufb_pixel8;
-        break;
-    case 15:
-        put_pixel_toqemu = put_to_qemufb_pixel15;
-        break;
-    case 16:
-        put_pixel_toqemu = put_to_qemufb_pixel16;
-        break;
-    case 24:
-        put_pixel_toqemu = put_to_qemufb_pixel24;
-        break;
-    case 32:
-        put_pixel_toqemu = put_to_qemufb_pixel32;
-        break;
-    default:
-        hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
-        break;
-    }
-}
-
-/* Routine to copy a line from internal frame buffer to QEMU display */
-static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
-{
-    rgba p;
-
-    do {
-        src += get_pixel_ifb(src, &p);
-        dst += put_pixel_toqemu(p, dst);
-    } while (--width);
-}
-
-/* Parse BPPMODE_F = WINCON1[5:2] bits */
-static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
-{
-    Exynos4210fimdWindow *w = &s->window[win];
-
-    if (w->winmap & FIMD_WINMAP_EN) {
-        w->draw_line = draw_line_mapcolor;
-        return;
-    }
-
-    switch (WIN_BPP_MODE(w)) {
-    case 0:
-        w->draw_line = draw_line_palette_1;
-        w->pixel_to_rgb =
-                palette_data_format[exynos4210_fimd_palette_format(s, win)];
-        break;
-    case 1:
-        w->draw_line = draw_line_palette_2;
-        w->pixel_to_rgb =
-                palette_data_format[exynos4210_fimd_palette_format(s, win)];
-        break;
-    case 2:
-        w->draw_line = draw_line_palette_4;
-        w->pixel_to_rgb =
-                palette_data_format[exynos4210_fimd_palette_format(s, win)];
-        break;
-    case 3:
-        w->draw_line = draw_line_palette_8;
-        w->pixel_to_rgb =
-                palette_data_format[exynos4210_fimd_palette_format(s, win)];
-        break;
-    case 4:
-        w->draw_line = draw_line_8;
-        w->pixel_to_rgb = pixel_a232_to_rgb;
-        break;
-    case 5:
-        w->draw_line = draw_line_16;
-        w->pixel_to_rgb = pixel_565_to_rgb;
-        break;
-    case 6:
-        w->draw_line = draw_line_16;
-        w->pixel_to_rgb = pixel_a555_to_rgb;
-        break;
-    case 7:
-        w->draw_line = draw_line_16;
-        w->pixel_to_rgb = pixel_1555_to_rgb;
-        break;
-    case 8:
-        w->draw_line = draw_line_32;
-        w->pixel_to_rgb = pixel_666_to_rgb;
-        break;
-    case 9:
-        w->draw_line = draw_line_32;
-        w->pixel_to_rgb = pixel_a665_to_rgb;
-        break;
-    case 10:
-        w->draw_line = draw_line_32;
-        w->pixel_to_rgb = pixel_a666_to_rgb;
-        break;
-    case 11:
-        w->draw_line = draw_line_32;
-        w->pixel_to_rgb = pixel_888_to_rgb;
-        break;
-    case 12:
-        w->draw_line = draw_line_32;
-        w->pixel_to_rgb = pixel_a887_to_rgb;
-        break;
-    case 13:
-        w->draw_line = draw_line_32;
-        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
-                FIMD_WINCON_ALPHA_SEL)) {
-            w->pixel_to_rgb = pixel_8888_to_rgb;
-        } else {
-            w->pixel_to_rgb = pixel_a888_to_rgb;
-        }
-        break;
-    case 14:
-        w->draw_line = draw_line_16;
-        if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
-                FIMD_WINCON_ALPHA_SEL)) {
-            w->pixel_to_rgb = pixel_4444_to_rgb;
-        } else {
-            w->pixel_to_rgb = pixel_a444_to_rgb;
-        }
-        break;
-    case 15:
-        w->draw_line = draw_line_16;
-        w->pixel_to_rgb = pixel_555_to_rgb;
-        break;
-    }
-}
-
-#if EXYNOS4210_FIMD_MODE_TRACE > 0
-static const char *exynos4210_fimd_get_bppmode(int mode_code)
-{
-    switch (mode_code) {
-    case 0:
-        return "1 bpp";
-    case 1:
-        return "2 bpp";
-    case 2:
-        return "4 bpp";
-    case 3:
-        return "8 bpp (palettized)";
-    case 4:
-        return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
-    case 5:
-        return "16 bpp (non-palettized, R:5-G:6-B:5)";
-    case 6:
-        return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
-    case 7:
-        return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
-    case 8:
-        return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
-    case 9:
-        return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
-    case 10:
-        return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
-    case 11:
-        return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
-    case 12:
-        return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
-    case 13:
-        return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
-    case 14:
-        return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
-    case 15:
-        return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
-    default:
-        return "Non-existing bpp mode";
-    }
-}
-
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
-                int win_num, uint32_t val)
-{
-    Exynos4210fimdWindow *w = &s->window[win_num];
-
-    if (w->winmap & FIMD_WINMAP_EN) {
-        printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
-                win_num, w->winmap & 0xFFFFFF);
-        return;
-    }
-
-    if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
-        return;
-    }
-    printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
-        exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
-}
-#else
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
-        int win_num, uint32_t val)
-{
-
-}
-#endif
-
-static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
-{
-    switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
-    case FIMD_WINCON_BUF0_STAT:
-        return 0;
-    case FIMD_WINCON_BUF1_STAT:
-        return 1;
-    case FIMD_WINCON_BUF2_STAT:
-        return 2;
-    default:
-        DPRINT_ERROR("Non-existent buffer index\n");
-        return 0;
-    }
-}
-
-/* Updates specified window's MemorySection based on values of WINCON,
- * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
-static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
-{
-    Exynos4210fimdWindow *w = &s->window[win];
-    hwaddr fb_start_addr, fb_mapped_len;
-
-    if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
-            FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
-        return;
-    }
-
-    if (w->host_fb_addr) {
-        cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
-        w->host_fb_addr = NULL;
-        w->fb_len = 0;
-    }
-
-    fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
-    /* Total number of bytes of virtual screen used by current window */
-    w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
-            (w->rightbot_y - w->lefttop_y + 1);
-    w->mem_section = memory_region_find(sysbus_address_space(&s->busdev),
-            fb_start_addr, w->fb_len);
-    assert(w->mem_section.mr);
-    assert(w->mem_section.offset_within_address_space == fb_start_addr);
-    DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
-            win, fb_start_addr, w->fb_len);
-
-    if (w->mem_section.size != w->fb_len ||
-            !memory_region_is_ram(w->mem_section.mr)) {
-        DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
-        goto error_return;
-    }
-
-    w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
-    if (!w->host_fb_addr) {
-        DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
-        goto error_return;
-    }
-
-    if (fb_mapped_len != w->fb_len) {
-        DPRINT_ERROR("Window %u mapped framebuffer length is less then "
-                "expected\n", win);
-        cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
-        goto error_return;
-    }
-    return;
-
-error_return:
-    w->mem_section.mr = NULL;
-    w->mem_section.size = 0;
-    w->host_fb_addr = NULL;
-    w->fb_len = 0;
-}
-
-static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
-{
-    if (enabled && !s->enabled) {
-        unsigned w;
-        s->enabled = true;
-        for (w = 0; w < NUM_OF_WINDOWS; w++) {
-            fimd_update_memory_section(s, w);
-        }
-    }
-    s->enabled = enabled;
-    DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
-}
-
-static inline uint32_t unpack_upper_4(uint32_t x)
-{
-    return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
-}
-
-static inline uint32_t pack_upper_4(uint32_t x)
-{
-    return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
-            ((x & 0xF0) >> 4)) & 0xFFF;
-}
-
-static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
-{
-    if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
-        qemu_irq_lower(s->irq[0]);
-        qemu_irq_lower(s->irq[1]);
-        qemu_irq_lower(s->irq[2]);
-        return;
-    }
-    if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
-            (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
-        qemu_irq_raise(s->irq[0]);
-    } else {
-        qemu_irq_lower(s->irq[0]);
-    }
-    if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
-            (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
-        qemu_irq_raise(s->irq[1]);
-    } else {
-        qemu_irq_lower(s->irq[1]);
-    }
-    if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
-            (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
-        qemu_irq_raise(s->irq[2]);
-    } else {
-        qemu_irq_lower(s->irq[2]);
-    }
-}
-
-static void exynos4210_fimd_invalidate(void *opaque)
-{
-    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
-    s->invalidate = true;
-}
-
-static void exynos4210_update_resolution(Exynos4210fimdState *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->console);
-
-    /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
-    uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
-            FIMD_VIDTCON2_SIZE_MASK) + 1;
-    uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
-            FIMD_VIDTCON2_SIZE_MASK) + 1;
-
-    if (s->ifb == NULL || surface_width(surface) != width ||
-            surface_height(surface) != height) {
-        DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
-           surface_width(surface), surface_height(surface), width, height);
-        qemu_console_resize(s->console, width, height);
-        s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
-        memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
-        exynos4210_fimd_invalidate(s);
-    }
-}
-
-static void exynos4210_fimd_update(void *opaque)
-{
-    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
-    DisplaySurface *surface = qemu_console_surface(s->console);
-    Exynos4210fimdWindow *w;
-    int i, line;
-    hwaddr fb_line_addr, inc_size;
-    int scrn_height;
-    int first_line = -1, last_line = -1, scrn_width;
-    bool blend = false;
-    uint8_t *host_fb_addr;
-    bool is_dirty = false;
-    const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
-    const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
-            FIMD_VIDTCON2_SIZE_MASK) + 1;
-
-    if (!s || !s->console || !surface_bits_per_pixel(surface) ||
-            !s->enabled) {
-        return;
-    }
-    exynos4210_update_resolution(s);
-
-    for (i = 0; i < NUM_OF_WINDOWS; i++) {
-        w = &s->window[i];
-        if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
-            scrn_height = w->rightbot_y - w->lefttop_y + 1;
-            scrn_width = w->virtpage_width;
-            /* Total width of virtual screen page in bytes */
-            inc_size = scrn_width + w->virtpage_offsize;
-            memory_region_sync_dirty_bitmap(w->mem_section.mr);
-            host_fb_addr = w->host_fb_addr;
-            fb_line_addr = w->mem_section.offset_within_region;
-
-            for (line = 0; line < scrn_height; line++) {
-                is_dirty = memory_region_get_dirty(w->mem_section.mr,
-                            fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
-
-                if (s->invalidate || is_dirty) {
-                    if (first_line == -1) {
-                        first_line = line;
-                    }
-                    last_line = line;
-                    w->draw_line(w, host_fb_addr, s->ifb +
-                        w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
-                        global_width * RGBA_SIZE, blend);
-                }
-                host_fb_addr += inc_size;
-                fb_line_addr += inc_size;
-                is_dirty = false;
-            }
-            memory_region_reset_dirty(w->mem_section.mr,
-                w->mem_section.offset_within_region,
-                w->fb_len, DIRTY_MEMORY_VGA);
-            blend = true;
-        }
-    }
-
-    /* Copy resulting image to QEMU_CONSOLE. */
-    if (first_line >= 0) {
-        uint8_t *d;
-        int bpp;
-
-        bpp = surface_bits_per_pixel(surface);
-        fimd_update_putpix_qemu(bpp);
-        bpp = (bpp + 1) >> 3;
-        d = surface_data(surface);
-        for (line = first_line; line <= last_line; line++) {
-            fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
-                    RGBA_SIZE, d + global_width * line * bpp);
-        }
-        dpy_gfx_update(s->console, 0, 0, global_width, global_height);
-    }
-    s->invalidate = false;
-    s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
-    if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
-        exynos4210_fimd_enable(s, false);
-    }
-    exynos4210_fimd_update_irq(s);
-}
-
-static void exynos4210_fimd_reset(DeviceState *d)
-{
-    Exynos4210fimdState *s = DO_UPCAST(Exynos4210fimdState, busdev.qdev, d);
-    unsigned w;
-
-    DPRINT_TRACE("Display controller reset\n");
-    /* Set all display controller registers to 0 */
-    memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
-    for (w = 0; w < NUM_OF_WINDOWS; w++) {
-        memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
-        s->window[w].blendeq = 0xC2;
-        exynos4210_fimd_update_win_bppmode(s, w);
-        exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
-        fimd_update_get_alpha(s, w);
-    }
-
-    if (s->ifb != NULL) {
-        g_free(s->ifb);
-    }
-    s->ifb = NULL;
-
-    exynos4210_fimd_invalidate(s);
-    exynos4210_fimd_enable(s, false);
-    /* Some registers have non-zero initial values */
-    s->winchmap = 0x7D517D51;
-    s->colorgaincon = 0x10040100;
-    s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
-    s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
-    s->hueoffset = 0x01800080;
-}
-
-static void exynos4210_fimd_write(void *opaque, hwaddr offset,
-                              uint64_t val, unsigned size)
-{
-    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
-    unsigned w, i;
-    uint32_t old_value;
-
-    DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
-            (long long unsigned int)val, (long long unsigned int)val);
-
-    switch (offset) {
-    case FIMD_VIDCON0:
-        if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
-            exynos4210_fimd_enable(s, true);
-        } else {
-            if ((val & FIMD_VIDCON0_ENVID) == 0) {
-                exynos4210_fimd_enable(s, false);
-            }
-        }
-        s->vidcon[0] = val;
-        break;
-    case FIMD_VIDCON1:
-        /* Leave read-only bits as is */
-        val = (val & (~FIMD_VIDCON1_ROMASK)) |
-                (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
-        s->vidcon[1] = val;
-        break;
-    case FIMD_VIDCON2 ... FIMD_VIDCON3:
-        s->vidcon[(offset) >> 2] = val;
-        break;
-    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
-        s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
-        break;
-    case FIMD_WINCON_START ... FIMD_WINCON_END:
-        w = (offset - FIMD_WINCON_START) >> 2;
-        /* Window's current buffer ID */
-        i = fimd_get_buffer_id(&s->window[w]);
-        old_value = s->window[w].wincon;
-        val = (val & ~FIMD_WINCON_ROMASK) |
-                (s->window[w].wincon & FIMD_WINCON_ROMASK);
-        if (w == 0) {
-            /* Window 0 wincon ALPHA_MUL bit must always be 0 */
-            val &= ~FIMD_WINCON_ALPHA_MUL;
-        }
-        exynos4210_fimd_trace_bppmode(s, w, val);
-        switch (val & FIMD_WINCON_BUFSELECT) {
-        case FIMD_WINCON_BUF0_SEL:
-            val &= ~FIMD_WINCON_BUFSTATUS;
-            break;
-        case FIMD_WINCON_BUF1_SEL:
-            val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
-            break;
-        case FIMD_WINCON_BUF2_SEL:
-            if (val & FIMD_WINCON_BUFMODE) {
-                val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
-            }
-            break;
-        default:
-            break;
-        }
-        s->window[w].wincon = val;
-        exynos4210_fimd_update_win_bppmode(s, w);
-        fimd_update_get_alpha(s, w);
-        if ((i != fimd_get_buffer_id(&s->window[w])) ||
-                (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
-                        FIMD_WINCON_ENWIN))) {
-            fimd_update_memory_section(s, w);
-        }
-        break;
-    case FIMD_SHADOWCON:
-        old_value = s->shadowcon;
-        s->shadowcon = val;
-        for (w = 0; w < NUM_OF_WINDOWS; w++) {
-            if (FIMD_WINDOW_PROTECTED(old_value, w) &&
-                    !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
-                fimd_update_memory_section(s, w);
-            }
-        }
-        break;
-    case FIMD_WINCHMAP:
-        s->winchmap = val;
-        break;
-    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
-        w = (offset - FIMD_VIDOSD_START) >> 4;
-        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
-        switch (i) {
-        case 0:
-            old_value = s->window[w].lefttop_y;
-            s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
-                                      FIMD_VIDOSD_COORD_MASK;
-            s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
-                                      FIMD_VIDOSD_COORD_MASK;
-            if (s->window[w].lefttop_y != old_value) {
-                fimd_update_memory_section(s, w);
-            }
-            break;
-        case 1:
-            old_value = s->window[w].rightbot_y;
-            s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
-                                       FIMD_VIDOSD_COORD_MASK;
-            s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
-                                       FIMD_VIDOSD_COORD_MASK;
-            if (s->window[w].rightbot_y != old_value) {
-                fimd_update_memory_section(s, w);
-            }
-            break;
-        case 2:
-            if (w == 0) {
-                s->window[w].osdsize = val;
-            } else {
-                s->window[w].alpha_val[0] =
-                    unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
-                    FIMD_VIDOSD_AEN0_SHIFT) |
-                    (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
-                s->window[w].alpha_val[1] =
-                    unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
-                    (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
-            }
-            break;
-        case 3:
-            if (w != 1 && w != 2) {
-                DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
-                return;
-            }
-            s->window[w].osdsize = val;
-            break;
-        }
-        break;
-    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
-        w = (offset - FIMD_VIDWADD0_START) >> 3;
-        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
-        if (i == fimd_get_buffer_id(&s->window[w]) &&
-                s->window[w].buf_start[i] != val) {
-            s->window[w].buf_start[i] = val;
-            fimd_update_memory_section(s, w);
-            break;
-        }
-        s->window[w].buf_start[i] = val;
-        break;
-    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
-        w = (offset - FIMD_VIDWADD1_START) >> 3;
-        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
-        s->window[w].buf_end[i] = val;
-        break;
-    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
-        w = (offset - FIMD_VIDWADD2_START) >> 2;
-        if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
-            (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
-                        s->window[w].virtpage_offsize)) {
-            s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
-            s->window[w].virtpage_offsize =
-                (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
-            fimd_update_memory_section(s, w);
-        }
-        break;
-    case FIMD_VIDINTCON0:
-        s->vidintcon[0] = val;
-        break;
-    case FIMD_VIDINTCON1:
-        s->vidintcon[1] &= ~(val & 7);
-        exynos4210_fimd_update_irq(s);
-        break;
-    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
-        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
-        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
-        s->window[w].keycon[i] = val;
-        break;
-    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
-        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
-        s->window[w].keyalpha = val;
-        break;
-    case FIMD_DITHMODE:
-        s->dithmode = val;
-        break;
-    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
-        w = (offset - FIMD_WINMAP_START) >> 2;
-        old_value = s->window[w].winmap;
-        s->window[w].winmap = val;
-        if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
-            exynos4210_fimd_invalidate(s);
-            exynos4210_fimd_update_win_bppmode(s, w);
-            exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
-            exynos4210_fimd_update(s);
-        }
-        break;
-    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
-        i = (offset - FIMD_WPALCON_HIGH) >> 2;
-        s->wpalcon[i] = val;
-        if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
-            for (w = 0; w < NUM_OF_WINDOWS; w++) {
-                exynos4210_fimd_update_win_bppmode(s, w);
-                fimd_update_get_alpha(s, w);
-            }
-        }
-        break;
-    case FIMD_TRIGCON:
-        val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
-        s->trigcon = val;
-        break;
-    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
-        s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
-        break;
-    case FIMD_COLORGAINCON:
-        s->colorgaincon = val;
-        break;
-    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
-        s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
-        break;
-    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
-        i = (offset - FIMD_SIFCCON0) >> 2;
-        if (i != 2) {
-            s->sifccon[i] = val;
-        }
-        break;
-    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
-        i = (offset - FIMD_HUECOEFCR_START) >> 2;
-        s->huecoef_cr[i] = val;
-        break;
-    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
-        i = (offset - FIMD_HUECOEFCB_START) >> 2;
-        s->huecoef_cb[i] = val;
-        break;
-    case FIMD_HUEOFFSET:
-        s->hueoffset = val;
-        break;
-    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
-        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
-        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
-        if (w == 0) {
-            s->window[w].alpha_val[i] = val;
-        } else {
-            s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
-                (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
-        }
-        break;
-    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
-        s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
-        break;
-    case FIMD_BLENDCON:
-        old_value = s->blendcon;
-        s->blendcon = val;
-        if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
-            for (w = 0; w < NUM_OF_WINDOWS; w++) {
-                fimd_update_get_alpha(s, w);
-            }
-        }
-        break;
-    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
-        s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
-        break;
-    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
-        s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
-        break;
-    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
-        if (offset & 0x0004) {
-            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
-            break;
-        }
-        w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
-        if (fimd_get_buffer_id(&s->window[w]) == 2 &&
-                s->window[w].buf_start[2] != val) {
-            s->window[w].buf_start[2] = val;
-            fimd_update_memory_section(s, w);
-            break;
-        }
-        s->window[w].buf_start[2] = val;
-        break;
-    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
-        if (offset & 0x0004) {
-            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
-            break;
-        }
-        s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
-        break;
-    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
-        if (offset & 0x0004) {
-            DPRINT_ERROR("bad write offset 0x%08x\n", offset);
-            break;
-        }
-        s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
-        break;
-    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
-        s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
-        break;
-    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
-        w = (offset - FIMD_PAL_MEM_START) >> 10;
-        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
-        s->window[w].palette[i] = val;
-        break;
-    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
-        /* Palette memory aliases for windows 0 and 1 */
-        w = (offset - FIMD_PALMEM_AL_START) >> 10;
-        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
-        s->window[w].palette[i] = val;
-        break;
-    default:
-        DPRINT_ERROR("bad write offset 0x%08x\n", offset);
-        break;
-    }
-}
-
-static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
-                                  unsigned size)
-{
-    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
-    int w, i;
-    uint32_t ret = 0;
-
-    DPRINT_L2("read offset 0x%08x\n", offset);
-
-    switch (offset) {
-    case FIMD_VIDCON0 ... FIMD_VIDCON3:
-        return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
-    case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
-        return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
-    case FIMD_WINCON_START ... FIMD_WINCON_END:
-        return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
-    case FIMD_SHADOWCON:
-        return s->shadowcon;
-    case FIMD_WINCHMAP:
-        return s->winchmap;
-    case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
-        w = (offset - FIMD_VIDOSD_START) >> 4;
-        i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
-        switch (i) {
-        case 0:
-            ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
-            FIMD_VIDOSD_HOR_SHIFT) |
-            (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
-            break;
-        case 1:
-            ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
-                FIMD_VIDOSD_HOR_SHIFT) |
-                (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
-            break;
-        case 2:
-            if (w == 0) {
-                ret = s->window[w].osdsize;
-            } else {
-                ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
-                    FIMD_VIDOSD_AEN0_SHIFT) |
-                    pack_upper_4(s->window[w].alpha_val[1]);
-            }
-            break;
-        case 3:
-            if (w != 1 && w != 2) {
-                DPRINT_ERROR("bad read offset 0x%08x\n", offset);
-                return 0xBAADBAAD;
-            }
-            ret = s->window[w].osdsize;
-            break;
-        }
-        return ret;
-    case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
-        w = (offset - FIMD_VIDWADD0_START) >> 3;
-        i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
-        return s->window[w].buf_start[i];
-    case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
-        w = (offset - FIMD_VIDWADD1_START) >> 3;
-        i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
-        return s->window[w].buf_end[i];
-    case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
-        w = (offset - FIMD_VIDWADD2_START) >> 2;
-        return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
-            FIMD_VIDWADD2_OFFSIZE_SHIFT);
-    case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
-        return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
-    case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
-        w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
-        i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
-        return s->window[w].keycon[i];
-    case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
-        w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
-        return s->window[w].keyalpha;
-    case FIMD_DITHMODE:
-        return s->dithmode;
-    case FIMD_WINMAP_START ... FIMD_WINMAP_END:
-        return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
-    case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
-        return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
-    case FIMD_TRIGCON:
-        return s->trigcon;
-    case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
-        return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
-    case FIMD_COLORGAINCON:
-        return s->colorgaincon;
-    case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
-        return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
-    case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
-        i = (offset - FIMD_SIFCCON0) >> 2;
-        return s->sifccon[i];
-    case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
-        i = (offset - FIMD_HUECOEFCR_START) >> 2;
-        return s->huecoef_cr[i];
-    case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
-        i = (offset - FIMD_HUECOEFCB_START) >> 2;
-        return s->huecoef_cb[i];
-    case FIMD_HUEOFFSET:
-        return s->hueoffset;
-    case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
-        w = ((offset - FIMD_VIDWALPHA_START) >> 3);
-        i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
-        return s->window[w].alpha_val[i] &
-                (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
-    case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
-        return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
-    case FIMD_BLENDCON:
-        return s->blendcon;
-    case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
-        return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
-    case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
-        return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
-    case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
-        if (offset & 0x0004) {
-            break;
-        }
-        return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
-    case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
-        if (offset & 0x0004) {
-            break;
-        }
-        return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
-    case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
-        if (offset & 0x0004) {
-            break;
-        }
-        return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
-    case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
-        return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
-    case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
-        w = (offset - FIMD_PAL_MEM_START) >> 10;
-        i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
-        return s->window[w].palette[i];
-    case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
-        /* Palette aliases for win 0,1 */
-        w = (offset - FIMD_PALMEM_AL_START) >> 10;
-        i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
-        return s->window[w].palette[i];
-    }
-
-    DPRINT_ERROR("bad read offset 0x%08x\n", offset);
-    return 0xBAADBAAD;
-}
-
-static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
-    .read = exynos4210_fimd_read,
-    .write = exynos4210_fimd_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-        .unaligned = false
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int exynos4210_fimd_load(void *opaque, int version_id)
-{
-    Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
-    int w;
-
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-
-    for (w = 0; w < NUM_OF_WINDOWS; w++) {
-        exynos4210_fimd_update_win_bppmode(s, w);
-        fimd_update_get_alpha(s, w);
-        fimd_update_memory_section(s, w);
-    }
-
-    /* Redraw the whole screen */
-    exynos4210_update_resolution(s);
-    exynos4210_fimd_invalidate(s);
-    exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
-            FIMD_VIDCON0_ENVID_MASK);
-    return 0;
-}
-
-static const VMStateDescription exynos4210_fimd_window_vmstate = {
-    .name = "exynos4210.fimd_window",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
-        VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
-        VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
-        VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
-        VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
-        VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
-        VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
-        VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
-        VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
-        VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
-        VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
-        VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
-        VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
-        VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
-        VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
-        VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
-        VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
-        VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
-        VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
-        VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription exynos4210_fimd_vmstate = {
-    .name = "exynos4210.fimd",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .post_load = exynos4210_fimd_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
-        VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
-        VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
-        VMSTATE_UINT32(winchmap, Exynos4210fimdState),
-        VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
-        VMSTATE_UINT32(dithmode, Exynos4210fimdState),
-        VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
-        VMSTATE_UINT32(trigcon, Exynos4210fimdState),
-        VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
-        VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
-        VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
-        VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
-        VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
-        VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
-        VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
-        VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
-        VMSTATE_UINT32(blendcon, Exynos4210fimdState),
-        VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
-                exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int exynos4210_fimd_init(SysBusDevice *dev)
-{
-    Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev);
-
-    s->ifb = NULL;
-
-    sysbus_init_irq(dev, &s->irq[0]);
-    sysbus_init_irq(dev, &s->irq[1]);
-    sysbus_init_irq(dev, &s->irq[2]);
-
-    memory_region_init_io(&s->iomem, &exynos4210_fimd_mmio_ops, s,
-            "exynos4210.fimd", FIMD_REGS_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    s->console = graphic_console_init(exynos4210_fimd_update,
-                                  exynos4210_fimd_invalidate, NULL, NULL, s);
-
-    return 0;
-}
-
-static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    dc->vmsd = &exynos4210_fimd_vmstate;
-    dc->reset = exynos4210_fimd_reset;
-    k->init = exynos4210_fimd_init;
-}
-
-static const TypeInfo exynos4210_fimd_info = {
-    .name = "exynos4210.fimd",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210fimdState),
-    .class_init = exynos4210_fimd_class_init,
-};
-
-static void exynos4210_fimd_register_types(void)
-{
-    type_register_static(&exynos4210_fimd_info);
-}
-
-type_init(exynos4210_fimd_register_types)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
deleted file mode 100644 (file)
index 7326a98..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Framebuffer device helper routines
- *
- * Copyright (c) 2009 CodeSourcery
- * Written by Paul Brook <paul@codesourcery.com>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/* TODO:
-   - Do something similar for framebuffers with local ram
-   - Handle rotation here instead of hacking dest_pitch
-   - Use common pixel conversion routines instead of per-device drawfn
-   - Remove all DisplayState knowledge from devices.
- */
-
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/framebuffer.h"
-
-/* Render an image from a shared memory framebuffer.  */
-   
-void framebuffer_update_display(
-    DisplaySurface *ds,
-    MemoryRegion *address_space,
-    hwaddr base,
-    int cols, /* Width in pixels.  */
-    int rows, /* Height in pixels.  */
-    int src_width, /* Length of source line, in bytes.  */
-    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
-    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
-    int invalidate, /* nonzero to redraw the whole image.  */
-    drawfn fn,
-    void *opaque,
-    int *first_row, /* Input and output.  */
-    int *last_row /* Output only */)
-{
-    hwaddr src_len;
-    uint8_t *dest;
-    uint8_t *src;
-    uint8_t *src_base;
-    int first, last = 0;
-    int dirty;
-    int i;
-    ram_addr_t addr;
-    MemoryRegionSection mem_section;
-    MemoryRegion *mem;
-
-    i = *first_row;
-    *first_row = -1;
-    src_len = src_width * rows;
-
-    mem_section = memory_region_find(address_space, base, src_len);
-    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
-        return;
-    }
-    mem = mem_section.mr;
-    assert(mem);
-    assert(mem_section.offset_within_address_space == base);
-
-    memory_region_sync_dirty_bitmap(mem);
-    src_base = cpu_physical_memory_map(base, &src_len, 0);
-    /* If we can't map the framebuffer then bail.  We could try harder,
-       but it's not really worth it as dirty flag tracking will probably
-       already have failed above.  */
-    if (!src_base)
-        return;
-    if (src_len != src_width * rows) {
-        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
-        return;
-    }
-    src = src_base;
-    dest = surface_data(ds);
-    if (dest_col_pitch < 0)
-        dest -= dest_col_pitch * (cols - 1);
-    if (dest_row_pitch < 0) {
-        dest -= dest_row_pitch * (rows - 1);
-    }
-    first = -1;
-    addr = mem_section.offset_within_region;
-
-    addr += i * src_width;
-    src += i * src_width;
-    dest += i * dest_row_pitch;
-
-    for (; i < rows; i++) {
-        dirty = memory_region_get_dirty(mem, addr, src_width,
-                                             DIRTY_MEMORY_VGA);
-        if (dirty || invalidate) {
-            fn(opaque, dest, src, cols, dest_col_pitch);
-            if (first == -1)
-                first = i;
-            last = i;
-        }
-        addr += src_width;
-        src += src_width;
-        dest += dest_row_pitch;
-    }
-    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
-    if (first < 0) {
-        return;
-    }
-    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
-                              DIRTY_MEMORY_VGA);
-    *first_row = first;
-    *last_row = last;
-}
index 6df5fd9196baa4e0215849fb70f8ff65b18cb891..fe0123489c7b3fcf86516b2005ed4070231f8465 100644 (file)
@@ -7,7 +7,6 @@ obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
 obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
 obj-y += kvm/
-obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 obj-y += pc-testdev.o
 
 obj-y := $(addprefix ../,$(obj-y))
index e328ec8400cb2519a1636d9e7d9b085694ec4717..a894c466ca7f956d24cd14a7b7306c434dc72bc4 100644 (file)
@@ -9,10 +9,7 @@ obj-y += milkymist-memcard.o
 obj-y += milkymist-pfpu.o
 obj-y += milkymist-softusb.o
 obj-y += milkymist-sysctl.o
-obj-$(CONFIG_GLX) += milkymist-tmu2.o
 obj-y += milkymist-uart.o
-obj-y += milkymist-vgafb.o
-obj-y += framebuffer.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
deleted file mode 100644 (file)
index b723a04..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- *  QEMU model of the Milkymist texture mapping unit.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *  Copyright (c) 2010 Sebastien Bourdeauducq
- *                       <sebastien.bourdeauducq@lekernel.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/tmu2.pdf
- *
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-#include <X11/Xlib.h>
-#include <GL/gl.h>
-#include <GL/glx.h>
-
-enum {
-    R_CTL = 0,
-    R_HMESHLAST,
-    R_VMESHLAST,
-    R_BRIGHTNESS,
-    R_CHROMAKEY,
-    R_VERTICESADDR,
-    R_TEXFBUF,
-    R_TEXHRES,
-    R_TEXVRES,
-    R_TEXHMASK,
-    R_TEXVMASK,
-    R_DSTFBUF,
-    R_DSTHRES,
-    R_DSTVRES,
-    R_DSTHOFFSET,
-    R_DSTVOFFSET,
-    R_DSTSQUAREW,
-    R_DSTSQUAREH,
-    R_ALPHA,
-    R_MAX
-};
-
-enum {
-    CTL_START_BUSY  = (1<<0),
-    CTL_CHROMAKEY   = (1<<1),
-};
-
-enum {
-    MAX_BRIGHTNESS = 63,
-    MAX_ALPHA      = 63,
-};
-
-enum {
-    MESH_MAXSIZE = 128,
-};
-
-struct vertex {
-    int x;
-    int y;
-} QEMU_PACKED;
-
-struct MilkymistTMU2State {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint32_t regs[R_MAX];
-
-    Display *dpy;
-    GLXFBConfig glx_fb_config;
-    GLXContext glx_context;
-};
-typedef struct MilkymistTMU2State MilkymistTMU2State;
-
-static const int glx_fbconfig_attr[] = {
-    GLX_GREEN_SIZE, 5,
-    GLX_GREEN_SIZE, 6,
-    GLX_BLUE_SIZE, 5,
-    None
-};
-
-static int tmu2_glx_init(MilkymistTMU2State *s)
-{
-    GLXFBConfig *configs;
-    int nelements;
-
-    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
-    if (s->dpy == NULL) {
-        return 1;
-    }
-
-    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
-    if (configs == NULL) {
-        return 1;
-    }
-
-    s->glx_fb_config = *configs;
-    XFree(configs);
-
-    /* FIXME: call glXDestroyContext() */
-    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
-            GLX_RGBA_TYPE, NULL, 1);
-    if (s->glx_context == NULL) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
-        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
-{
-    int x, y;
-    int x0, y0, x1, y1;
-    int u0, v0, u1, v1, u2, v2, u3, v3;
-    double xscale = 1.0 / ((double)(64 * texhres));
-    double yscale = 1.0 / ((double)(64 * texvres));
-
-    glLoadIdentity();
-    glTranslatef(ho, vo, 0);
-    glEnable(GL_TEXTURE_2D);
-    glBegin(GL_QUADS);
-
-    for (y = 0; y < vmeshlast; y++) {
-        y0 = y * sh;
-        y1 = y0 + sh;
-        for (x = 0; x < hmeshlast; x++) {
-            x0 = x * sw;
-            x1 = x0 + sw;
-
-            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
-            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
-            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
-            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
-            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
-            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
-            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
-            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
-
-            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
-            glVertex3i(x0, y0, 0);
-            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
-            glVertex3i(x1, y0, 0);
-            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
-            glVertex3i(x1, y1, 0);
-            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
-            glVertex3i(x0, y1, 0);
-        }
-    }
-
-    glEnd();
-}
-
-static void tmu2_start(MilkymistTMU2State *s)
-{
-    int pbuffer_attrib[6] = {
-        GLX_PBUFFER_WIDTH,
-        0,
-        GLX_PBUFFER_HEIGHT,
-        0,
-        GLX_PRESERVED_CONTENTS,
-        True
-    };
-
-    GLXPbuffer pbuffer;
-    GLuint texture;
-    void *fb;
-    hwaddr fb_len;
-    void *mesh;
-    hwaddr mesh_len;
-    float m;
-
-    trace_milkymist_tmu2_start();
-
-    /* Create and set up a suitable OpenGL context */
-    pbuffer_attrib[1] = s->regs[R_DSTHRES];
-    pbuffer_attrib[3] = s->regs[R_DSTVRES];
-    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
-    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
-
-    /* Fixup endianness. TODO: would it work on BE hosts? */
-    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
-
-    /* Row alignment */
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
-    glPixelStorei(GL_PACK_ALIGNMENT, 2);
-
-    /* Read the QEMU source framebuffer into an OpenGL texture */
-    glGenTextures(1, &texture);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
-    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
-            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-
-    /* Set up texturing options */
-    /* WARNING:
-     * Many cases of TMU2 masking are not supported by OpenGL.
-     * We only implement the most common ones:
-     *  - full bilinear filtering vs. nearest texel
-     *  - texture clamping vs. texture wrapping
-     */
-    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    }
-    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    }
-    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    }
-
-    /* Translucency and decay */
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
-    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
-
-    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
-    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
-    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
-            GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-
-    /* Map the texture */
-    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
-    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
-    if (mesh == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    tmu2_gl_map((struct vertex *)mesh,
-        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
-        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
-        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
-        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
-    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
-
-    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
-    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
-    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
-            GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
-
-    /* Free OpenGL allocs */
-    glDeleteTextures(1, &texture);
-    glXMakeContextCurrent(s->dpy, None, None, NULL);
-    glXDestroyPbuffer(s->dpy, pbuffer);
-
-    s->regs[R_CTL] &= ~CTL_START_BUSY;
-
-    trace_milkymist_tmu2_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static uint64_t tmu2_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    MilkymistTMU2State *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_BRIGHTNESS:
-    case R_CHROMAKEY:
-    case R_VERTICESADDR:
-    case R_TEXFBUF:
-    case R_TEXHRES:
-    case R_TEXVRES:
-    case R_TEXHMASK:
-    case R_TEXVMASK:
-    case R_DSTFBUF:
-    case R_DSTHRES:
-    case R_DSTVRES:
-    case R_DSTHOFFSET:
-    case R_DSTVOFFSET:
-    case R_DSTSQUAREW:
-    case R_DSTSQUAREH:
-    case R_ALPHA:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_tmu2: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_tmu2_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void tmu2_check_registers(MilkymistTMU2State *s)
-{
-    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
-        error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
-    }
-
-    if (s->regs[R_ALPHA] > MAX_ALPHA) {
-        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
-    }
-
-    if (s->regs[R_VERTICESADDR] & 0x07) {
-        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
-                "aligned");
-    }
-
-    if (s->regs[R_TEXFBUF] & 0x01) {
-        error_report("milkymist_tmu2: texture buffer address has to be "
-                "16-bit aligned");
-    }
-}
-
-static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    MilkymistTMU2State *s = opaque;
-
-    trace_milkymist_tmu2_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-        s->regs[addr] = value;
-        if (value & CTL_START_BUSY) {
-            tmu2_start(s);
-        }
-        break;
-    case R_BRIGHTNESS:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_CHROMAKEY:
-    case R_VERTICESADDR:
-    case R_TEXFBUF:
-    case R_TEXHRES:
-    case R_TEXVRES:
-    case R_TEXHMASK:
-    case R_TEXVMASK:
-    case R_DSTFBUF:
-    case R_DSTHRES:
-    case R_DSTVRES:
-    case R_DSTHOFFSET:
-    case R_DSTVOFFSET:
-    case R_DSTSQUAREW:
-    case R_DSTSQUAREH:
-    case R_ALPHA:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_tmu2: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    tmu2_check_registers(s);
-}
-
-static const MemoryRegionOps tmu2_mmio_ops = {
-    .read = tmu2_read,
-    .write = tmu2_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_tmu2_reset(DeviceState *d)
-{
-    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-}
-
-static int milkymist_tmu2_init(SysBusDevice *dev)
-{
-    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
-
-    if (tmu2_glx_init(s)) {
-        return 1;
-    }
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
-            "milkymist-tmu2", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_tmu2 = {
-    .name = "milkymist-tmu2",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_tmu2_init;
-    dc->reset = milkymist_tmu2_reset;
-    dc->vmsd = &vmstate_milkymist_tmu2;
-}
-
-static const TypeInfo milkymist_tmu2_info = {
-    .name          = "milkymist-tmu2",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MilkymistTMU2State),
-    .class_init    = milkymist_tmu2_class_init,
-};
-
-static void milkymist_tmu2_register_types(void)
-{
-    type_register_static(&milkymist_tmu2_info);
-}
-
-type_init(milkymist_tmu2_register_types)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
deleted file mode 100644 (file)
index 98762ec..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-
-/*
- *  QEMU model of the Milkymist VGA framebuffer.
- *
- *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/vgafb.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "qemu/error-report.h"
-
-#define BITS 8
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 15
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 16
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 24
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 32
-#include "hw/milkymist-vgafb_template.h"
-
-enum {
-    R_CTRL = 0,
-    R_HRES,
-    R_HSYNC_START,
-    R_HSYNC_END,
-    R_HSCAN,
-    R_VRES,
-    R_VSYNC_START,
-    R_VSYNC_END,
-    R_VSCAN,
-    R_BASEADDRESS,
-    R_BASEADDRESS_ACT,
-    R_BURST_COUNT,
-    R_DDC,
-    R_SOURCE_CLOCK,
-    R_MAX
-};
-
-enum {
-    CTRL_RESET = (1<<0),
-};
-
-struct MilkymistVgafbState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    QemuConsole *con;
-
-    int invalidate;
-    uint32_t fb_offset;
-    uint32_t fb_mask;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct MilkymistVgafbState MilkymistVgafbState;
-
-static int vgafb_enabled(MilkymistVgafbState *s)
-{
-    return !(s->regs[R_CTRL] & CTRL_RESET);
-}
-
-static void vgafb_update_display(void *opaque)
-{
-    MilkymistVgafbState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int first = 0;
-    int last = 0;
-    drawfn fn;
-
-    if (!vgafb_enabled(s)) {
-        return;
-    }
-
-    int dest_width = s->regs[R_HRES];
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        return;
-    case 8:
-        fn = draw_line_8;
-        break;
-    case 15:
-        fn = draw_line_15;
-        dest_width *= 2;
-        break;
-    case 16:
-        fn = draw_line_16;
-        dest_width *= 2;
-        break;
-    case 24:
-        fn = draw_line_24;
-        dest_width *= 3;
-        break;
-    case 32:
-        fn = draw_line_32;
-        dest_width *= 4;
-        break;
-    default:
-        hw_error("milkymist_vgafb: bad color depth\n");
-        break;
-    }
-
-    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
-                               s->regs[R_BASEADDRESS] + s->fb_offset,
-                               s->regs[R_HRES],
-                               s->regs[R_VRES],
-                               s->regs[R_HRES] * 2,
-                               dest_width,
-                               0,
-                               s->invalidate,
-                               fn,
-                               NULL,
-                               &first, &last);
-
-    if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
-    }
-    s->invalidate = 0;
-}
-
-static void vgafb_invalidate_display(void *opaque)
-{
-    MilkymistVgafbState *s = opaque;
-    s->invalidate = 1;
-}
-
-static void vgafb_resize(MilkymistVgafbState *s)
-{
-    if (!vgafb_enabled(s)) {
-        return;
-    }
-
-    qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
-    s->invalidate = 1;
-}
-
-static uint64_t vgafb_read(void *opaque, hwaddr addr,
-                           unsigned size)
-{
-    MilkymistVgafbState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-    case R_HRES:
-    case R_HSYNC_START:
-    case R_HSYNC_END:
-    case R_HSCAN:
-    case R_VRES:
-    case R_VSYNC_START:
-    case R_VSYNC_END:
-    case R_VSCAN:
-    case R_BASEADDRESS:
-    case R_BURST_COUNT:
-    case R_DDC:
-    case R_SOURCE_CLOCK:
-        r = s->regs[addr];
-    break;
-    case R_BASEADDRESS_ACT:
-        r = s->regs[R_BASEADDRESS];
-    break;
-
-    default:
-        error_report("milkymist_vgafb: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_vgafb_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
-                        unsigned size)
-{
-    MilkymistVgafbState *s = opaque;
-
-    trace_milkymist_vgafb_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        s->regs[addr] = value;
-        vgafb_resize(s);
-        break;
-    case R_HSYNC_START:
-    case R_HSYNC_END:
-    case R_HSCAN:
-    case R_VSYNC_START:
-    case R_VSYNC_END:
-    case R_VSCAN:
-    case R_BURST_COUNT:
-    case R_DDC:
-    case R_SOURCE_CLOCK:
-        s->regs[addr] = value;
-        break;
-    case R_BASEADDRESS:
-        if (value & 0x1f) {
-            error_report("milkymist_vgafb: framebuffer base address have to "
-                     "be 32 byte aligned");
-            break;
-        }
-        s->regs[addr] = value & s->fb_mask;
-        s->invalidate = 1;
-        break;
-    case R_HRES:
-    case R_VRES:
-        s->regs[addr] = value;
-        vgafb_resize(s);
-        break;
-    case R_BASEADDRESS_ACT:
-        error_report("milkymist_vgafb: write to read-only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-
-    default:
-        error_report("milkymist_vgafb: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps vgafb_mmio_ops = {
-    .read = vgafb_read,
-    .write = vgafb_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_vgafb_reset(DeviceState *d)
-{
-    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    /* defaults */
-    s->regs[R_CTRL] = CTRL_RESET;
-    s->regs[R_HRES] = 640;
-    s->regs[R_VRES] = 480;
-    s->regs[R_BASEADDRESS] = 0;
-}
-
-static int milkymist_vgafb_init(SysBusDevice *dev)
-{
-    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
-            "milkymist-vgafb", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    s->con = graphic_console_init(vgafb_update_display,
-                                  vgafb_invalidate_display,
-                                  NULL, NULL, s);
-
-    return 0;
-}
-
-static int vgafb_post_load(void *opaque, int version_id)
-{
-    vgafb_invalidate_display(opaque);
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_vgafb = {
-    .name = "milkymist-vgafb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = vgafb_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_vgafb_properties[] = {
-    DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
-    DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_vgafb_init;
-    dc->reset = milkymist_vgafb_reset;
-    dc->vmsd = &vmstate_milkymist_vgafb;
-    dc->props = milkymist_vgafb_properties;
-}
-
-static const TypeInfo milkymist_vgafb_info = {
-    .name          = "milkymist-vgafb",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MilkymistVgafbState),
-    .class_init    = milkymist_vgafb_class_init,
-};
-
-static void milkymist_vgafb_register_types(void)
-{
-    type_register_static(&milkymist_vgafb_info);
-}
-
-type_init(milkymist_vgafb_register_types)
index 1d33ee8b50878db6ae61c7a5d81fd4583624c45b..e0036e16cf7be105e99c180194f6365bacc15a43 100644 (file)
@@ -61,7 +61,7 @@ static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
     uint8_t r, g, b;
 
     while (width--) {
-        rgb565 = lduw_raw(s);
+        memcpy(&rgb565, s, sizeof(rgb565));
         r = ((rgb565 >> 11) & 0x1f) << 3;
         g = ((rgb565 >>  5) & 0x3f) << 2;
         b = ((rgb565 >>  0) & 0x1f) << 3;
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
deleted file mode 100644 (file)
index ea3afce..0000000
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
- * OMAP2 Display Subsystem.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-
-struct omap_dss_s {
-    qemu_irq irq;
-    qemu_irq drq;
-    DisplayState *state;
-    MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
-
-    int autoidle;
-    int control;
-    int enable;
-
-    struct omap_dss_panel_s {
-        int enable;
-        int nx;
-        int ny;
-
-        int x;
-        int y;
-    } dig, lcd;
-
-    struct {
-        uint32_t idlemode;
-        uint32_t irqst;
-        uint32_t irqen;
-        uint32_t control;
-        uint32_t config;
-        uint32_t capable;
-        uint32_t timing[4];
-        int line;
-        uint32_t bg[2];
-        uint32_t trans[2];
-
-        struct omap_dss_plane_s {
-            int enable;
-            int bpp;
-            int posx;
-            int posy;
-            int nx;
-            int ny;
-
-            hwaddr addr[3];
-
-            uint32_t attr;
-            uint32_t tresh;
-            int rowinc;
-            int colinc;
-            int wininc;
-        } l[3];
-
-        int invalidate;
-        uint16_t palette[256];
-    } dispc;
-
-    struct {
-        int idlemode;
-        uint32_t control;
-        int enable;
-        int pixels;
-        int busy;
-        int skiplines;
-        uint16_t rxbuf;
-        uint32_t config[2];
-        uint32_t time[4];
-        uint32_t data[6];
-        uint16_t vsync;
-        uint16_t hsync;
-        struct rfbi_chip_s *chip[2];
-    } rfbi;
-};
-
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
-{
-    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
-}
-
-static void omap_rfbi_reset(struct omap_dss_s *s)
-{
-    s->rfbi.idlemode = 0;
-    s->rfbi.control = 2;
-    s->rfbi.enable = 0;
-    s->rfbi.pixels = 0;
-    s->rfbi.skiplines = 0;
-    s->rfbi.busy = 0;
-    s->rfbi.config[0] = 0x00310000;
-    s->rfbi.config[1] = 0x00310000;
-    s->rfbi.time[0] = 0;
-    s->rfbi.time[1] = 0;
-    s->rfbi.time[2] = 0;
-    s->rfbi.time[3] = 0;
-    s->rfbi.data[0] = 0;
-    s->rfbi.data[1] = 0;
-    s->rfbi.data[2] = 0;
-    s->rfbi.data[3] = 0;
-    s->rfbi.data[4] = 0;
-    s->rfbi.data[5] = 0;
-    s->rfbi.vsync = 0;
-    s->rfbi.hsync = 0;
-}
-
-void omap_dss_reset(struct omap_dss_s *s)
-{
-    s->autoidle = 0;
-    s->control = 0;
-    s->enable = 0;
-
-    s->dig.enable = 0;
-    s->dig.nx = 1;
-    s->dig.ny = 1;
-
-    s->lcd.enable = 0;
-    s->lcd.nx = 1;
-    s->lcd.ny = 1;
-
-    s->dispc.idlemode = 0;
-    s->dispc.irqst = 0;
-    s->dispc.irqen = 0;
-    s->dispc.control = 0;
-    s->dispc.config = 0;
-    s->dispc.capable = 0x161;
-    s->dispc.timing[0] = 0;
-    s->dispc.timing[1] = 0;
-    s->dispc.timing[2] = 0;
-    s->dispc.timing[3] = 0;
-    s->dispc.line = 0;
-    s->dispc.bg[0] = 0;
-    s->dispc.bg[1] = 0;
-    s->dispc.trans[0] = 0;
-    s->dispc.trans[1] = 0;
-
-    s->dispc.l[0].enable = 0;
-    s->dispc.l[0].bpp = 0;
-    s->dispc.l[0].addr[0] = 0;
-    s->dispc.l[0].addr[1] = 0;
-    s->dispc.l[0].addr[2] = 0;
-    s->dispc.l[0].posx = 0;
-    s->dispc.l[0].posy = 0;
-    s->dispc.l[0].nx = 1;
-    s->dispc.l[0].ny = 1;
-    s->dispc.l[0].attr = 0;
-    s->dispc.l[0].tresh = 0;
-    s->dispc.l[0].rowinc = 1;
-    s->dispc.l[0].colinc = 1;
-    s->dispc.l[0].wininc = 0;
-
-    omap_rfbi_reset(s);
-    omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_diss_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* DSS_REVISIONNUMBER */
-        return 0x20;
-
-    case 0x10: /* DSS_SYSCONFIG */
-        return s->autoidle;
-
-    case 0x14: /* DSS_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x40: /* DSS_CONTROL */
-        return s->control;
-
-    case 0x50: /* DSS_PSA_LCD_REG_1 */
-    case 0x54: /* DSS_PSA_LCD_REG_2 */
-    case 0x58: /* DSS_PSA_VIDEO_REG */
-        /* TODO: fake some values when appropriate s->control bits are set */
-        return 0;
-
-    case 0x5c: /* DSS_STATUS */
-        return 1 + (s->control & 1);
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_diss_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* DSS_REVISIONNUMBER */
-    case 0x14: /* DSS_SYSSTATUS */
-    case 0x50: /* DSS_PSA_LCD_REG_1 */
-    case 0x54: /* DSS_PSA_LCD_REG_2 */
-    case 0x58: /* DSS_PSA_VIDEO_REG */
-    case 0x5c: /* DSS_STATUS */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* DSS_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_dss_reset(s);
-        s->autoidle = value & 1;
-        break;
-
-    case 0x40: /* DSS_CONTROL */
-        s->control = value & 0x3dd;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_diss_ops = {
-    .read = omap_diss_read,
-    .write = omap_diss_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_disc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x000:        /* DISPC_REVISION */
-        return 0x20;
-
-    case 0x010:        /* DISPC_SYSCONFIG */
-        return s->dispc.idlemode;
-
-    case 0x014:        /* DISPC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x018:        /* DISPC_IRQSTATUS */
-        return s->dispc.irqst;
-
-    case 0x01c:        /* DISPC_IRQENABLE */
-        return s->dispc.irqen;
-
-    case 0x040:        /* DISPC_CONTROL */
-        return s->dispc.control;
-
-    case 0x044:        /* DISPC_CONFIG */
-        return s->dispc.config;
-
-    case 0x048:        /* DISPC_CAPABLE */
-        return s->dispc.capable;
-
-    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
-        return s->dispc.bg[0];
-    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
-        return s->dispc.bg[1];
-    case 0x054:        /* DISPC_TRANS_COLOR0 */
-        return s->dispc.trans[0];
-    case 0x058:        /* DISPC_TRANS_COLOR1 */
-        return s->dispc.trans[1];
-
-    case 0x05c:        /* DISPC_LINE_STATUS */
-        return 0x7ff;
-    case 0x060:        /* DISPC_LINE_NUMBER */
-        return s->dispc.line;
-
-    case 0x064:        /* DISPC_TIMING_H */
-        return s->dispc.timing[0];
-    case 0x068:        /* DISPC_TIMING_V */
-        return s->dispc.timing[1];
-    case 0x06c:        /* DISPC_POL_FREQ */
-        return s->dispc.timing[2];
-    case 0x070:        /* DISPC_DIVISOR */
-        return s->dispc.timing[3];
-
-    case 0x078:        /* DISPC_SIZE_DIG */
-        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
-    case 0x07c:        /* DISPC_SIZE_LCD */
-        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
-    case 0x080:        /* DISPC_GFX_BA0 */
-        return s->dispc.l[0].addr[0];
-    case 0x084:        /* DISPC_GFX_BA1 */
-        return s->dispc.l[0].addr[1];
-    case 0x088:        /* DISPC_GFX_POSITION */
-        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
-    case 0x08c:        /* DISPC_GFX_SIZE */
-        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
-    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        return s->dispc.l[0].attr;
-    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        return s->dispc.l[0].tresh;
-    case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
-        return 256;
-    case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        return s->dispc.l[0].rowinc;
-    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        return s->dispc.l[0].colinc;
-    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
-        return s->dispc.l[0].wininc;
-    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
-        return s->dispc.l[0].addr[2];
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
-    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
-    case 0x170:        /* DISPC_VID2_FIR */
-    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
-    case 0x178:        /* DISPC_VID2_ACCU0 */
-    case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
-    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
-    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
-    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_disc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x010:        /* DISPC_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_dss_reset(s);
-        s->dispc.idlemode = value & 0x301b;
-        break;
-
-    case 0x018:        /* DISPC_IRQSTATUS */
-        s->dispc.irqst &= ~value;
-        omap_dispc_interrupt_update(s);
-        break;
-
-    case 0x01c:        /* DISPC_IRQENABLE */
-        s->dispc.irqen = value & 0xffff;
-        omap_dispc_interrupt_update(s);
-        break;
-
-    case 0x040:        /* DISPC_CONTROL */
-        s->dispc.control = value & 0x07ff9fff;
-        s->dig.enable = (value >> 1) & 1;
-        s->lcd.enable = (value >> 0) & 1;
-        if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
-            if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
-                fprintf(stderr, "%s: Overlay Optimization when no overlay "
-                        "region effectively exists leads to "
-                        "unpredictable behaviour!\n", __func__);
-            }
-        if (value & (1 << 6)) {                                /* GODIGITAL */
-            /* XXX: Shadowed fields are:
-             * s->dispc.config
-             * s->dispc.capable
-             * s->dispc.bg[0]
-             * s->dispc.bg[1]
-             * s->dispc.trans[0]
-             * s->dispc.trans[1]
-             * s->dispc.line
-             * s->dispc.timing[0]
-             * s->dispc.timing[1]
-             * s->dispc.timing[2]
-             * s->dispc.timing[3]
-             * s->lcd.nx
-             * s->lcd.ny
-             * s->dig.nx
-             * s->dig.ny
-             * s->dispc.l[0].addr[0]
-             * s->dispc.l[0].addr[1]
-             * s->dispc.l[0].addr[2]
-             * s->dispc.l[0].posx
-             * s->dispc.l[0].posy
-             * s->dispc.l[0].nx
-             * s->dispc.l[0].ny
-             * s->dispc.l[0].tresh
-             * s->dispc.l[0].rowinc
-             * s->dispc.l[0].colinc
-             * s->dispc.l[0].wininc
-             * All they need to be loaded here from their shadow registers.
-             */
-        }
-        if (value & (1 << 5)) {                                /* GOLCD */
-             /* XXX: Likewise for LCD here.  */
-        }
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x044:        /* DISPC_CONFIG */
-        s->dispc.config = value & 0x3fff;
-        /* XXX:
-         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
-         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
-         */
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x048:        /* DISPC_CAPABLE */
-        s->dispc.capable = value & 0x3ff;
-        break;
-
-    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
-        s->dispc.bg[0] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
-        s->dispc.bg[1] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x054:        /* DISPC_TRANS_COLOR0 */
-        s->dispc.trans[0] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x058:        /* DISPC_TRANS_COLOR1 */
-        s->dispc.trans[1] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x060:        /* DISPC_LINE_NUMBER */
-        s->dispc.line = value & 0x7ff;
-        break;
-
-    case 0x064:        /* DISPC_TIMING_H */
-        s->dispc.timing[0] = value & 0x0ff0ff3f;
-        break;
-    case 0x068:        /* DISPC_TIMING_V */
-        s->dispc.timing[1] = value & 0x0ff0ff3f;
-        break;
-    case 0x06c:        /* DISPC_POL_FREQ */
-        s->dispc.timing[2] = value & 0x0003ffff;
-        break;
-    case 0x070:        /* DISPC_DIVISOR */
-        s->dispc.timing[3] = value & 0x00ff00ff;
-        break;
-
-    case 0x078:        /* DISPC_SIZE_DIG */
-        s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
-        s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x07c:        /* DISPC_SIZE_LCD */
-        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
-        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x080:        /* DISPC_GFX_BA0 */
-        s->dispc.l[0].addr[0] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x084:        /* DISPC_GFX_BA1 */
-        s->dispc.l[0].addr[1] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x088:        /* DISPC_GFX_POSITION */
-        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
-        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x08c:        /* DISPC_GFX_SIZE */
-        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
-        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        s->dispc.l[0].attr = value & 0x7ff;
-        if (value & (3 << 9))
-            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
-                            __FUNCTION__);
-        s->dispc.l[0].enable = value & 1;
-        s->dispc.l[0].bpp = (value >> 1) & 0xf;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        s->dispc.l[0].tresh = value & 0x01ff01ff;
-        break;
-    case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        s->dispc.l[0].rowinc = value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        s->dispc.l[0].colinc = value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
-        s->dispc.l[0].wininc = value;
-        break;
-    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
-        s->dispc.l[0].addr[2] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
-    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
-    case 0x170:        /* DISPC_VID2_FIR */
-    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
-    case 0x178:        /* DISPC_VID2_ACCU0 */
-    case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
-    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
-    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
-    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_disc_ops = {
-    .read = omap_disc_read,
-    .write = omap_disc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
-    if (!s->rfbi.busy)
-        return;
-
-    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
-
-    s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
-    void *data;
-    hwaddr len;
-    hwaddr data_addr;
-    int pitch;
-    static void *bounce_buffer;
-    static hwaddr bounce_len;
-
-    if (!s->rfbi.enable || s->rfbi.busy)
-        return;
-
-    if (s->rfbi.control & (1 << 1)) {                          /* BYPASS */
-        /* TODO: in non-Bypass mode we probably need to just assert the
-         * DRQ and wait for DMA to write the pixels.  */
-        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
-        return;
-    }
-
-    if (!(s->dispc.control & (1 << 11)))                       /* RFBIMODE */
-        return;
-    /* TODO: check that LCD output is enabled in DISPC.  */
-
-    s->rfbi.busy = 1;
-
-    len = s->rfbi.pixels * 2;
-
-    data_addr = s->dispc.l[0].addr[0];
-    data = cpu_physical_memory_map(data_addr, &len, 0);
-    if (data && len != s->rfbi.pixels * 2) {
-        cpu_physical_memory_unmap(data, len, 0, 0);
-        data = NULL;
-        len = s->rfbi.pixels * 2;
-    }
-    if (!data) {
-        if (len > bounce_len) {
-            bounce_buffer = g_realloc(bounce_buffer, len);
-        }
-        data = bounce_buffer;
-        cpu_physical_memory_read(data_addr, data, len);
-    }
-
-    /* TODO bpp */
-    s->rfbi.pixels = 0;
-
-    /* TODO: negative values */
-    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
-    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
-    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
-    if (data != bounce_buffer) {
-        cpu_physical_memory_unmap(data, len, 0, len);
-    }
-
-    omap_rfbi_transfer_stop(s);
-
-    /* TODO */
-    s->dispc.irqst |= 1;                                       /* FRAMEDONE */
-    omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* RFBI_REVISION */
-        return 0x10;
-
-    case 0x10: /* RFBI_SYSCONFIG */
-        return s->rfbi.idlemode;
-
-    case 0x14: /* RFBI_SYSSTATUS */
-        return 1 | (s->rfbi.busy << 8);                                /* RESETDONE */
-
-    case 0x40: /* RFBI_CONTROL */
-        return s->rfbi.control;
-
-    case 0x44: /* RFBI_PIXELCNT */
-        return s->rfbi.pixels;
-
-    case 0x48: /* RFBI_LINE_NUMBER */
-        return s->rfbi.skiplines;
-
-    case 0x58: /* RFBI_READ */
-    case 0x5c: /* RFBI_STATUS */
-        return s->rfbi.rxbuf;
-
-    case 0x60: /* RFBI_CONFIG0 */
-        return s->rfbi.config[0];
-    case 0x64: /* RFBI_ONOFF_TIME0 */
-        return s->rfbi.time[0];
-    case 0x68: /* RFBI_CYCLE_TIME0 */
-        return s->rfbi.time[1];
-    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
-        return s->rfbi.data[0];
-    case 0x70: /* RFBI_DATA_CYCLE2_0 */
-        return s->rfbi.data[1];
-    case 0x74: /* RFBI_DATA_CYCLE3_0 */
-        return s->rfbi.data[2];
-
-    case 0x78: /* RFBI_CONFIG1 */
-        return s->rfbi.config[1];
-    case 0x7c: /* RFBI_ONOFF_TIME1 */
-        return s->rfbi.time[2];
-    case 0x80: /* RFBI_CYCLE_TIME1 */
-        return s->rfbi.time[3];
-    case 0x84: /* RFBI_DATA_CYCLE1_1 */
-        return s->rfbi.data[3];
-    case 0x88: /* RFBI_DATA_CYCLE2_1 */
-        return s->rfbi.data[4];
-    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
-        return s->rfbi.data[5];
-
-    case 0x90: /* RFBI_VSYNC_WIDTH */
-        return s->rfbi.vsync;
-    case 0x94: /* RFBI_HSYNC_WIDTH */
-        return s->rfbi.hsync;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_rfbi_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x10: /* RFBI_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_rfbi_reset(s);
-        s->rfbi.idlemode = value & 0x19;
-        break;
-
-    case 0x40: /* RFBI_CONTROL */
-        s->rfbi.control = value & 0xf;
-        s->rfbi.enable = value & 1;
-        if (value & (1 << 4) &&                                        /* ITE */
-                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
-            omap_rfbi_transfer_start(s);
-        break;
-
-    case 0x44: /* RFBI_PIXELCNT */
-        s->rfbi.pixels = value;
-        break;
-
-    case 0x48: /* RFBI_LINE_NUMBER */
-        s->rfbi.skiplines = value & 0x7ff;
-        break;
-
-    case 0x4c: /* RFBI_CMD */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
-        break;
-    case 0x50: /* RFBI_PARAM */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
-        break;
-    case 0x54: /* RFBI_DATA */
-        /* TODO: take into account the format set up in s->rfbi.config[?] and
-         * s->rfbi.data[?], but special-case the most usual scenario so that
-         * speed doesn't suffer.  */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
-        }
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
-        }
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-    case 0x58: /* RFBI_READ */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
-        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-
-    case 0x5c: /* RFBI_STATUS */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
-        else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-
-    case 0x60: /* RFBI_CONFIG0 */
-        s->rfbi.config[0] = value & 0x003f1fff;
-        break;
-
-    case 0x64: /* RFBI_ONOFF_TIME0 */
-        s->rfbi.time[0] = value & 0x3fffffff;
-        break;
-    case 0x68: /* RFBI_CYCLE_TIME0 */
-        s->rfbi.time[1] = value & 0x0fffffff;
-        break;
-    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
-        s->rfbi.data[0] = value & 0x0f1f0f1f;
-        break;
-    case 0x70: /* RFBI_DATA_CYCLE2_0 */
-        s->rfbi.data[1] = value & 0x0f1f0f1f;
-        break;
-    case 0x74: /* RFBI_DATA_CYCLE3_0 */
-        s->rfbi.data[2] = value & 0x0f1f0f1f;
-        break;
-    case 0x78: /* RFBI_CONFIG1 */
-        s->rfbi.config[1] = value & 0x003f1fff;
-        break;
-
-    case 0x7c: /* RFBI_ONOFF_TIME1 */
-        s->rfbi.time[2] = value & 0x3fffffff;
-        break;
-    case 0x80: /* RFBI_CYCLE_TIME1 */
-        s->rfbi.time[3] = value & 0x0fffffff;
-        break;
-    case 0x84: /* RFBI_DATA_CYCLE1_1 */
-        s->rfbi.data[3] = value & 0x0f1f0f1f;
-        break;
-    case 0x88: /* RFBI_DATA_CYCLE2_1 */
-        s->rfbi.data[4] = value & 0x0f1f0f1f;
-        break;
-    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
-        s->rfbi.data[5] = value & 0x0f1f0f1f;
-        break;
-
-    case 0x90: /* RFBI_VSYNC_WIDTH */
-        s->rfbi.vsync = value & 0xffff;
-        break;
-    case 0x94: /* RFBI_HSYNC_WIDTH */
-        s->rfbi.hsync = value & 0xffff;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_rfbi_ops = {
-    .read = omap_rfbi_read,
-    .write = omap_rfbi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_venc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* REV_ID */
-    case 0x04: /* STATUS */
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_venc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, size);
-    }
-
-    switch (addr) {
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_venc_ops = {
-    .read = omap_venc_read,
-    .write = omap_venc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_im3_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x0a8:        /* SBIMERRLOGA */
-    case 0x0b0:        /* SBIMERRLOG */
-    case 0x190:        /* SBIMSTATE */
-    case 0x198:        /* SBTMSTATE_L */
-    case 0x19c:        /* SBTMSTATE_H */
-    case 0x1a8:        /* SBIMCONFIG_L */
-    case 0x1ac:        /* SBIMCONFIG_H */
-    case 0x1f8:        /* SBID_L */
-    case 0x1fc:        /* SBID_H */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_im3_write(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x0b0:        /* SBIMERRLOG */
-    case 0x190:        /* SBIMSTATE */
-    case 0x198:        /* SBTMSTATE_L */
-    case 0x19c:        /* SBTMSTATE_H */
-    case 0x1a8:        /* SBIMCONFIG_L */
-    case 0x1ac:        /* SBIMCONFIG_H */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_im3_ops = {
-    .read = omap_im3_read,
-    .write = omap_im3_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
-                MemoryRegion *sysmem,
-                hwaddr l3_base,
-                qemu_irq irq, qemu_irq drq,
-                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
-                omap_clk ick1, omap_clk ick2)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *)
-            g_malloc0(sizeof(struct omap_dss_s));
-
-    s->irq = irq;
-    s->drq = drq;
-    omap_dss_reset(s);
-
-    memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
-                          omap_l4_region_size(ta, 0));
-    memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
-                          omap_l4_region_size(ta, 1));
-    memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
-                          omap_l4_region_size(ta, 2));
-    memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
-                          omap_l4_region_size(ta, 3));
-    memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
-                          "omap.im3", 0x1000);
-
-    omap_l4_attach(ta, 0, &s->iomem_diss1);
-    omap_l4_attach(ta, 1, &s->iomem_disc1);
-    omap_l4_attach(ta, 2, &s->iomem_rfbi1);
-    omap_l4_attach(ta, 3, &s->iomem_venc1);
-    memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
-    s->state = graphic_console_init(omap_update_display,
-                                    omap_invalidate_display, omap_screen_dump, s);
-#endif
-
-    return s;
-}
-
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
-{
-    if (cs < 0 || cs > 1)
-        hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
-    s->rfbi.chip[cs] = chip;
-}
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
deleted file mode 100644 (file)
index 4048cc1..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * OMAP LCD controller.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "hw/framebuffer.h"
-#include "ui/pixel_ops.h"
-
-struct omap_lcd_panel_s {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    QemuConsole *con;
-
-    int plm;
-    int tft;
-    int mono;
-    int enable;
-    int width;
-    int height;
-    int interrupts;
-    uint32_t timing[3];
-    uint32_t subpanel;
-    uint32_t ctrl;
-
-    struct omap_dma_lcd_channel_s *dma;
-    uint16_t palette[256];
-    int palette_done;
-    int frame_done;
-    int invalidate;
-    int sync_error;
-};
-
-static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
-{
-    if (s->frame_done && (s->interrupts & 1)) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    if (s->palette_done && (s->interrupts & 2)) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    if (s->sync_error) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    qemu_irq_lower(s->irq);
-}
-
-#define draw_line_func drawfn
-
-#define DEPTH 8
-#include "hw/omap_lcd_template.h"
-#define DEPTH 15
-#include "hw/omap_lcd_template.h"
-#define DEPTH 16
-#include "hw/omap_lcd_template.h"
-#define DEPTH 32
-#include "hw/omap_lcd_template.h"
-
-static draw_line_func draw_line_table2[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line2_8,
-    [15]       = draw_line2_15,
-    [16]       = draw_line2_16,
-    [32]       = draw_line2_32,
-}, draw_line_table4[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line4_8,
-    [15]       = draw_line4_15,
-    [16]       = draw_line4_16,
-    [32]       = draw_line4_32,
-}, draw_line_table8[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line8_8,
-    [15]       = draw_line8_15,
-    [16]       = draw_line8_16,
-    [32]       = draw_line8_32,
-}, draw_line_table12[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line12_8,
-    [15]       = draw_line12_15,
-    [16]       = draw_line12_16,
-    [32]       = draw_line12_32,
-}, draw_line_table16[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line16_8,
-    [15]       = draw_line16_15,
-    [16]       = draw_line16_16,
-    [32]       = draw_line16_32,
-};
-
-static void omap_update_display(void *opaque)
-{
-    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
-    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
-    draw_line_func draw_line;
-    int size, height, first, last;
-    int width, linesize, step, bpp, frame_offset;
-    hwaddr frame_base;
-
-    if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable ||
-        !surface_bits_per_pixel(surface)) {
-        return;
-    }
-
-    frame_offset = 0;
-    if (omap_lcd->plm != 2) {
-        cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
-                                  omap_lcd->dma->current_frame],
-                                 (void *)omap_lcd->palette, 0x200);
-        switch (omap_lcd->palette[0] >> 12 & 7) {
-        case 3 ... 7:
-            frame_offset += 0x200;
-            break;
-        default:
-            frame_offset += 0x20;
-        }
-    }
-
-    /* Colour depth */
-    switch ((omap_lcd->palette[0] >> 12) & 7) {
-    case 1:
-        draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
-        bpp = 2;
-        break;
-
-    case 2:
-        draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
-        bpp = 4;
-        break;
-
-    case 3:
-        draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
-        bpp = 8;
-        break;
-
-    case 4 ... 7:
-        if (!omap_lcd->tft)
-            draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
-        else
-            draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
-        bpp = 16;
-        break;
-
-    default:
-        /* Unsupported at the moment.  */
-        return;
-    }
-
-    /* Resolution */
-    width = omap_lcd->width;
-    if (width != surface_width(surface) ||
-        omap_lcd->height != surface_height(surface)) {
-        qemu_console_resize(omap_lcd->con,
-                            omap_lcd->width, omap_lcd->height);
-        surface = qemu_console_surface(omap_lcd->con);
-        omap_lcd->invalidate = 1;
-    }
-
-    if (omap_lcd->dma->current_frame == 0)
-        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
-    else
-        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
-
-    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
-        omap_lcd->sync_error = 1;
-        omap_lcd_interrupts(omap_lcd);
-        omap_lcd->enable = 0;
-        return;
-    }
-
-    /* Content */
-    frame_base = omap_lcd->dma->phys_framebuffer[
-            omap_lcd->dma->current_frame] + frame_offset;
-    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
-    if (omap_lcd->dma->interrupts & 1)
-        qemu_irq_raise(omap_lcd->dma->irq);
-    if (omap_lcd->dma->dual)
-        omap_lcd->dma->current_frame ^= 1;
-
-    if (!surface_bits_per_pixel(surface)) {
-        return;
-    }
-
-    first = 0;
-    height = omap_lcd->height;
-    if (omap_lcd->subpanel & (1 << 31)) {
-        if (omap_lcd->subpanel & (1 << 29))
-            first = (omap_lcd->subpanel >> 16) & 0x3ff;
-        else
-            height = (omap_lcd->subpanel >> 16) & 0x3ff;
-        /* TODO: fill the rest of the panel with DPD */
-    }
-
-    step = width * bpp >> 3;
-    linesize = surface_stride(surface);
-    framebuffer_update_display(surface, omap_lcd->sysmem,
-                               frame_base, width, height,
-                               step, linesize, 0,
-                               omap_lcd->invalidate,
-                               draw_line, omap_lcd->palette,
-                               &first, &last);
-    if (first >= 0) {
-        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
-    }
-    omap_lcd->invalidate = 0;
-}
-
-static void omap_ppm_save(const char *filename, uint8_t *data,
-                    int w, int h, int linesize, Error **errp)
-{
-    FILE *f;
-    uint8_t *d, *d1;
-    unsigned int v;
-    int ret, y, x, bpp;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = data;
-    bpp = linesize / w;
-    for (y = 0; y < h; y ++) {
-        d = d1;
-        for (x = 0; x < w; x ++) {
-            v = *(uint32_t *) d;
-            switch (bpp) {
-            case 2:
-                ret = fputc((v >> 8) & 0xf8, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v >> 3) & 0xfc, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v << 3) & 0xf8, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                break;
-            case 3:
-            case 4:
-            default:
-                ret = fputc((v >> 16) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v >> 8) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                break;
-            }
-            d += bpp;
-        }
-        d1 += linesize;
-    }
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
-                             Error **errp)
-{
-    struct omap_lcd_panel_s *omap_lcd = opaque;
-    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
-
-    omap_update_display(opaque);
-    if (omap_lcd && surface_data(surface))
-        omap_ppm_save(filename, surface_data(surface),
-                    omap_lcd->width, omap_lcd->height,
-                    surface_stride(surface), errp);
-}
-
-static void omap_invalidate_display(void *opaque) {
-    struct omap_lcd_panel_s *omap_lcd = opaque;
-    omap_lcd->invalidate = 1;
-}
-
-static void omap_lcd_update(struct omap_lcd_panel_s *s) {
-    if (!s->enable) {
-        s->dma->current_frame = -1;
-        s->sync_error = 0;
-        if (s->plm != 1)
-            s->frame_done = 1;
-        omap_lcd_interrupts(s);
-        return;
-    }
-
-    if (s->dma->current_frame == -1) {
-        s->frame_done = 0;
-        s->palette_done = 0;
-        s->dma->current_frame = 0;
-    }
-
-    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
-                            s->dma->src_f1_top) ||
-                    !s->dma->mpu->port[
-                    s->dma->src].addr_valid(s->dma->mpu,
-                            s->dma->src_f1_bottom) ||
-                    (s->dma->dual &&
-                     (!s->dma->mpu->port[
-                      s->dma->src].addr_valid(s->dma->mpu,
-                              s->dma->src_f2_top) ||
-                      !s->dma->mpu->port[
-                      s->dma->src].addr_valid(s->dma->mpu,
-                              s->dma->src_f2_bottom)))) {
-        s->dma->condition |= 1 << 2;
-        if (s->dma->interrupts & (1 << 1))
-            qemu_irq_raise(s->dma->irq);
-        s->enable = 0;
-        return;
-    }
-
-    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
-    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
-
-    if (s->plm != 2 && !s->palette_done) {
-        cpu_physical_memory_read(
-            s->dma->phys_framebuffer[s->dma->current_frame],
-            (void *)s->palette, 0x200);
-        s->palette_done = 1;
-        omap_lcd_interrupts(s);
-    }
-}
-
-static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* LCD_CONTROL */
-        return (s->tft << 23) | (s->plm << 20) |
-                (s->tft << 7) | (s->interrupts << 3) |
-                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
-
-    case 0x04: /* LCD_TIMING0 */
-        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
-
-    case 0x08: /* LCD_TIMING1 */
-        return (s->timing[1] << 10) | (s->height - 1);
-
-    case 0x0c: /* LCD_TIMING2 */
-        return s->timing[2] | 0xfc000000;
-
-    case 0x10: /* LCD_STATUS */
-        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
-
-    case 0x14: /* LCD_SUBPANEL */
-        return s->subpanel;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_lcdc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* LCD_CONTROL */
-        s->plm = (value >> 20) & 3;
-        s->tft = (value >> 7) & 1;
-        s->interrupts = (value >> 3) & 3;
-        s->mono = (value >> 1) & 1;
-        s->ctrl = value & 0x01cff300;
-        if (s->enable != (value & 1)) {
-            s->enable = value & 1;
-            omap_lcd_update(s);
-        }
-        break;
-
-    case 0x04: /* LCD_TIMING0 */
-        s->timing[0] = value >> 10;
-        s->width = (value & 0x3ff) + 1;
-        break;
-
-    case 0x08: /* LCD_TIMING1 */
-        s->timing[1] = value >> 10;
-        s->height = (value & 0x3ff) + 1;
-        break;
-
-    case 0x0c: /* LCD_TIMING2 */
-        s->timing[2] = value;
-        break;
-
-    case 0x10: /* LCD_STATUS */
-        break;
-
-    case 0x14: /* LCD_SUBPANEL */
-        s->subpanel = value & 0xa1ffffff;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_lcdc_ops = {
-    .read = omap_lcdc_read,
-    .write = omap_lcdc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_lcdc_reset(struct omap_lcd_panel_s *s)
-{
-    s->dma->current_frame = -1;
-    s->plm = 0;
-    s->tft = 0;
-    s->mono = 0;
-    s->enable = 0;
-    s->width = 0;
-    s->height = 0;
-    s->interrupts = 0;
-    s->timing[0] = 0;
-    s->timing[1] = 0;
-    s->timing[2] = 0;
-    s->subpanel = 0;
-    s->palette_done = 0;
-    s->frame_done = 0;
-    s->sync_error = 0;
-    s->invalidate = 1;
-    s->subpanel = 0;
-    s->ctrl = 0;
-}
-
-struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
-                                        hwaddr base,
-                                        qemu_irq irq,
-                                        struct omap_dma_lcd_channel_s *dma,
-                                        omap_clk clk)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
-            g_malloc0(sizeof(struct omap_lcd_panel_s));
-
-    s->irq = irq;
-    s->dma = dma;
-    s->sysmem = sysmem;
-    omap_lcdc_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->con = graphic_console_init(omap_update_display,
-                                  omap_invalidate_display,
-                                  omap_screen_dump, NULL, s);
-
-    return s;
-}
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
deleted file mode 100644 (file)
index ee59bc2..0000000
+++ /dev/null
@@ -1,1058 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * 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/hw.h"
-#include "ui/console.h"
-#include "hw/arm/pxa.h"
-#include "ui/pixel_ops.h"
-/* FIXME: For graphic_rotate. Should probably be done in common code.  */
-#include "sysemu/sysemu.h"
-#include "hw/framebuffer.h"
-
-struct DMAChannel {
-    uint32_t branch;
-    uint8_t up;
-    uint8_t palette[1024];
-    uint8_t pbuffer[1024];
-    void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
-                   int *miny, int *maxy);
-
-    uint32_t descriptor;
-    uint32_t source;
-    uint32_t id;
-    uint32_t command;
-};
-
-struct PXA2xxLCDState {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    int irqlevel;
-
-    int invalidated;
-    QemuConsole *con;
-    drawfn *line_fn[2];
-    int dest_width;
-    int xres, yres;
-    int pal_for;
-    int transp;
-    enum {
-        pxa_lcdc_2bpp = 1,
-        pxa_lcdc_4bpp = 2,
-        pxa_lcdc_8bpp = 3,
-        pxa_lcdc_16bpp = 4,
-        pxa_lcdc_18bpp = 5,
-        pxa_lcdc_18pbpp = 6,
-        pxa_lcdc_19bpp = 7,
-        pxa_lcdc_19pbpp = 8,
-        pxa_lcdc_24bpp = 9,
-        pxa_lcdc_25bpp = 10,
-    } bpp;
-
-    uint32_t control[6];
-    uint32_t status[2];
-    uint32_t ovl1c[2];
-    uint32_t ovl2c[2];
-    uint32_t ccr;
-    uint32_t cmdcr;
-    uint32_t trgbr;
-    uint32_t tcr;
-    uint32_t liidr;
-    uint8_t bscntr;
-
-    struct DMAChannel dma_ch[7];
-
-    qemu_irq vsync_cb;
-    int orientation;
-};
-
-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 */
-#define LCCR2  0x008   /* LCD Controller Control register 2 */
-#define LCCR3  0x00c   /* LCD Controller Control register 3 */
-#define LCCR4  0x010   /* LCD Controller Control register 4 */
-#define LCCR5  0x014   /* LCD Controller Control register 5 */
-
-#define FBR0   0x020   /* DMA Channel 0 Frame Branch register */
-#define FBR1   0x024   /* DMA Channel 1 Frame Branch register */
-#define FBR2   0x028   /* DMA Channel 2 Frame Branch register */
-#define FBR3   0x02c   /* DMA Channel 3 Frame Branch register */
-#define FBR4   0x030   /* DMA Channel 4 Frame Branch register */
-#define FBR5   0x110   /* DMA Channel 5 Frame Branch register */
-#define FBR6   0x114   /* DMA Channel 6 Frame Branch register */
-
-#define LCSR1  0x034   /* LCD Controller Status register 1 */
-#define LCSR0  0x038   /* LCD Controller Status register 0 */
-#define LIIDR  0x03c   /* LCD Controller Interrupt ID register */
-
-#define TRGBR  0x040   /* TMED RGB Seed register */
-#define TCR    0x044   /* TMED Control register */
-
-#define OVL1C1 0x050   /* Overlay 1 Control register 1 */
-#define OVL1C2 0x060   /* Overlay 1 Control register 2 */
-#define OVL2C1 0x070   /* Overlay 2 Control register 1 */
-#define OVL2C2 0x080   /* Overlay 2 Control register 2 */
-#define CCR    0x090   /* Cursor Control register */
-
-#define CMDCR  0x100   /* Command Control register */
-#define PRSR   0x104   /* Panel Read Status register */
-
-#define PXA_LCDDMA_CHANS       7
-#define DMA_FDADR              0x00    /* Frame Descriptor Address register */
-#define DMA_FSADR              0x04    /* Frame Source Address register */
-#define DMA_FIDR               0x08    /* Frame ID register */
-#define DMA_LDCMD              0x0c    /* Command register */
-
-/* LCD Buffer Strength Control register */
-#define BSCNTR 0x04000054
-
-/* Bitfield masks */
-#define LCCR0_ENB      (1 << 0)
-#define LCCR0_CMS      (1 << 1)
-#define LCCR0_SDS      (1 << 2)
-#define LCCR0_LDM      (1 << 3)
-#define LCCR0_SOFM0    (1 << 4)
-#define LCCR0_IUM      (1 << 5)
-#define LCCR0_EOFM0    (1 << 6)
-#define LCCR0_PAS      (1 << 7)
-#define LCCR0_DPD      (1 << 9)
-#define LCCR0_DIS      (1 << 10)
-#define LCCR0_QDM      (1 << 11)
-#define LCCR0_PDD      (0xff << 12)
-#define LCCR0_BSM0     (1 << 20)
-#define LCCR0_OUM      (1 << 21)
-#define LCCR0_LCDT     (1 << 22)
-#define LCCR0_RDSTM    (1 << 23)
-#define LCCR0_CMDIM    (1 << 24)
-#define LCCR0_OUC      (1 << 25)
-#define LCCR0_LDDALT   (1 << 26)
-#define LCCR1_PPL(x)   ((x) & 0x3ff)
-#define LCCR2_LPP(x)   ((x) & 0x3ff)
-#define LCCR3_API      (15 << 16)
-#define LCCR3_BPP(x)   ((((x) >> 24) & 7) | (((x) >> 26) & 8))
-#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
-#define LCCR4_K1(x)    (((x) >> 0) & 7)
-#define LCCR4_K2(x)    (((x) >> 3) & 7)
-#define LCCR4_K3(x)    (((x) >> 6) & 7)
-#define LCCR4_PALFOR(x)        (((x) >> 15) & 3)
-#define LCCR5_SOFM(ch) (1 << (ch - 1))
-#define LCCR5_EOFM(ch) (1 << (ch + 7))
-#define LCCR5_BSM(ch)  (1 << (ch + 15))
-#define LCCR5_IUM(ch)  (1 << (ch + 23))
-#define OVLC1_EN       (1 << 31)
-#define CCR_CEN                (1 << 31)
-#define FBR_BRA                (1 << 0)
-#define FBR_BINT       (1 << 1)
-#define FBR_SRCADDR    (0xfffffff << 4)
-#define LCSR0_LDD      (1 << 0)
-#define LCSR0_SOF0     (1 << 1)
-#define LCSR0_BER      (1 << 2)
-#define LCSR0_ABC      (1 << 3)
-#define LCSR0_IU0      (1 << 4)
-#define LCSR0_IU1      (1 << 5)
-#define LCSR0_OU       (1 << 6)
-#define LCSR0_QD       (1 << 7)
-#define LCSR0_EOF0     (1 << 8)
-#define LCSR0_BS0      (1 << 9)
-#define LCSR0_SINT     (1 << 10)
-#define LCSR0_RDST     (1 << 11)
-#define LCSR0_CMDINT   (1 << 12)
-#define LCSR0_BERCH(x) (((x) & 7) << 28)
-#define LCSR1_SOF(ch)  (1 << (ch - 1))
-#define LCSR1_EOF(ch)  (1 << (ch + 7))
-#define LCSR1_BS(ch)   (1 << (ch + 15))
-#define LCSR1_IU(ch)   (1 << (ch + 23))
-#define LDCMD_LENGTH(x)        ((x) & 0x001ffffc)
-#define LDCMD_EOFINT   (1 << 21)
-#define LDCMD_SOFINT   (1 << 22)
-#define LDCMD_PAL      (1 << 26)
-
-/* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
-{
-    int level = 0;
-    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
-    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
-    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
-    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
-    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
-    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
-    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
-    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
-    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
-    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
-    level |= (s->status[1] & ~s->control[5]);
-
-    qemu_set_irq(s->irq, !!level);
-    s->irqlevel = level;
-}
-
-/* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (ch == 0) {
-        s->status[0] |= LCSR0_BS0;
-        unmasked = !(s->control[0] & LCCR0_BSM0);
-    } else {
-        s->status[1] |= LCSR1_BS(ch);
-        unmasked = !(s->control[5] & LCCR5_BSM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
-        return;
-
-    if (ch == 0) {
-        s->status[0] |= LCSR0_SOF0;
-        unmasked = !(s->control[0] & LCCR0_SOFM0);
-    } else {
-        s->status[1] |= LCSR1_SOF(ch);
-        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
-        return;
-
-    if (ch == 0) {
-        s->status[0] |= LCSR0_EOF0;
-        unmasked = !(s->control[0] & LCCR0_EOFM0);
-    } else {
-        s->status[1] |= LCSR1_EOF(ch);
-        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
-{
-    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
-    if (s->irqlevel)
-        s->status[0] |= LCSR0_SINT;
-    else
-        s->liidr = s->dma_ch[ch].id;
-}
-
-/* Set Read Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
-{
-    s->status[0] |= LCSR0_RDST;
-    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
-        s->status[0] |= LCSR0_SINT;
-}
-
-/* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
-{
-    PXAFrameDescriptor desc;
-    hwaddr descptr;
-    int i;
-
-    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
-        s->dma_ch[i].source = 0;
-
-        if (!s->dma_ch[i].up)
-            continue;
-
-        if (s->dma_ch[i].branch & FBR_BRA) {
-            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
-            if (s->dma_ch[i].branch & FBR_BINT)
-                pxa2xx_dma_bs_set(s, i);
-            s->dma_ch[i].branch &= ~FBR_BRA;
-        } else
-            descptr = s->dma_ch[i].descriptor;
-
-        if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
-                 sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size) ||
-                (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
-                 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
-            continue;
-        }
-
-        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 uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
-                                 unsigned size)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int ch;
-
-    switch (offset) {
-    case LCCR0:
-        return s->control[0];
-    case LCCR1:
-        return s->control[1];
-    case LCCR2:
-        return s->control[2];
-    case LCCR3:
-        return s->control[3];
-    case LCCR4:
-        return s->control[4];
-    case LCCR5:
-        return s->control[5];
-
-    case OVL1C1:
-        return s->ovl1c[0];
-    case OVL1C2:
-        return s->ovl1c[1];
-    case OVL2C1:
-        return s->ovl2c[0];
-    case OVL2C2:
-        return s->ovl2c[1];
-
-    case CCR:
-        return s->ccr;
-
-    case CMDCR:
-        return s->cmdcr;
-
-    case TRGBR:
-        return s->trgbr;
-    case TCR:
-        return s->tcr;
-
-    case 0x200 ... 0x1000:     /* DMA per-channel registers */
-        ch = (offset - 0x200) >> 4;
-        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
-            goto fail;
-
-        switch (offset & 0xf) {
-        case DMA_FDADR:
-            return s->dma_ch[ch].descriptor;
-        case DMA_FSADR:
-            return s->dma_ch[ch].source;
-        case DMA_FIDR:
-            return s->dma_ch[ch].id;
-        case DMA_LDCMD:
-            return s->dma_ch[ch].command;
-        default:
-            goto fail;
-        }
-
-    case FBR0:
-        return s->dma_ch[0].branch;
-    case FBR1:
-        return s->dma_ch[1].branch;
-    case FBR2:
-        return s->dma_ch[2].branch;
-    case FBR3:
-        return s->dma_ch[3].branch;
-    case FBR4:
-        return s->dma_ch[4].branch;
-    case FBR5:
-        return s->dma_ch[5].branch;
-    case FBR6:
-        return s->dma_ch[6].branch;
-
-    case BSCNTR:
-        return s->bscntr;
-
-    case PRSR:
-        return 0;
-
-    case LCSR0:
-        return s->status[0];
-    case LCSR1:
-        return s->status[1];
-    case LIIDR:
-        return s->liidr;
-
-    default:
-    fail:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned size)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int ch;
-
-    switch (offset) {
-    case LCCR0:
-        /* ACK Quick Disable done */
-        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
-            s->status[0] |= LCSR0_QD;
-
-        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
-            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
-
-        if ((s->control[3] & LCCR3_API) &&
-                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
-            s->status[0] |= LCSR0_ABC;
-
-        s->control[0] = value & 0x07ffffff;
-        pxa2xx_lcdc_int_update(s);
-
-        s->dma_ch[0].up = !!(value & LCCR0_ENB);
-        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
-        break;
-
-    case LCCR1:
-        s->control[1] = value;
-        break;
-
-    case LCCR2:
-        s->control[2] = value;
-        break;
-
-    case LCCR3:
-        s->control[3] = value & 0xefffffff;
-        s->bpp = LCCR3_BPP(value);
-        break;
-
-    case LCCR4:
-        s->control[4] = value & 0x83ff81ff;
-        break;
-
-    case LCCR5:
-        s->control[5] = value & 0x3f3f3f3f;
-        break;
-
-    case OVL1C1:
-        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
-            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
-
-        s->ovl1c[0] = value & 0x80ffffff;
-        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
-        break;
-
-    case OVL1C2:
-        s->ovl1c[1] = value & 0x000fffff;
-        break;
-
-    case OVL2C1:
-        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
-            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
-
-        s->ovl2c[0] = value & 0x80ffffff;
-        s->dma_ch[2].up = !!(value & OVLC1_EN);
-        s->dma_ch[3].up = !!(value & OVLC1_EN);
-        s->dma_ch[4].up = !!(value & OVLC1_EN);
-        break;
-
-    case OVL2C2:
-        s->ovl2c[1] = value & 0x007fffff;
-        break;
-
-    case CCR:
-        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
-            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
-
-        s->ccr = value & 0x81ffffe7;
-        s->dma_ch[5].up = !!(value & CCR_CEN);
-        break;
-
-    case CMDCR:
-        s->cmdcr = value & 0xff;
-        break;
-
-    case TRGBR:
-        s->trgbr = value & 0x00ffffff;
-        break;
-
-    case TCR:
-        s->tcr = value & 0x7fff;
-        break;
-
-    case 0x200 ... 0x1000:     /* DMA per-channel registers */
-        ch = (offset - 0x200) >> 4;
-        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
-            goto fail;
-
-        switch (offset & 0xf) {
-        case DMA_FDADR:
-            s->dma_ch[ch].descriptor = value & 0xfffffff0;
-            break;
-
-        default:
-            goto fail;
-        }
-        break;
-
-    case FBR0:
-        s->dma_ch[0].branch = value & 0xfffffff3;
-        break;
-    case FBR1:
-        s->dma_ch[1].branch = value & 0xfffffff3;
-        break;
-    case FBR2:
-        s->dma_ch[2].branch = value & 0xfffffff3;
-        break;
-    case FBR3:
-        s->dma_ch[3].branch = value & 0xfffffff3;
-        break;
-    case FBR4:
-        s->dma_ch[4].branch = value & 0xfffffff3;
-        break;
-    case FBR5:
-        s->dma_ch[5].branch = value & 0xfffffff3;
-        break;
-    case FBR6:
-        s->dma_ch[6].branch = value & 0xfffffff3;
-        break;
-
-    case BSCNTR:
-        s->bscntr = value & 0xf;
-        break;
-
-    case PRSR:
-        break;
-
-    case LCSR0:
-        s->status[0] &= ~(value & 0xfff);
-        if (value & LCSR0_BER)
-            s->status[0] &= ~LCSR0_BERCH(7);
-        break;
-
-    case LCSR1:
-        s->status[1] &= ~(value & 0x3e3f3f);
-        break;
-
-    default:
-    fail:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-}
-
-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(PXA2xxLCDState *s, int ch, int bpp)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, n, format, r, g, b, alpha;
-    uint32_t *dest;
-    uint8_t *src;
-    s->pal_for = LCCR4_PALFOR(s->control[4]);
-    format = s->pal_for;
-
-    switch (bpp) {
-    case pxa_lcdc_2bpp:
-        n = 4;
-        break;
-    case pxa_lcdc_4bpp:
-        n = 16;
-        break;
-    case pxa_lcdc_8bpp:
-        n = 256;
-        break;
-    default:
-        format = 0;
-        return;
-    }
-
-    src = (uint8_t *) s->dma_ch[ch].pbuffer;
-    dest = (uint32_t *) s->dma_ch[ch].palette;
-    alpha = r = g = b = 0;
-
-    for (i = 0; i < n; i ++) {
-        switch (format) {
-        case 0: /* 16 bpp, no transparency */
-            alpha = 0;
-            if (s->control[0] & LCCR0_CMS) {
-                r = g = b = *(uint16_t *) src & 0xff;
-            }
-            else {
-                r = (*(uint16_t *) src & 0xf800) >> 8;
-                g = (*(uint16_t *) src & 0x07e0) >> 3;
-                b = (*(uint16_t *) src & 0x001f) << 3;
-            }
-            src += 2;
-            break;
-        case 1: /* 16 bpp plus transparency */
-            alpha = *(uint16_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint16_t *) src & 0xff;
-            else {
-                r = (*(uint16_t *) src & 0xf800) >> 8;
-                g = (*(uint16_t *) src & 0x07e0) >> 3;
-                b = (*(uint16_t *) src & 0x001f) << 3;
-            }
-            src += 2;
-            break;
-        case 2: /* 18 bpp plus transparency */
-            alpha = *(uint32_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint32_t *) src & 0xff;
-            else {
-                r = (*(uint32_t *) src & 0xf80000) >> 16;
-                g = (*(uint32_t *) src & 0x00fc00) >> 8;
-                b = (*(uint32_t *) src & 0x0000f8);
-            }
-            src += 4;
-            break;
-        case 3: /* 24 bpp plus transparency */
-            alpha = *(uint32_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint32_t *) src & 0xff;
-            else {
-                r = (*(uint32_t *) src & 0xff0000) >> 16;
-                g = (*(uint32_t *) src & 0x00ff00) >> 8;
-                b = (*(uint32_t *) src & 0x0000ff);
-            }
-            src += 4;
-            break;
-        }
-        switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            *dest = rgb_to_pixel8(r, g, b) | alpha;
-            break;
-        case 15:
-            *dest = rgb_to_pixel15(r, g, b) | alpha;
-            break;
-        case 16:
-            *dest = rgb_to_pixel16(r, g, b) | alpha;
-            break;
-        case 24:
-            *dest = rgb_to_pixel24(r, g, b) | alpha;
-            break;
-        case 32:
-            *dest = rgb_to_pixel32(r, g, b) | alpha;
-            break;
-        }
-        dest ++;
-    }
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
-                hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    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(surface, 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_rot90(PXA2xxLCDState *s,
-               hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    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->yres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, 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,
-                hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    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(surface, 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,
-               hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    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->yres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, 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(PXA2xxLCDState *s)
-{
-    int width, height;
-    if (!(s->control[0] & LCCR0_ENB))
-        return;
-
-    width = LCCR1_PPL(s->control[1]) + 1;
-    height = LCCR2_LPP(s->control[2]) + 1;
-
-    if (width != s->xres || height != s->yres) {
-        if (s->orientation == 90 || s->orientation == 270) {
-            qemu_console_resize(s->con, height, width);
-        } else {
-            qemu_console_resize(s->con, width, height);
-        }
-        s->invalidated = 1;
-        s->xres = width;
-        s->yres = height;
-    }
-}
-
-static void pxa2xx_update_display(void *opaque)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    hwaddr fbptr;
-    int miny, maxy;
-    int ch;
-    if (!(s->control[0] & LCCR0_ENB))
-        return;
-
-    pxa2xx_descriptor_load(s);
-
-    pxa2xx_lcdc_resize(s);
-    miny = s->yres;
-    maxy = 0;
-    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
-    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
-    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
-        if (s->dma_ch[ch].up) {
-            if (!s->dma_ch[ch].source) {
-                pxa2xx_dma_ber_set(s, ch);
-                continue;
-            }
-            fbptr = s->dma_ch[ch].source;
-            if (!((fbptr >= PXA2XX_SDRAM_BASE &&
-                     fbptr <= PXA2XX_SDRAM_BASE + ram_size) ||
-                    (fbptr >= PXA2XX_INTERNAL_BASE &&
-                     fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
-                pxa2xx_dma_ber_set(s, ch);
-                continue;
-            }
-
-            if (s->dma_ch[ch].command & LDCMD_PAL) {
-                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 */
-                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
-                    pxa2xx_palette_parse(s, ch, s->bpp);
-
-                /* ACK frame start */
-                pxa2xx_dma_sof_set(s, ch);
-
-                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
-                s->invalidated = 0;
-
-                /* ACK frame completed */
-                pxa2xx_dma_eof_set(s, ch);
-            }
-        }
-
-    if (s->control[0] & LCCR0_DIS) {
-        /* ACK last frame completed */
-        s->control[0] &= ~LCCR0_ENB;
-        s->status[0] |= LCSR0_LDD;
-    }
-
-    if (miny >= 0) {
-        switch (s->orientation) {
-        case 0:
-            dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
-            break;
-        case 90:
-            dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
-            break;
-        case 180:
-            maxy = s->yres - maxy - 1;
-            miny = s->yres - miny - 1;
-            dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
-            break;
-        case 270:
-            maxy = s->yres - maxy - 1;
-            miny = s->yres - miny - 1;
-            dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
-            break;
-        }
-    }
-    pxa2xx_lcdc_int_update(s);
-
-    qemu_irq_raise(s->vsync_cb);
-}
-
-static void pxa2xx_invalidate_display(void *opaque)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    s->invalidated = 1;
-}
-
-static void pxa2xx_lcdc_orientation(void *opaque, int angle)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-
-    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;
-    s->xres = s->yres = -1;
-    pxa2xx_lcdc_resize(s);
-}
-
-static const VMStateDescription vmstate_dma_channel = {
-    .name = "dma_channel",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(branch, struct DMAChannel),
-        VMSTATE_UINT8(up, struct DMAChannel),
-        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
-        VMSTATE_UINT32(descriptor, struct DMAChannel),
-        VMSTATE_UINT32(source, struct DMAChannel),
-        VMSTATE_UINT32(id, struct DMAChannel),
-        VMSTATE_UINT32(command, struct DMAChannel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
-{
-    PXA2xxLCDState *s = opaque;
-
-    s->bpp = LCCR3_BPP(s->control[3]);
-    s->xres = s->yres = s->pal_for = -1;
-
-    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 "hw/pxa2xx_template.h"
-#define BITS 15
-#include "hw/pxa2xx_template.h"
-#define BITS 16
-#include "hw/pxa2xx_template.h"
-#define BITS 24
-#include "hw/pxa2xx_template.h"
-#define BITS 32
-#include "hw/pxa2xx_template.h"
-
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
-                                 hwaddr base, qemu_irq irq)
-{
-    PXA2xxLCDState *s;
-    DisplaySurface *surface;
-
-    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
-    s->invalidated = 1;
-    s->irq = irq;
-    s->sysmem = sysmem;
-
-    pxa2xx_lcdc_orientation(s, graphic_rotate);
-
-    memory_region_init_io(&s->iomem, &pxa2xx_lcdc_ops, s,
-                          "pxa2xx-lcd-controller", 0x00100000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->con = graphic_console_init(pxa2xx_update_display,
-                                  pxa2xx_invalidate_display,
-                                  NULL, NULL, s);
-    surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        s->dest_width = 0;
-        break;
-    case 8:
-        s->line_fn[0] = pxa2xx_draw_fn_8;
-        s->line_fn[1] = pxa2xx_draw_fn_8t;
-        s->dest_width = 1;
-        break;
-    case 15:
-        s->line_fn[0] = pxa2xx_draw_fn_15;
-        s->line_fn[1] = pxa2xx_draw_fn_15t;
-        s->dest_width = 2;
-        break;
-    case 16:
-        s->line_fn[0] = pxa2xx_draw_fn_16;
-        s->line_fn[1] = pxa2xx_draw_fn_16t;
-        s->dest_width = 2;
-        break;
-    case 24:
-        s->line_fn[0] = pxa2xx_draw_fn_24;
-        s->line_fn[1] = pxa2xx_draw_fn_24t;
-        s->dest_width = 3;
-        break;
-    case 32:
-        s->line_fn[0] = pxa2xx_draw_fn_32;
-        s->line_fn[1] = pxa2xx_draw_fn_32t;
-        s->dest_width = 4;
-        break;
-    default:
-        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
-        exit(1);
-    }
-
-    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
-
-    return s;
-}
-
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
-{
-    s->vsync_cb = handler;
-}
diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
deleted file mode 100644 (file)
index 84f9aa1..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * qxl command logging -- for debug purposes
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/timer.h"
-#include "hw/qxl.h"
-
-static const char *qxl_type[] = {
-    [ QXL_CMD_NOP ]     = "nop",
-    [ QXL_CMD_DRAW ]    = "draw",
-    [ QXL_CMD_UPDATE ]  = "update",
-    [ QXL_CMD_CURSOR ]  = "cursor",
-    [ QXL_CMD_MESSAGE ] = "message",
-    [ QXL_CMD_SURFACE ] = "surface",
-};
-
-static const char *qxl_draw_type[] = {
-    [ QXL_DRAW_NOP         ] = "nop",
-    [ QXL_DRAW_FILL        ] = "fill",
-    [ QXL_DRAW_OPAQUE      ] = "opaque",
-    [ QXL_DRAW_COPY        ] = "copy",
-    [ QXL_COPY_BITS        ] = "copy-bits",
-    [ QXL_DRAW_BLEND       ] = "blend",
-    [ QXL_DRAW_BLACKNESS   ] = "blackness",
-    [ QXL_DRAW_WHITENESS   ] = "whitemess",
-    [ QXL_DRAW_INVERS      ] = "invers",
-    [ QXL_DRAW_ROP3        ] = "rop3",
-    [ QXL_DRAW_STROKE      ] = "stroke",
-    [ QXL_DRAW_TEXT        ] = "text",
-    [ QXL_DRAW_TRANSPARENT ] = "transparent",
-    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
-};
-
-static const char *qxl_draw_effect[] = {
-    [ QXL_EFFECT_BLEND            ] = "blend",
-    [ QXL_EFFECT_OPAQUE           ] = "opaque",
-    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
-    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
-    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
-    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
-    [ QXL_EFFECT_NOP              ] = "nop",
-    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
-};
-
-static const char *qxl_surface_cmd[] = {
-   [ QXL_SURFACE_CMD_CREATE  ] = "create",
-   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
-};
-
-static const char *spice_surface_fmt[] = {
-   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
-   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
-   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
-   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
-   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
-   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
-   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
-};
-
-static const char *qxl_cursor_cmd[] = {
-   [ QXL_CURSOR_SET   ] = "set",
-   [ QXL_CURSOR_MOVE  ] = "move",
-   [ QXL_CURSOR_HIDE  ] = "hide",
-   [ QXL_CURSOR_TRAIL ] = "trail",
-};
-
-static const char *spice_cursor_type[] = {
-   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
-   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
-   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
-   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
-   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
-   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
-   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
-};
-
-static const char *qxl_v2n(const char *n[], size_t l, int v)
-{
-    if (v >= l || !n[v]) {
-        return "???";
-    }
-    return n[v];
-}
-#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
-
-static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
-{
-    QXLImage *image;
-    QXLImageDescriptor *desc;
-
-    image = qxl_phys2virt(qxl, addr, group_id);
-    if (!image) {
-        return 1;
-    }
-    desc = &image->descriptor;
-    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
-            desc->id, desc->type, desc->flags, desc->width, desc->height);
-    switch (desc->type) {
-    case SPICE_IMAGE_TYPE_BITMAP:
-        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
-                " palette %" PRIx64 " data %" PRIx64,
-                image->bitmap.format, image->bitmap.flags,
-                image->bitmap.x, image->bitmap.y,
-                image->bitmap.stride,
-                image->bitmap.palette, image->bitmap.data);
-        break;
-    }
-    fprintf(stderr, ")");
-    return 0;
-}
-
-static void qxl_log_rect(QXLRect *rect)
-{
-    fprintf(stderr, " %dx%d+%d+%d",
-            rect->right - rect->left,
-            rect->bottom - rect->top,
-            rect->left, rect->top);
-}
-
-static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
-                                 int group_id)
-{
-    int ret;
-
-    fprintf(stderr, " src %" PRIx64,
-            copy->src_bitmap);
-    ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
-    if (ret != 0) {
-        return ret;
-    }
-    fprintf(stderr, " area");
-    qxl_log_rect(&copy->src_area);
-    fprintf(stderr, " rop %d", copy->rop_descriptor);
-    return 0;
-}
-
-static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
-{
-    fprintf(stderr, ": surface_id %d type %s effect %s",
-            draw->surface_id,
-            qxl_name(qxl_draw_type, draw->type),
-            qxl_name(qxl_draw_effect, draw->effect));
-    switch (draw->type) {
-    case QXL_DRAW_COPY:
-        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
-        break;
-    }
-    return 0;
-}
-
-static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
-                                   int group_id)
-{
-    fprintf(stderr, ": type %s effect %s",
-            qxl_name(qxl_draw_type, draw->type),
-            qxl_name(qxl_draw_effect, draw->effect));
-    if (draw->bitmap_offset) {
-        fprintf(stderr, ": bitmap %d",
-                draw->bitmap_offset);
-        qxl_log_rect(&draw->bitmap_area);
-    }
-    switch (draw->type) {
-    case QXL_DRAW_COPY:
-        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
-        break;
-    }
-    return 0;
-}
-
-static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
-{
-    fprintf(stderr, ": %s id %d",
-            qxl_name(qxl_surface_cmd, cmd->type),
-            cmd->surface_id);
-    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
-        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
-                cmd->u.surface_create.width,
-                cmd->u.surface_create.height,
-                cmd->u.surface_create.stride,
-                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
-                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
-    }
-    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
-        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
-    }
-}
-
-int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
-{
-    QXLCursor *cursor;
-
-    fprintf(stderr, ": %s",
-            qxl_name(qxl_cursor_cmd, cmd->type));
-    switch (cmd->type) {
-    case QXL_CURSOR_SET:
-        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
-                cmd->u.set.position.x,
-                cmd->u.set.position.y,
-                cmd->u.set.visible ? "yes" : "no",
-                cmd->u.set.shape);
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
-        if (!cursor) {
-            return 1;
-        }
-        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
-                " unique 0x%" PRIx64 " data-size %d",
-                qxl_name(spice_cursor_type, cursor->header.type),
-                cursor->header.width, cursor->header.height,
-                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
-                cursor->header.unique, cursor->data_size);
-        break;
-    case QXL_CURSOR_MOVE:
-        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
-        break;
-    }
-    return 0;
-}
-
-int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
-{
-    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
-    void *data;
-    int ret;
-
-    if (!qxl->cmdlog) {
-        return 0;
-    }
-    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
-            qxl->id, ring);
-    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
-            qxl_name(qxl_type, ext->cmd.type),
-            compat ? "(compat)" : "");
-
-    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-    if (!data) {
-        return 1;
-    }
-    switch (ext->cmd.type) {
-    case QXL_CMD_DRAW:
-        if (!compat) {
-            ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
-        } else {
-            ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
-        }
-        if (ret) {
-            return ret;
-        }
-        break;
-    case QXL_CMD_SURFACE:
-        qxl_log_cmd_surface(qxl, data);
-        break;
-    case QXL_CMD_CURSOR:
-        qxl_log_cmd_cursor(qxl, data, ext->group_id);
-        break;
-    }
-    fprintf(stderr, "\n");
-    return 0;
-}
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
deleted file mode 100644 (file)
index 8cd9be4..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * qxl local rendering (aka display on sdl/vnc)
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/qxl.h"
-
-static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
-{
-    DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
-    uint8_t *dst = surface_data(surface);
-    uint8_t *src;
-    int len, i;
-
-    if (is_buffer_shared(surface)) {
-        return;
-    }
-    if (!qxl->guest_primary.data) {
-        trace_qxl_render_blit_guest_primary_initialized();
-        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
-    }
-    trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
-            rect->left, rect->right, rect->top, rect->bottom);
-    src = qxl->guest_primary.data;
-    if (qxl->guest_primary.qxl_stride < 0) {
-        /* qxl surface is upside down, walk src scanlines
-         * in reverse order to flip it */
-        src += (qxl->guest_primary.surface.height - rect->top - 1) *
-            qxl->guest_primary.abs_stride;
-    } else {
-        src += rect->top * qxl->guest_primary.abs_stride;
-    }
-    dst += rect->top  * qxl->guest_primary.abs_stride;
-    src += rect->left * qxl->guest_primary.bytes_pp;
-    dst += rect->left * qxl->guest_primary.bytes_pp;
-    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
-
-    for (i = rect->top; i < rect->bottom; i++) {
-        memcpy(dst, src, len);
-        dst += qxl->guest_primary.abs_stride;
-        src += qxl->guest_primary.qxl_stride;
-    }
-}
-
-void qxl_render_resize(PCIQXLDevice *qxl)
-{
-    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-
-    qxl->guest_primary.qxl_stride = sc->stride;
-    qxl->guest_primary.abs_stride = abs(sc->stride);
-    qxl->guest_primary.resized++;
-    switch (sc->format) {
-    case SPICE_SURFACE_FMT_16_555:
-        qxl->guest_primary.bytes_pp = 2;
-        qxl->guest_primary.bits_pp = 15;
-        break;
-    case SPICE_SURFACE_FMT_16_565:
-        qxl->guest_primary.bytes_pp = 2;
-        qxl->guest_primary.bits_pp = 16;
-        break;
-    case SPICE_SURFACE_FMT_32_xRGB:
-    case SPICE_SURFACE_FMT_32_ARGB:
-        qxl->guest_primary.bytes_pp = 4;
-        qxl->guest_primary.bits_pp = 32;
-        break;
-    default:
-        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
-                qxl->guest_primary.surface.format);
-        qxl->guest_primary.bytes_pp = 4;
-        qxl->guest_primary.bits_pp = 32;
-        break;
-    }
-}
-
-static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
-{
-    area->left   = 0;
-    area->right  = qxl->guest_primary.surface.width;
-    area->top    = 0;
-    area->bottom = qxl->guest_primary.surface.height;
-}
-
-static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
-{
-    VGACommonState *vga = &qxl->vga;
-    DisplaySurface *surface;
-    int i;
-
-    if (qxl->guest_primary.resized) {
-        qxl->guest_primary.resized = 0;
-        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
-        qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
-        qxl->num_dirty_rects = 1;
-        trace_qxl_render_guest_primary_resized(
-               qxl->guest_primary.surface.width,
-               qxl->guest_primary.surface.height,
-               qxl->guest_primary.qxl_stride,
-               qxl->guest_primary.bytes_pp,
-               qxl->guest_primary.bits_pp);
-        if (qxl->guest_primary.qxl_stride > 0) {
-            surface = qemu_create_displaysurface_from
-                (qxl->guest_primary.surface.width,
-                 qxl->guest_primary.surface.height,
-                 qxl->guest_primary.bits_pp,
-                 qxl->guest_primary.abs_stride,
-                 qxl->guest_primary.data,
-                 false);
-        } else {
-            surface = qemu_create_displaysurface
-                (qxl->guest_primary.surface.width,
-                 qxl->guest_primary.surface.height);
-        }
-        dpy_gfx_replace_surface(vga->con, surface);
-    }
-    for (i = 0; i < qxl->num_dirty_rects; i++) {
-        if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
-            break;
-        }
-        qxl_blit(qxl, qxl->dirty+i);
-        dpy_gfx_update(vga->con,
-                       qxl->dirty[i].left, qxl->dirty[i].top,
-                       qxl->dirty[i].right - qxl->dirty[i].left,
-                       qxl->dirty[i].bottom - qxl->dirty[i].top);
-    }
-    qxl->num_dirty_rects = 0;
-}
-
-/*
- * use ssd.lock to protect render_update_cookie_num.
- * qxl_render_update is called by io thread or vcpu thread, and the completion
- * callbacks are called by spice_server thread, defering to bh called from the
- * io thread.
- */
-void qxl_render_update(PCIQXLDevice *qxl)
-{
-    QXLCookie *cookie;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-
-    if (!runstate_is_running() || !qxl->guest_primary.commands) {
-        qxl_render_update_area_unlocked(qxl);
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-
-    qxl->guest_primary.commands = 0;
-    qxl->render_update_cookie_num++;
-    qemu_mutex_unlock(&qxl->ssd.lock);
-    cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
-                            0);
-    qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
-    qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
-                          0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
-}
-
-void qxl_render_update_area_bh(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-    qxl_render_update_area_unlocked(qxl);
-    qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
-    qemu_mutex_lock(&qxl->ssd.lock);
-    trace_qxl_render_update_area_done(cookie);
-    qemu_bh_schedule(qxl->update_area_bh);
-    qxl->render_update_cookie_num--;
-    qemu_mutex_unlock(&qxl->ssd.lock);
-    g_free(cookie);
-}
-
-static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
-{
-    QEMUCursor *c;
-    uint8_t *image, *mask;
-    size_t size;
-
-    c = cursor_alloc(cursor->header.width, cursor->header.height);
-    c->hot_x = cursor->header.hot_spot_x;
-    c->hot_y = cursor->header.hot_spot_y;
-    switch (cursor->header.type) {
-    case SPICE_CURSOR_TYPE_ALPHA:
-        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
-        memcpy(c->data, cursor->chunk.data, size);
-        if (qxl->debug > 2) {
-            cursor_print_ascii_art(c, "qxl/alpha");
-        }
-        break;
-    case SPICE_CURSOR_TYPE_MONO:
-        mask  = cursor->chunk.data;
-        image = mask + cursor_get_mono_bpl(c) * c->width;
-        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
-        if (qxl->debug > 2) {
-            cursor_print_ascii_art(c, "qxl/mono");
-        }
-        break;
-    default:
-        fprintf(stderr, "%s: not implemented: type %d\n",
-                __FUNCTION__, cursor->header.type);
-        goto fail;
-    }
-    return c;
-
-fail:
-    cursor_put(c);
-    return NULL;
-}
-
-
-/* called from spice server thread context only */
-int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
-{
-    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-    QXLCursor *cursor;
-    QEMUCursor *c;
-
-    if (!cmd) {
-        return 1;
-    }
-
-    if (!dpy_cursor_define_supported(qxl->vga.con)) {
-        return 0;
-    }
-
-    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
-        fprintf(stderr, "%s", __FUNCTION__);
-        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
-        fprintf(stderr, "\n");
-    }
-    switch (cmd->type) {
-    case QXL_CURSOR_SET:
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
-        if (!cursor) {
-            return 1;
-        }
-        if (cursor->chunk.data_size != cursor->data_size) {
-            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
-            return 1;
-        }
-        c = qxl_cursor(qxl, cursor);
-        if (c == NULL) {
-            c = cursor_builtin_left_ptr();
-        }
-        qemu_mutex_lock(&qxl->ssd.lock);
-        if (qxl->ssd.cursor) {
-            cursor_put(qxl->ssd.cursor);
-        }
-        qxl->ssd.cursor = c;
-        qxl->ssd.mouse_x = cmd->u.set.position.x;
-        qxl->ssd.mouse_y = cmd->u.set.position.y;
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        break;
-    case QXL_CURSOR_MOVE:
-        qemu_mutex_lock(&qxl->ssd.lock);
-        qxl->ssd.mouse_x = cmd->u.position.x;
-        qxl->ssd.mouse_y = cmd->u.position.y;
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        break;
-    }
-    return 0;
-}
diff --git a/hw/qxl.c b/hw/qxl.c
deleted file mode 100644 (file)
index b66b414..0000000
--- a/hw/qxl.c
+++ /dev/null
@@ -1,2365 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
- * maintained by Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <zlib.h>
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "qemu/queue.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "hw/qxl.h"
-
-/*
- * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
- * such can be changed by the guest, so to avoid a guest trigerrable
- * abort we just qxl_set_guest_bug and set the return to NULL. Still
- * it may happen as a result of emulator bug as well.
- */
-#undef SPICE_RING_PROD_ITEM
-#define SPICE_RING_PROD_ITEM(qxl, r, ret) {                             \
-        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
-        if (prod >= ARRAY_SIZE((r)->items)) {                           \
-            qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
-                          "%u >= %zu", prod, ARRAY_SIZE((r)->items));   \
-            ret = NULL;                                                 \
-        } else {                                                        \
-            ret = &(r)->items[prod].el;                                 \
-        }                                                               \
-    }
-
-#undef SPICE_RING_CONS_ITEM
-#define SPICE_RING_CONS_ITEM(qxl, r, ret) {                             \
-        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
-        if (cons >= ARRAY_SIZE((r)->items)) {                           \
-            qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \
-                          "%u >= %zu", cons, ARRAY_SIZE((r)->items));   \
-            ret = NULL;                                                 \
-        } else {                                                        \
-            ret = &(r)->items[cons].el;                                 \
-        }                                                               \
-    }
-
-#undef ALIGN
-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-
-#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
-
-#define QXL_MODE(_x, _y, _b, _o)                  \
-    {   .x_res = _x,                              \
-        .y_res = _y,                              \
-        .bits  = _b,                              \
-        .stride = (_x) * (_b) / 8,                \
-        .x_mili = PIXEL_SIZE * (_x),              \
-        .y_mili = PIXEL_SIZE * (_y),              \
-        .orientation = _o,                        \
-    }
-
-#define QXL_MODE_16_32(x_res, y_res, orientation) \
-    QXL_MODE(x_res, y_res, 16, orientation),      \
-    QXL_MODE(x_res, y_res, 32, orientation)
-
-#define QXL_MODE_EX(x_res, y_res)                 \
-    QXL_MODE_16_32(x_res, y_res, 0),              \
-    QXL_MODE_16_32(x_res, y_res, 1)
-
-static QXLMode qxl_modes[] = {
-    QXL_MODE_EX(640, 480),
-    QXL_MODE_EX(800, 480),
-    QXL_MODE_EX(800, 600),
-    QXL_MODE_EX(832, 624),
-    QXL_MODE_EX(960, 640),
-    QXL_MODE_EX(1024, 600),
-    QXL_MODE_EX(1024, 768),
-    QXL_MODE_EX(1152, 864),
-    QXL_MODE_EX(1152, 870),
-    QXL_MODE_EX(1280, 720),
-    QXL_MODE_EX(1280, 760),
-    QXL_MODE_EX(1280, 768),
-    QXL_MODE_EX(1280, 800),
-    QXL_MODE_EX(1280, 960),
-    QXL_MODE_EX(1280, 1024),
-    QXL_MODE_EX(1360, 768),
-    QXL_MODE_EX(1366, 768),
-    QXL_MODE_EX(1400, 1050),
-    QXL_MODE_EX(1440, 900),
-    QXL_MODE_EX(1600, 900),
-    QXL_MODE_EX(1600, 1200),
-    QXL_MODE_EX(1680, 1050),
-    QXL_MODE_EX(1920, 1080),
-    /* these modes need more than 8 MB video memory */
-    QXL_MODE_EX(1920, 1200),
-    QXL_MODE_EX(1920, 1440),
-    QXL_MODE_EX(2048, 1536),
-    QXL_MODE_EX(2560, 1440),
-    QXL_MODE_EX(2560, 1600),
-    /* these modes need more than 16 MB video memory */
-    QXL_MODE_EX(2560, 2048),
-    QXL_MODE_EX(2800, 2100),
-    QXL_MODE_EX(3200, 2400),
-};
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
-static void qxl_reset_memslots(PCIQXLDevice *d);
-static void qxl_reset_surfaces(PCIQXLDevice *d);
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
-
-void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
-{
-    trace_qxl_set_guest_bug(qxl->id);
-    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
-    qxl->guest_bug = 1;
-    if (qxl->guestdebug) {
-        va_list ap;
-        va_start(ap, msg);
-        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
-        vfprintf(stderr, msg, ap);
-        fprintf(stderr, "\n");
-        va_end(ap);
-    }
-}
-
-static void qxl_clear_guest_bug(PCIQXLDevice *qxl)
-{
-    qxl->guest_bug = 0;
-}
-
-void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                           struct QXLRect *area, struct QXLRect *dirty_rects,
-                           uint32_t num_dirty_rects,
-                           uint32_t clear_dirty_region,
-                           qxl_async_io async, struct QXLCookie *cookie)
-{
-    trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right,
-                                area->top, area->bottom);
-    trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects,
-                                     clear_dirty_region);
-    if (async == QXL_SYNC) {
-        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
-                        dirty_rects, num_dirty_rects, clear_dirty_region);
-    } else {
-        assert(cookie != NULL);
-        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
-                                    clear_dirty_region, (uintptr_t)cookie);
-    }
-}
-
-static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
-                                                    uint32_t id)
-{
-    trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id);
-    qemu_mutex_lock(&qxl->track_lock);
-    qxl->guest_surfaces.cmds[id] = 0;
-    qxl->guest_surfaces.count--;
-    qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
-                                           qxl_async_io async)
-{
-    QXLCookie *cookie;
-
-    trace_qxl_spice_destroy_surface_wait(qxl->id, id, async);
-    if (async) {
-        cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                QXL_IO_DESTROY_SURFACE_ASYNC);
-        cookie->u.surface_id = id;
-        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
-    } else {
-        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-        qxl_spice_destroy_surface_wait_complete(qxl, id);
-    }
-}
-
-static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count,
-                                         qxl->num_free_res);
-    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl,
-        (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                  QXL_IO_FLUSH_SURFACES_ASYNC));
-}
-
-void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                               uint32_t count)
-{
-    trace_qxl_spice_loadvm_commands(qxl->id, ext, count);
-    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
-}
-
-void qxl_spice_oom(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_oom(qxl->id);
-    qxl->ssd.worker->oom(qxl->ssd.worker);
-}
-
-void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_memslots(qxl->id);
-    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
-}
-
-static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_destroy_surfaces_complete(qxl->id);
-    qemu_mutex_lock(&qxl->track_lock);
-    memset(qxl->guest_surfaces.cmds, 0,
-           sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
-    qxl->guest_surfaces.count = 0;
-    qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
-{
-    trace_qxl_spice_destroy_surfaces(qxl->id, async);
-    if (async) {
-        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
-                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                          QXL_IO_DESTROY_ALL_SURFACES_ASYNC));
-    } else {
-        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-        qxl_spice_destroy_surfaces_complete(qxl);
-    }
-}
-
-static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
-{
-    trace_qxl_spice_monitors_config(qxl->id);
-    if (replay) {
-        /*
-         * don't use QXL_COOKIE_TYPE_IO:
-         *  - we are not running yet (post_load), we will assert
-         *    in send_events
-         *  - this is not a guest io, but a reply, so async_io isn't set.
-         */
-        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
-                qxl->guest_monitors_config,
-                MEMSLOT_GROUP_GUEST,
-                (uintptr_t)qxl_cookie_new(
-                    QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
-                    0));
-    } else {
-        qxl->guest_monitors_config = qxl->ram->monitors_config;
-        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
-                qxl->ram->monitors_config,
-                MEMSLOT_GROUP_GUEST,
-                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                          QXL_IO_MONITORS_CONFIG_ASYNC));
-    }
-}
-
-void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_image_cache(qxl->id);
-    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
-}
-
-void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_cursor(qxl->id);
-    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
-    qemu_mutex_lock(&qxl->track_lock);
-    qxl->guest_cursor = 0;
-    qemu_mutex_unlock(&qxl->track_lock);
-    if (qxl->ssd.cursor) {
-        cursor_put(qxl->ssd.cursor);
-    }
-    qxl->ssd.cursor = cursor_builtin_hidden();
-}
-
-
-static inline uint32_t msb_mask(uint32_t val)
-{
-    uint32_t mask;
-
-    do {
-        mask = ~(val - 1) & val;
-        val &= ~mask;
-    } while (mask < val);
-
-    return mask;
-}
-
-static ram_addr_t qxl_rom_size(void)
-{
-    uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
-                                 sizeof(qxl_modes);
-    uint32_t rom_size = 8192; /* two pages */
-
-    required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE);
-    required_rom_size = msb_mask(required_rom_size * 2 - 1);
-    assert(required_rom_size <= rom_size);
-    return rom_size;
-}
-
-static void init_qxl_rom(PCIQXLDevice *d)
-{
-    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
-    QXLModes *modes = (QXLModes *)(rom + 1);
-    uint32_t ram_header_size;
-    uint32_t surface0_area_size;
-    uint32_t num_pages;
-    uint32_t fb;
-    int i, n;
-
-    memset(rom, 0, d->rom_size);
-
-    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
-    rom->id            = cpu_to_le32(d->id);
-    rom->log_level     = cpu_to_le32(d->guestdebug);
-    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
-
-    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
-    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
-    rom->slots_start   = 1;
-    rom->slots_end     = NUM_MEMSLOTS - 1;
-    rom->n_surfaces    = cpu_to_le32(d->ssd.num_surfaces);
-
-    for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
-        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
-        if (fb > d->vgamem_size) {
-            continue;
-        }
-        modes->modes[n].id          = cpu_to_le32(i);
-        modes->modes[n].x_res       = cpu_to_le32(qxl_modes[i].x_res);
-        modes->modes[n].y_res       = cpu_to_le32(qxl_modes[i].y_res);
-        modes->modes[n].bits        = cpu_to_le32(qxl_modes[i].bits);
-        modes->modes[n].stride      = cpu_to_le32(qxl_modes[i].stride);
-        modes->modes[n].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
-        modes->modes[n].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
-        modes->modes[n].orientation = cpu_to_le32(qxl_modes[i].orientation);
-        n++;
-    }
-    modes->n_modes     = cpu_to_le32(n);
-
-    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
-    surface0_area_size = ALIGN(d->vgamem_size, 4096);
-    num_pages          = d->vga.vram_size;
-    num_pages         -= ram_header_size;
-    num_pages         -= surface0_area_size;
-    num_pages          = num_pages / TARGET_PAGE_SIZE;
-
-    rom->draw_area_offset   = cpu_to_le32(0);
-    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
-    rom->pages_offset       = cpu_to_le32(surface0_area_size);
-    rom->num_pages          = cpu_to_le32(num_pages);
-    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
-
-    d->shadow_rom = *rom;
-    d->rom        = rom;
-    d->modes      = modes;
-}
-
-static void init_qxl_ram(PCIQXLDevice *d)
-{
-    uint8_t *buf;
-    uint64_t *item;
-
-    buf = d->vga.vram_ptr;
-    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
-    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
-    d->ram->int_pending = cpu_to_le32(0);
-    d->ram->int_mask    = cpu_to_le32(0);
-    d->ram->update_surface = 0;
-    SPICE_RING_INIT(&d->ram->cmd_ring);
-    SPICE_RING_INIT(&d->ram->cursor_ring);
-    SPICE_RING_INIT(&d->ram->release_ring);
-    SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
-    assert(item);
-    *item = 0;
-    qxl_ring_set_dirty(d);
-}
-
-/* can be called from spice server thread context */
-static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
-{
-    memory_region_set_dirty(mr, addr, end - addr);
-}
-
-static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
-{
-    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
-}
-
-/* called from spice server thread context only */
-static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
-{
-    void *base = qxl->vga.vram_ptr;
-    intptr_t offset;
-
-    offset = ptr - base;
-    offset &= ~(TARGET_PAGE_SIZE-1);
-    assert(offset < qxl->vga.vram_size);
-    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
-}
-
-/* can be called from spice server thread context */
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
-{
-    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
-    ram_addr_t end  = qxl->vga.vram_size;
-    qxl_set_dirty(&qxl->vga.vram, addr, end);
-}
-
-/*
- * keep track of some command state, for savevm/loadvm.
- * called from spice server thread context only
- */
-static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
-{
-    switch (le32_to_cpu(ext->cmd.type)) {
-    case QXL_CMD_SURFACE:
-    {
-        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
-        if (!cmd) {
-            return 1;
-        }
-        uint32_t id = le32_to_cpu(cmd->surface_id);
-
-        if (id >= qxl->ssd.num_surfaces) {
-            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
-                              qxl->ssd.num_surfaces);
-            return 1;
-        }
-        if (cmd->type == QXL_SURFACE_CMD_CREATE &&
-            (cmd->u.surface_create.stride & 0x03) != 0) {
-            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
-                              cmd->u.surface_create.stride);
-            return 1;
-        }
-        qemu_mutex_lock(&qxl->track_lock);
-        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
-            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
-            qxl->guest_surfaces.count++;
-            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
-                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
-        }
-        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
-            qxl->guest_surfaces.cmds[id] = 0;
-            qxl->guest_surfaces.count--;
-        }
-        qemu_mutex_unlock(&qxl->track_lock);
-        break;
-    }
-    case QXL_CMD_CURSOR:
-    {
-        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
-        if (!cmd) {
-            return 1;
-        }
-        if (cmd->type == QXL_CURSOR_SET) {
-            qemu_mutex_lock(&qxl->track_lock);
-            qxl->guest_cursor = ext->cmd.data;
-            qemu_mutex_unlock(&qxl->track_lock);
-        }
-        break;
-    }
-    }
-    return 0;
-}
-
-/* spice display interface callbacks */
-
-static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_attach_worker(qxl->id);
-    qxl->ssd.worker = qxl_worker;
-}
-
-static void interface_set_compression_level(QXLInstance *sin, int level)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_set_compression_level(qxl->id, level);
-    qxl->shadow_rom.compression_level = cpu_to_le32(level);
-    qxl->rom->compression_level = cpu_to_le32(level);
-    qxl_rom_set_dirty(qxl);
-}
-
-static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_set_mm_time(qxl->id, mm_time);
-    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
-    qxl->rom->mm_clock = cpu_to_le32(mm_time);
-    qxl_rom_set_dirty(qxl);
-}
-
-static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_get_init_info(qxl->id);
-    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
-    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
-    info->num_memslots = NUM_MEMSLOTS;
-    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
-    info->internal_groupslot_id = 0;
-    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
-    info->n_surfaces = qxl->ssd.num_surfaces;
-}
-
-static const char *qxl_mode_to_string(int mode)
-{
-    switch (mode) {
-    case QXL_MODE_COMPAT:
-        return "compat";
-    case QXL_MODE_NATIVE:
-        return "native";
-    case QXL_MODE_UNDEFINED:
-        return "undefined";
-    case QXL_MODE_VGA:
-        return "vga";
-    }
-    return "INVALID";
-}
-
-static const char *io_port_to_string(uint32_t io_port)
-{
-    if (io_port >= QXL_IO_RANGE_SIZE) {
-        return "out of range";
-    }
-    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
-        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
-        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
-        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
-        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
-        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
-        [QXL_IO_RESET]                  = "QXL_IO_RESET",
-        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
-        [QXL_IO_LOG]                    = "QXL_IO_LOG",
-        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
-        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
-        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
-        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
-        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
-        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
-        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
-        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
-        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
-        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
-        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
-        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
-        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
-        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
-                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
-        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
-        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
-        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
-    };
-    return io_port_to_string[io_port];
-}
-
-/* called from spice server thread context only */
-static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    SimpleSpiceUpdate *update;
-    QXLCommandRing *ring;
-    QXLCommand *cmd;
-    int notify, ret;
-
-    trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
-    switch (qxl->mode) {
-    case QXL_MODE_VGA:
-        ret = false;
-        qemu_mutex_lock(&qxl->ssd.lock);
-        update = QTAILQ_FIRST(&qxl->ssd.updates);
-        if (update != NULL) {
-            QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
-            *ext = update->ext;
-            ret = true;
-        }
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        if (ret) {
-            trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
-            qxl_log_command(qxl, "vga", ext);
-        }
-        return ret;
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        ring = &qxl->ram->cmd_ring;
-        if (qxl->guest_bug || SPICE_RING_IS_EMPTY(ring)) {
-            return false;
-        }
-        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
-        if (!cmd) {
-            return false;
-        }
-        ext->cmd      = *cmd;
-        ext->group_id = MEMSLOT_GROUP_GUEST;
-        ext->flags    = qxl->cmdflags;
-        SPICE_RING_POP(ring, notify);
-        qxl_ring_set_dirty(qxl);
-        if (notify) {
-            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
-        }
-        qxl->guest_primary.commands++;
-        qxl_track_command(qxl, ext);
-        qxl_log_command(qxl, "cmd", ext);
-        trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
-        return true;
-    default:
-        return false;
-    }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cmd_notification(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int wait = 1;
-
-    trace_qxl_ring_command_req_notification(qxl->id);
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
-        qxl_ring_set_dirty(qxl);
-        break;
-    default:
-        /* nothing */
-        break;
-    }
-    return wait;
-}
-
-/* called from spice server thread context only */
-static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
-{
-    QXLReleaseRing *ring = &d->ram->release_ring;
-    uint64_t *item;
-    int notify;
-
-#define QXL_FREE_BUNCH_SIZE 32
-
-    if (ring->prod - ring->cons + 1 == ring->num_items) {
-        /* ring full -- can't push */
-        return;
-    }
-    if (!flush && d->oom_running) {
-        /* collect everything from oom handler before pushing */
-        return;
-    }
-    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
-        /* collect a bit more before pushing */
-        return;
-    }
-
-    SPICE_RING_PUSH(ring, notify);
-    trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode),
-           d->guest_surfaces.count, d->num_free_res,
-           d->last_release, notify ? "yes" : "no");
-    trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons,
-           ring->num_items, ring->prod, ring->cons);
-    if (notify) {
-        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
-    }
-    SPICE_RING_PROD_ITEM(d, ring, item);
-    if (!item) {
-        return;
-    }
-    *item = 0;
-    d->num_free_res = 0;
-    d->last_release = NULL;
-    qxl_ring_set_dirty(d);
-}
-
-/* called from spice server thread context only */
-static void interface_release_resource(QXLInstance *sin,
-                                       struct QXLReleaseInfoExt ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLReleaseRing *ring;
-    uint64_t *item, id;
-
-    if (ext.group_id == MEMSLOT_GROUP_HOST) {
-        /* host group -> vga mode update request */
-        qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id);
-        return;
-    }
-
-    /*
-     * ext->info points into guest-visible memory
-     * pci bar 0, $command.release_info
-     */
-    ring = &qxl->ram->release_ring;
-    SPICE_RING_PROD_ITEM(qxl, ring, item);
-    if (!item) {
-        return;
-    }
-    if (*item == 0) {
-        /* stick head into the ring */
-        id = ext.info->id;
-        ext.info->next = 0;
-        qxl_ram_set_dirty(qxl, &ext.info->next);
-        *item = id;
-        qxl_ring_set_dirty(qxl);
-    } else {
-        /* append item to the list */
-        qxl->last_release->next = ext.info->id;
-        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
-        ext.info->next = 0;
-        qxl_ram_set_dirty(qxl, &ext.info->next);
-    }
-    qxl->last_release = ext.info;
-    qxl->num_free_res++;
-    trace_qxl_ring_res_put(qxl->id, qxl->num_free_res);
-    qxl_push_free_res(qxl, 0);
-}
-
-/* called from spice server thread context only */
-static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLCursorRing *ring;
-    QXLCommand *cmd;
-    int notify;
-
-    trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        ring = &qxl->ram->cursor_ring;
-        if (SPICE_RING_IS_EMPTY(ring)) {
-            return false;
-        }
-        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
-        if (!cmd) {
-            return false;
-        }
-        ext->cmd      = *cmd;
-        ext->group_id = MEMSLOT_GROUP_GUEST;
-        ext->flags    = qxl->cmdflags;
-        SPICE_RING_POP(ring, notify);
-        qxl_ring_set_dirty(qxl);
-        if (notify) {
-            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
-        }
-        qxl->guest_primary.commands++;
-        qxl_track_command(qxl, ext);
-        qxl_log_command(qxl, "csr", ext);
-        if (qxl->id == 0) {
-            qxl_render_cursor(qxl, ext);
-        }
-        trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
-        return true;
-    default:
-        return false;
-    }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cursor_notification(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int wait = 1;
-
-    trace_qxl_ring_cursor_req_notification(qxl->id);
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
-        qxl_ring_set_dirty(qxl);
-        break;
-    default:
-        /* nothing */
-        break;
-    }
-    return wait;
-}
-
-/* called from spice server thread context */
-static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
-{
-    /*
-     * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in
-     * use by xf86-video-qxl and is defined out in the qxl windows driver.
-     * Probably was at some earlier version that is prior to git start (2009),
-     * and is still guest trigerrable.
-     */
-    fprintf(stderr, "%s: deprecated\n", __func__);
-}
-
-/* called from spice server thread context only */
-static int interface_flush_resources(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int ret;
-
-    ret = qxl->num_free_res;
-    if (ret) {
-        qxl_push_free_res(qxl, 1);
-    }
-    return ret;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
-
-/* called from spice server thread context only */
-static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
-    uint32_t current_async;
-
-    qemu_mutex_lock(&qxl->async_lock);
-    current_async = qxl->current_async;
-    qxl->current_async = QXL_UNDEFINED_IO;
-    qemu_mutex_unlock(&qxl->async_lock);
-
-    trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie);
-    if (!cookie) {
-        fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__);
-        return;
-    }
-    if (cookie && current_async != cookie->io) {
-        fprintf(stderr,
-                "qxl: %s: error: current_async = %d != %"
-                PRId64 " = cookie->io\n", __func__, current_async, cookie->io);
-    }
-    switch (current_async) {
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-    case QXL_IO_DESTROY_PRIMARY_ASYNC:
-    case QXL_IO_UPDATE_AREA_ASYNC:
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-        break;
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        qxl_create_guest_primary_complete(qxl);
-        break;
-    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-        qxl_spice_destroy_surfaces_complete(qxl);
-        break;
-    case QXL_IO_DESTROY_SURFACE_ASYNC:
-        qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
-        break;
-    default:
-        fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
-                current_async);
-    }
-    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
-}
-
-/* called from spice server thread context only */
-static void interface_update_area_complete(QXLInstance *sin,
-        uint32_t surface_id,
-        QXLRect *dirty, uint32_t num_updated_rects)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int i;
-    int qxl_i;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-    if (surface_id != 0 || !qxl->render_update_cookie_num) {
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-    trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
-            dirty->right, dirty->top, dirty->bottom);
-    trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects);
-    if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) {
-        /*
-         * overflow - treat this as a full update. Not expected to be common.
-         */
-        trace_qxl_interface_update_area_complete_overflow(qxl->id,
-                                                          QXL_NUM_DIRTY_RECTS);
-        qxl->guest_primary.resized = 1;
-    }
-    if (qxl->guest_primary.resized) {
-        /*
-         * Don't bother copying or scheduling the bh since we will flip
-         * the whole area anyway on completion of the update_area async call
-         */
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-    qxl_i = qxl->num_dirty_rects;
-    for (i = 0; i < num_updated_rects; i++) {
-        qxl->dirty[qxl_i++] = dirty[i];
-    }
-    qxl->num_dirty_rects += num_updated_rects;
-    trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
-                                                         qxl->num_dirty_rects);
-    qemu_bh_schedule(qxl->update_area_bh);
-    qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-/* called from spice server thread context only */
-static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
-
-    switch (cookie->type) {
-    case QXL_COOKIE_TYPE_IO:
-        interface_async_complete_io(qxl, cookie);
-        g_free(cookie);
-        break;
-    case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
-        qxl_render_update_area_done(qxl, cookie);
-        break;
-    case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
-        break;
-    default:
-        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
-                __func__, cookie->type);
-        g_free(cookie);
-    }
-}
-
-/* called from spice server thread context only */
-static void interface_set_client_capabilities(QXLInstance *sin,
-                                              uint8_t client_present,
-                                              uint8_t caps[58])
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    if (qxl->revision < 4) {
-        trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id,
-                                                              qxl->revision);
-        return;
-    }
-
-    if (runstate_check(RUN_STATE_INMIGRATE) ||
-        runstate_check(RUN_STATE_POSTMIGRATE)) {
-        return;
-    }
-
-    qxl->shadow_rom.client_present = client_present;
-    memcpy(qxl->shadow_rom.client_capabilities, caps,
-           sizeof(qxl->shadow_rom.client_capabilities));
-    qxl->rom->client_present = client_present;
-    memcpy(qxl->rom->client_capabilities, caps,
-           sizeof(qxl->rom->client_capabilities));
-    qxl_rom_set_dirty(qxl);
-
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
-}
-
-static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
-{
-    /*
-     * zlib xors the seed with 0xffffffff, and xors the result
-     * again with 0xffffffff; Both are not done with linux's crc32,
-     * which we want to be compatible with, so undo that.
-     */
-    return crc32(0xffffffff, p, len) ^ 0xffffffff;
-}
-
-/* called from main context only */
-static int interface_client_monitors_config(QXLInstance *sin,
-                                        VDAgentMonitorsConfig *monitors_config)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
-    int i;
-
-    if (qxl->revision < 4) {
-        trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
-                                                               qxl->revision);
-        return 0;
-    }
-    /*
-     * Older windows drivers set int_mask to 0 when their ISR is called,
-     * then later set it to ~0. So it doesn't relate to the actual interrupts
-     * handled. However, they are old, so clearly they don't support this
-     * interrupt
-     */
-    if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
-        !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
-        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
-                                                            qxl->ram->int_mask,
-                                                            monitors_config);
-        return 0;
-    }
-    if (!monitors_config) {
-        return 1;
-    }
-    memset(&rom->client_monitors_config, 0,
-           sizeof(rom->client_monitors_config));
-    rom->client_monitors_config.count = monitors_config->num_of_monitors;
-    /* monitors_config->flags ignored */
-    if (rom->client_monitors_config.count >=
-            ARRAY_SIZE(rom->client_monitors_config.heads)) {
-        trace_qxl_client_monitors_config_capped(qxl->id,
-                                monitors_config->num_of_monitors,
-                                ARRAY_SIZE(rom->client_monitors_config.heads));
-        rom->client_monitors_config.count =
-            ARRAY_SIZE(rom->client_monitors_config.heads);
-    }
-    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
-        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
-        QXLURect *rect = &rom->client_monitors_config.heads[i];
-        /* monitor->depth ignored */
-        rect->left = monitor->x;
-        rect->top = monitor->y;
-        rect->right = monitor->x + monitor->width;
-        rect->bottom = monitor->y + monitor->height;
-    }
-    rom->client_monitors_config_crc = qxl_crc32(
-            (const uint8_t *)&rom->client_monitors_config,
-            sizeof(rom->client_monitors_config));
-    trace_qxl_client_monitors_config_crc(qxl->id,
-            sizeof(rom->client_monitors_config),
-            rom->client_monitors_config_crc);
-
-    trace_qxl_interrupt_client_monitors_config(qxl->id,
-                        rom->client_monitors_config.count,
-                        rom->client_monitors_config.heads);
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
-    return 1;
-}
-
-static const QXLInterface qxl_interface = {
-    .base.type               = SPICE_INTERFACE_QXL,
-    .base.description        = "qxl gpu",
-    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
-    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
-
-    .attache_worker          = interface_attach_worker,
-    .set_compression_level   = interface_set_compression_level,
-    .set_mm_time             = interface_set_mm_time,
-    .get_init_info           = interface_get_init_info,
-
-    /* the callbacks below are called from spice server thread context */
-    .get_command             = interface_get_command,
-    .req_cmd_notification    = interface_req_cmd_notification,
-    .release_resource        = interface_release_resource,
-    .get_cursor_command      = interface_get_cursor_command,
-    .req_cursor_notification = interface_req_cursor_notification,
-    .notify_update           = interface_notify_update,
-    .flush_resources         = interface_flush_resources,
-    .async_complete          = interface_async_complete,
-    .update_area_complete    = interface_update_area_complete,
-    .set_client_capabilities = interface_set_client_capabilities,
-    .client_monitors_config = interface_client_monitors_config,
-};
-
-static void qxl_enter_vga_mode(PCIQXLDevice *d)
-{
-    if (d->mode == QXL_MODE_VGA) {
-        return;
-    }
-    trace_qxl_enter_vga_mode(d->id);
-    qemu_spice_create_host_primary(&d->ssd);
-    d->mode = QXL_MODE_VGA;
-    vga_dirty_log_start(&d->vga);
-    vga_hw_update();
-}
-
-static void qxl_exit_vga_mode(PCIQXLDevice *d)
-{
-    if (d->mode != QXL_MODE_VGA) {
-        return;
-    }
-    trace_qxl_exit_vga_mode(d->id);
-    vga_dirty_log_stop(&d->vga);
-    qxl_destroy_primary(d, QXL_SYNC);
-}
-
-static void qxl_update_irq(PCIQXLDevice *d)
-{
-    uint32_t pending = le32_to_cpu(d->ram->int_pending);
-    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
-    int level = !!(pending & mask);
-    qemu_set_irq(d->pci.irq[0], level);
-    qxl_ring_set_dirty(d);
-}
-
-static void qxl_check_state(PCIQXLDevice *d)
-{
-    QXLRam *ram = d->ram;
-    int spice_display_running = qemu_spice_display_is_running(&d->ssd);
-
-    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
-    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
-}
-
-static void qxl_reset_state(PCIQXLDevice *d)
-{
-    QXLRom *rom = d->rom;
-
-    qxl_check_state(d);
-    d->shadow_rom.update_id = cpu_to_le32(0);
-    *rom = d->shadow_rom;
-    qxl_rom_set_dirty(d);
-    init_qxl_ram(d);
-    d->num_free_res = 0;
-    d->last_release = NULL;
-    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
-}
-
-static void qxl_soft_reset(PCIQXLDevice *d)
-{
-    trace_qxl_soft_reset(d->id);
-    qxl_check_state(d);
-    qxl_clear_guest_bug(d);
-    d->current_async = QXL_UNDEFINED_IO;
-
-    if (d->id == 0) {
-        qxl_enter_vga_mode(d);
-    } else {
-        d->mode = QXL_MODE_UNDEFINED;
-    }
-}
-
-static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
-{
-    trace_qxl_hard_reset(d->id, loadvm);
-
-    qxl_spice_reset_cursor(d);
-    qxl_spice_reset_image_cache(d);
-    qxl_reset_surfaces(d);
-    qxl_reset_memslots(d);
-
-    /* pre loadvm reset must not touch QXLRam.  This lives in
-     * device memory, is migrated together with RAM and thus
-     * already loaded at this point */
-    if (!loadvm) {
-        qxl_reset_state(d);
-    }
-    qemu_spice_create_host_memslot(&d->ssd);
-    qxl_soft_reset(d);
-}
-
-static void qxl_reset_handler(DeviceState *dev)
-{
-    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
-
-    qxl_hard_reset(d, 0);
-}
-
-static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *vga = opaque;
-    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
-
-    trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val);
-    if (qxl->mode != QXL_MODE_VGA) {
-        qxl_destroy_primary(qxl, QXL_SYNC);
-        qxl_soft_reset(qxl);
-    }
-    vga_ioport_write(opaque, addr, val);
-}
-
-static const MemoryRegionPortio qxl_vga_portio_list[] = {
-    { 0x04,  2, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3b4 */
-    { 0x0a,  1, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3ba */
-    { 0x10, 16, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3c0 */
-    { 0x24,  2, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3d4 */
-    { 0x2a,  1, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3da */
-    PORTIO_END_OF_LIST(),
-};
-
-static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
-                           qxl_async_io async)
-{
-    static const int regions[] = {
-        QXL_RAM_RANGE_INDEX,
-        QXL_VRAM_RANGE_INDEX,
-        QXL_VRAM64_RANGE_INDEX,
-    };
-    uint64_t guest_start;
-    uint64_t guest_end;
-    int pci_region;
-    pcibus_t pci_start;
-    pcibus_t pci_end;
-    intptr_t virt_start;
-    QXLDevMemSlot memslot;
-    int i;
-
-    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
-    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
-
-    trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end);
-
-    if (slot_id >= NUM_MEMSLOTS) {
-        qxl_set_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__,
-                      slot_id, NUM_MEMSLOTS);
-        return 1;
-    }
-    if (guest_start > guest_end) {
-        qxl_set_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64
-                         " > 0x%" PRIx64, __func__, guest_start, guest_end);
-        return 1;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(regions); i++) {
-        pci_region = regions[i];
-        pci_start = d->pci.io_regions[pci_region].addr;
-        pci_end = pci_start + d->pci.io_regions[pci_region].size;
-        /* mapped? */
-        if (pci_start == -1) {
-            continue;
-        }
-        /* start address in range ? */
-        if (guest_start < pci_start || guest_start > pci_end) {
-            continue;
-        }
-        /* end address in range ? */
-        if (guest_end > pci_end) {
-            continue;
-        }
-        /* passed */
-        break;
-    }
-    if (i == ARRAY_SIZE(regions)) {
-        qxl_set_guest_bug(d, "%s: finished loop without match", __func__);
-        return 1;
-    }
-
-    switch (pci_region) {
-    case QXL_RAM_RANGE_INDEX:
-        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
-        break;
-    case QXL_VRAM_RANGE_INDEX:
-    case 4 /* vram 64bit */:
-        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
-        break;
-    default:
-        /* should not happen */
-        qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region);
-        return 1;
-    }
-
-    memslot.slot_id = slot_id;
-    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
-    memslot.virt_start = virt_start + (guest_start - pci_start);
-    memslot.virt_end   = virt_start + (guest_end   - pci_start);
-    memslot.addr_delta = memslot.virt_start - delta;
-    memslot.generation = d->rom->slot_generation = 0;
-    qxl_rom_set_dirty(d);
-
-    qemu_spice_add_memslot(&d->ssd, &memslot, async);
-    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
-    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
-    d->guest_slots[slot_id].delta = delta;
-    d->guest_slots[slot_id].active = 1;
-    return 0;
-}
-
-static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
-{
-    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
-    d->guest_slots[slot_id].active = 0;
-}
-
-static void qxl_reset_memslots(PCIQXLDevice *d)
-{
-    qxl_spice_reset_memslots(d);
-    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
-}
-
-static void qxl_reset_surfaces(PCIQXLDevice *d)
-{
-    trace_qxl_reset_surfaces(d->id);
-    d->mode = QXL_MODE_UNDEFINED;
-    qxl_spice_destroy_surfaces(d, QXL_SYNC);
-}
-
-/* can be also called from spice server thread context */
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
-{
-    uint64_t phys   = le64_to_cpu(pqxl);
-    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
-    uint64_t offset = phys & 0xffffffffffff;
-
-    switch (group_id) {
-    case MEMSLOT_GROUP_HOST:
-        return (void *)(intptr_t)offset;
-    case MEMSLOT_GROUP_GUEST:
-        if (slot >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
-                              NUM_MEMSLOTS);
-            return NULL;
-        }
-        if (!qxl->guest_slots[slot].active) {
-            qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
-            return NULL;
-        }
-        if (offset < qxl->guest_slots[slot].delta) {
-            qxl_set_guest_bug(qxl,
-                          "slot %d offset %"PRIu64" < delta %"PRIu64"\n",
-                          slot, offset, qxl->guest_slots[slot].delta);
-            return NULL;
-        }
-        offset -= qxl->guest_slots[slot].delta;
-        if (offset > qxl->guest_slots[slot].size) {
-            qxl_set_guest_bug(qxl,
-                          "slot %d offset %"PRIu64" > size %"PRIu64"\n",
-                          slot, offset, qxl->guest_slots[slot].size);
-            return NULL;
-        }
-        return qxl->guest_slots[slot].ptr + offset;
-    }
-    return NULL;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
-{
-    /* for local rendering */
-    qxl_render_resize(qxl);
-}
-
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
-                                     qxl_async_io async)
-{
-    QXLDevSurfaceCreate surface;
-    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-    int size;
-    int requested_height = le32_to_cpu(sc->height);
-    int requested_stride = le32_to_cpu(sc->stride);
-
-    size = abs(requested_stride) * requested_height;
-    if (size > qxl->vgamem_size) {
-        qxl_set_guest_bug(qxl, "%s: requested primary larger then framebuffer"
-                               " size", __func__);
-        return;
-    }
-
-    if (qxl->mode == QXL_MODE_NATIVE) {
-        qxl_set_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE",
-                      __func__);
-    }
-    qxl_exit_vga_mode(qxl);
-
-    surface.format     = le32_to_cpu(sc->format);
-    surface.height     = le32_to_cpu(sc->height);
-    surface.mem        = le64_to_cpu(sc->mem);
-    surface.position   = le32_to_cpu(sc->position);
-    surface.stride     = le32_to_cpu(sc->stride);
-    surface.width      = le32_to_cpu(sc->width);
-    surface.type       = le32_to_cpu(sc->type);
-    surface.flags      = le32_to_cpu(sc->flags);
-    trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem,
-                                   sc->format, sc->position);
-    trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
-                                        sc->flags);
-
-    if ((surface.stride & 0x3) != 0) {
-        qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
-                          surface.stride);
-        return;
-    }
-
-    surface.mouse_mode = true;
-    surface.group_id   = MEMSLOT_GROUP_GUEST;
-    if (loadvm) {
-        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
-    }
-
-    qxl->mode = QXL_MODE_NATIVE;
-    qxl->cmdflags = 0;
-    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
-
-    if (async == QXL_SYNC) {
-        qxl_create_guest_primary_complete(qxl);
-    }
-}
-
-/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
- * done (in QXL_SYNC case), 0 otherwise. */
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
-{
-    if (d->mode == QXL_MODE_UNDEFINED) {
-        return 0;
-    }
-    trace_qxl_destroy_primary(d->id);
-    d->mode = QXL_MODE_UNDEFINED;
-    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
-    qxl_spice_reset_cursor(d);
-    return 1;
-}
-
-static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
-{
-    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
-    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
-    QXLMode *mode = d->modes->modes + modenr;
-    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
-    QXLMemSlot slot = {
-        .mem_start = start,
-        .mem_end = end
-    };
-    QXLSurfaceCreate surface = {
-        .width      = mode->x_res,
-        .height     = mode->y_res,
-        .stride     = -mode->x_res * 4,
-        .format     = SPICE_SURFACE_FMT_32_xRGB,
-        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
-        .mouse_mode = true,
-        .mem        = devmem + d->shadow_rom.draw_area_offset,
-    };
-
-    trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits,
-                       devmem);
-    if (!loadvm) {
-        qxl_hard_reset(d, 0);
-    }
-
-    d->guest_slots[0].slot = slot;
-    assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0);
-
-    d->guest_primary.surface = surface;
-    qxl_create_guest_primary(d, 0, QXL_SYNC);
-
-    d->mode = QXL_MODE_COMPAT;
-    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
-    if (mode->bits == 16) {
-        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
-    }
-    d->shadow_rom.mode = cpu_to_le32(modenr);
-    d->rom->mode = cpu_to_le32(modenr);
-    qxl_rom_set_dirty(d);
-}
-
-static void ioport_write(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-    PCIQXLDevice *d = opaque;
-    uint32_t io_port = addr;
-    qxl_async_io async = QXL_SYNC;
-    uint32_t orig_io_port = io_port;
-
-    if (d->guest_bug && io_port != QXL_IO_RESET) {
-        return;
-    }
-
-    if (d->revision <= QXL_REVISION_STABLE_V10 &&
-        io_port > QXL_IO_FLUSH_RELEASE) {
-        qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
-            io_port, d->revision);
-        return;
-    }
-
-    switch (io_port) {
-    case QXL_IO_RESET:
-    case QXL_IO_SET_MODE:
-    case QXL_IO_MEMSLOT_ADD:
-    case QXL_IO_MEMSLOT_DEL:
-    case QXL_IO_CREATE_PRIMARY:
-    case QXL_IO_UPDATE_IRQ:
-    case QXL_IO_LOG:
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        break;
-    default:
-        if (d->mode != QXL_MODE_VGA) {
-            break;
-        }
-        trace_qxl_io_unexpected_vga_mode(d->id,
-            addr, val, io_port_to_string(io_port));
-        /* be nice to buggy guest drivers */
-        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
-            io_port < QXL_IO_RANGE_SIZE) {
-            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-        }
-        return;
-    }
-
-    /* we change the io_port to avoid ifdeffery in the main switch */
-    orig_io_port = io_port;
-    switch (io_port) {
-    case QXL_IO_UPDATE_AREA_ASYNC:
-        io_port = QXL_IO_UPDATE_AREA;
-        goto async_common;
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-        io_port = QXL_IO_MEMSLOT_ADD;
-        goto async_common;
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        io_port = QXL_IO_CREATE_PRIMARY;
-        goto async_common;
-    case QXL_IO_DESTROY_PRIMARY_ASYNC:
-        io_port = QXL_IO_DESTROY_PRIMARY;
-        goto async_common;
-    case QXL_IO_DESTROY_SURFACE_ASYNC:
-        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
-        goto async_common;
-    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-        io_port = QXL_IO_DESTROY_ALL_SURFACES;
-        goto async_common;
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-async_common:
-        async = QXL_ASYNC;
-        qemu_mutex_lock(&d->async_lock);
-        if (d->current_async != QXL_UNDEFINED_IO) {
-            qxl_set_guest_bug(d, "%d async started before last (%d) complete",
-                io_port, d->current_async);
-            qemu_mutex_unlock(&d->async_lock);
-            return;
-        }
-        d->current_async = orig_io_port;
-        qemu_mutex_unlock(&d->async_lock);
-        break;
-    default:
-        break;
-    }
-    trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size,
-                       async);
-
-    switch (io_port) {
-    case QXL_IO_UPDATE_AREA:
-    {
-        QXLCookie *cookie = NULL;
-        QXLRect update = d->ram->update_area;
-
-        if (d->ram->update_surface > d->ssd.num_surfaces) {
-            qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
-                              d->ram->update_surface);
-            break;
-        }
-        if (update.left >= update.right || update.top >= update.bottom ||
-            update.left < 0 || update.top < 0) {
-            qxl_set_guest_bug(d,
-                    "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
-                    update.left, update.top, update.right, update.bottom);
-            break;
-        }
-        if (async == QXL_ASYNC) {
-            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                    QXL_IO_UPDATE_AREA_ASYNC);
-            cookie->u.area = update;
-        }
-        qxl_spice_update_area(d, d->ram->update_surface,
-                              cookie ? &cookie->u.area : &update,
-                              NULL, 0, 0, async, cookie);
-        break;
-    }
-    case QXL_IO_NOTIFY_CMD:
-        qemu_spice_wakeup(&d->ssd);
-        break;
-    case QXL_IO_NOTIFY_CURSOR:
-        qemu_spice_wakeup(&d->ssd);
-        break;
-    case QXL_IO_UPDATE_IRQ:
-        qxl_update_irq(d);
-        break;
-    case QXL_IO_NOTIFY_OOM:
-        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
-            break;
-        }
-        d->oom_running = 1;
-        qxl_spice_oom(d);
-        d->oom_running = 0;
-        break;
-    case QXL_IO_SET_MODE:
-        qxl_set_mode(d, val, 0);
-        break;
-    case QXL_IO_LOG:
-        trace_qxl_io_log(d->id, d->ram->log_buf);
-        if (d->guestdebug) {
-            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
-                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
-        }
-        break;
-    case QXL_IO_RESET:
-        qxl_hard_reset(d, 0);
-        break;
-    case QXL_IO_MEMSLOT_ADD:
-        if (val >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
-            break;
-        }
-        if (d->guest_slots[val].active) {
-            qxl_set_guest_bug(d,
-                        "QXL_IO_MEMSLOT_ADD: memory slot already active");
-            break;
-        }
-        d->guest_slots[val].slot = d->ram->mem_slot;
-        qxl_add_memslot(d, val, 0, async);
-        break;
-    case QXL_IO_MEMSLOT_DEL:
-        if (val >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
-            break;
-        }
-        qxl_del_memslot(d, val);
-        break;
-    case QXL_IO_CREATE_PRIMARY:
-        if (val != 0) {
-            qxl_set_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
-                          async);
-            goto cancel_async;
-        }
-        d->guest_primary.surface = d->ram->create_surface;
-        qxl_create_guest_primary(d, 0, async);
-        break;
-    case QXL_IO_DESTROY_PRIMARY:
-        if (val != 0) {
-            qxl_set_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
-                          async);
-            goto cancel_async;
-        }
-        if (!qxl_destroy_primary(d, async)) {
-            trace_qxl_io_destroy_primary_ignored(d->id,
-                                                 qxl_mode_to_string(d->mode));
-            goto cancel_async;
-        }
-        break;
-    case QXL_IO_DESTROY_SURFACE_WAIT:
-        if (val >= d->ssd.num_surfaces) {
-            qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
-                             "%" PRIu64 " >= NUM_SURFACES", async, val);
-            goto cancel_async;
-        }
-        qxl_spice_destroy_surface_wait(d, val, async);
-        break;
-    case QXL_IO_FLUSH_RELEASE: {
-        QXLReleaseRing *ring = &d->ram->release_ring;
-        if (ring->prod - ring->cons + 1 == ring->num_items) {
-            fprintf(stderr,
-                "ERROR: no flush, full release ring [p%d,%dc]\n",
-                ring->prod, ring->cons);
-        }
-        qxl_push_free_res(d, 1 /* flush */);
-        break;
-    }
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-        qxl_spice_flush_surfaces_async(d);
-        break;
-    case QXL_IO_DESTROY_ALL_SURFACES:
-        d->mode = QXL_MODE_UNDEFINED;
-        qxl_spice_destroy_surfaces(d, async);
-        break;
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-        qxl_spice_monitors_config_async(d, 0);
-        break;
-    default:
-        qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
-    }
-    return;
-cancel_async:
-    if (async) {
-        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-        qemu_mutex_lock(&d->async_lock);
-        d->current_async = QXL_UNDEFINED_IO;
-        qemu_mutex_unlock(&d->async_lock);
-    }
-}
-
-static uint64_t ioport_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    trace_qxl_io_read_unexpected(qxl->id);
-    return 0xff;
-}
-
-static const MemoryRegionOps qxl_io_ops = {
-    .read = ioport_read,
-    .write = ioport_write,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void pipe_read(void *opaque)
-{
-    PCIQXLDevice *d = opaque;
-    char dummy;
-    int len;
-
-    do {
-        len = read(d->pipe[0], &dummy, sizeof(dummy));
-    } while (len == sizeof(dummy));
-    qxl_update_irq(d);
-}
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
-{
-    uint32_t old_pending;
-    uint32_t le_events = cpu_to_le32(events);
-
-    trace_qxl_send_events(d->id, events);
-    if (!qemu_spice_display_is_running(&d->ssd)) {
-        /* spice-server tracks guest running state and should not do this */
-        fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
-                __func__);
-        trace_qxl_send_events_vm_stopped(d->id, events);
-        return;
-    }
-    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
-    if ((old_pending & le_events) == le_events) {
-        return;
-    }
-    if (qemu_thread_is_self(&d->main)) {
-        qxl_update_irq(d);
-    } else {
-        if (write(d->pipe[1], d, 1) != 1) {
-            dprint(d, 1, "%s: write to pipe failed\n", __func__);
-        }
-    }
-}
-
-static void init_pipe_signaling(PCIQXLDevice *d)
-{
-    if (pipe(d->pipe) < 0) {
-        fprintf(stderr, "%s:%s: qxl pipe creation failed\n",
-                __FILE__, __func__);
-        exit(1);
-    }
-    fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
-    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
-    fcntl(d->pipe[0], F_SETOWN, getpid());
-
-    qemu_thread_get_self(&d->main);
-    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
-}
-
-/* graphics console */
-
-static void qxl_hw_update(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    switch (qxl->mode) {
-    case QXL_MODE_VGA:
-        vga->update(vga);
-        break;
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
-        break;
-    default:
-        break;
-    }
-}
-
-static void qxl_hw_invalidate(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    vga->invalidate(vga);
-}
-
-static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
-                               Error **errp)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
-        ppm_save(filename, qxl->ssd.ds, errp);
-        break;
-    case QXL_MODE_VGA:
-        vga->screen_dump(vga, filename, cswitch, errp);
-        break;
-    default:
-        break;
-    }
-}
-
-static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        vga->text_update(vga, chardata);
-        return;
-    }
-}
-
-static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
-{
-    uintptr_t vram_start;
-    int i;
-
-    if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
-        return;
-    }
-
-    /* dirty the primary surface */
-    qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
-                  qxl->shadow_rom.surface0_area_size);
-
-    vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
-
-    /* dirty the off-screen surfaces */
-    for (i = 0; i < qxl->ssd.num_surfaces; i++) {
-        QXLSurfaceCmd *cmd;
-        intptr_t surface_offset;
-        int surface_size;
-
-        if (qxl->guest_surfaces.cmds[i] == 0) {
-            continue;
-        }
-
-        cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
-                            MEMSLOT_GROUP_GUEST);
-        assert(cmd);
-        assert(cmd->type == QXL_SURFACE_CMD_CREATE);
-        surface_offset = (intptr_t)qxl_phys2virt(qxl,
-                                                 cmd->u.surface_create.data,
-                                                 MEMSLOT_GROUP_GUEST);
-        assert(surface_offset);
-        surface_offset -= vram_start;
-        surface_size = cmd->u.surface_create.height *
-                       abs(cmd->u.surface_create.stride);
-        trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
-        qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
-    }
-}
-
-static void qxl_vm_change_state_handler(void *opaque, int running,
-                                        RunState state)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    if (running) {
-        /*
-         * if qxl_send_events was called from spice server context before
-         * migration ended, qxl_update_irq for these events might not have been
-         * called
-         */
-         qxl_update_irq(qxl);
-    } else {
-        /* make sure surfaces are saved before migration */
-        qxl_dirty_surfaces(qxl);
-    }
-}
-
-/* display change listener */
-
-static void display_update(DisplayChangeListener *dcl,
-                           int x, int y, int w, int h)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_update(&qxl->ssd, x, y, w, h);
-    }
-}
-
-static void display_switch(DisplayChangeListener *dcl,
-                           struct DisplaySurface *surface)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    qxl->ssd.ds = surface;
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_switch(&qxl->ssd, surface);
-    }
-}
-
-static void display_refresh(DisplayChangeListener *dcl)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_refresh(&qxl->ssd);
-    } else {
-        qemu_mutex_lock(&qxl->ssd.lock);
-        qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
-        qemu_mutex_unlock(&qxl->ssd.lock);
-    }
-}
-
-static DisplayChangeListenerOps display_listener_ops = {
-    .dpy_name        = "spice/qxl",
-    .dpy_gfx_update  = display_update,
-    .dpy_gfx_switch  = display_switch,
-    .dpy_refresh     = display_refresh,
-};
-
-static void qxl_init_ramsize(PCIQXLDevice *qxl)
-{
-    /* vga mode framebuffer / primary surface (bar 0, first part) */
-    if (qxl->vgamem_size_mb < 8) {
-        qxl->vgamem_size_mb = 8;
-    }
-    qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024;
-
-    /* vga ram (bar 0, total) */
-    if (qxl->ram_size_mb != -1) {
-        qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
-    }
-    if (qxl->vga.vram_size < qxl->vgamem_size * 2) {
-        qxl->vga.vram_size = qxl->vgamem_size * 2;
-    }
-
-    /* vram32 (surfaces, 32bit, bar 1) */
-    if (qxl->vram32_size_mb != -1) {
-        qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024;
-    }
-    if (qxl->vram32_size < 4096) {
-        qxl->vram32_size = 4096;
-    }
-
-    /* vram (surfaces, 64bit, bar 4+5) */
-    if (qxl->vram_size_mb != -1) {
-        qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
-    }
-    if (qxl->vram_size < qxl->vram32_size) {
-        qxl->vram_size = qxl->vram32_size;
-    }
-
-    if (qxl->revision == 1) {
-        qxl->vram32_size = 4096;
-        qxl->vram_size = 4096;
-    }
-    qxl->vgamem_size = msb_mask(qxl->vgamem_size * 2 - 1);
-    qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
-    qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1);
-    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
-}
-
-static int qxl_init_common(PCIQXLDevice *qxl)
-{
-    uint8_t* config = qxl->pci.config;
-    uint32_t pci_device_rev;
-    uint32_t io_size;
-
-    qxl->mode = QXL_MODE_UNDEFINED;
-    qxl->generation = 1;
-    qxl->num_memslots = NUM_MEMSLOTS;
-    qemu_mutex_init(&qxl->track_lock);
-    qemu_mutex_init(&qxl->async_lock);
-    qxl->current_async = QXL_UNDEFINED_IO;
-    qxl->guest_bug = 0;
-
-    switch (qxl->revision) {
-    case 1: /* spice 0.4 -- qxl-1 */
-        pci_device_rev = QXL_REVISION_STABLE_V04;
-        io_size = 8;
-        break;
-    case 2: /* spice 0.6 -- qxl-2 */
-        pci_device_rev = QXL_REVISION_STABLE_V06;
-        io_size = 16;
-        break;
-    case 3: /* qxl-3 */
-        pci_device_rev = QXL_REVISION_STABLE_V10;
-        io_size = 32; /* PCI region size must be pow2 */
-        break;
-    case 4: /* qxl-4 */
-        pci_device_rev = QXL_REVISION_STABLE_V12;
-        io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
-        break;
-    default:
-        error_report("Invalid revision %d for qxl device (max %d)",
-                     qxl->revision, QXL_DEFAULT_REVISION);
-        return -1;
-    }
-
-    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
-    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
-
-    qxl->rom_size = qxl_rom_size();
-    memory_region_init_ram(&qxl->rom_bar, "qxl.vrom", qxl->rom_size);
-    vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
-    init_qxl_rom(qxl);
-    init_qxl_ram(qxl);
-
-    qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
-    memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
-    vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
-    memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
-                             0, qxl->vram32_size);
-
-    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
-                          "qxl-ioports", io_size);
-    if (qxl->id == 0) {
-        vga_dirty_log_start(&qxl->vga);
-    }
-    memory_region_set_flush_coalesced(&qxl->io_bar);
-
-
-    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
-
-    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
-
-    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
-
-    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar);
-
-    if (qxl->vram32_size < qxl->vram_size) {
-        /*
-         * Make the 64bit vram bar show up only in case it is
-         * configured to be larger than the 32bit vram bar.
-         */
-        pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX,
-                         PCI_BASE_ADDRESS_SPACE_MEMORY |
-                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
-                         PCI_BASE_ADDRESS_MEM_PREFETCH,
-                         &qxl->vram_bar);
-    }
-
-    /* print pci bar details */
-    dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
-           qxl->id == 0 ? "pri" : "sec",
-           qxl->vga.vram_size / (1024*1024));
-    dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
-           qxl->vram32_size / (1024*1024));
-    dprint(qxl, 1, "vram/64: %d MB %s\n",
-           qxl->vram_size / (1024*1024),
-           qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
-
-    qxl->ssd.qxl.base.sif = &qxl_interface.base;
-    qxl->ssd.qxl.id = qxl->id;
-    if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) {
-        error_report("qxl interface %d.%d not supported by spice-server",
-                     SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR);
-        return -1;
-    }
-    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
-
-    init_pipe_signaling(qxl);
-    qxl_reset_state(qxl);
-
-    qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
-
-    return 0;
-}
-
-static int qxl_init_primary(PCIDevice *dev)
-{
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
-    VGACommonState *vga = &qxl->vga;
-    PortioList *qxl_vga_port_list = g_new(PortioList, 1);
-    DisplayState *ds;
-    int rc;
-
-    qxl->id = 0;
-    qxl_init_ramsize(qxl);
-    vga->vram_size_mb = qxl->vga.vram_size >> 20;
-    vga_common_init(vga);
-    vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
-    portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
-    portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
-
-    vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
-                                    qxl_hw_screen_dump, qxl_hw_text_update,
-                                    qxl);
-    qxl->ssd.con = vga->con,
-    qemu_spice_display_init_common(&qxl->ssd);
-
-    rc = qxl_init_common(qxl);
-    if (rc != 0) {
-        return rc;
-    }
-
-    qxl->ssd.dcl.ops = &display_listener_ops;
-    ds = qemu_console_displaystate(vga->con);
-    register_displaychangelistener(ds, &qxl->ssd.dcl);
-    return rc;
-}
-
-static int qxl_init_secondary(PCIDevice *dev)
-{
-    static int device_id = 1;
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
-
-    qxl->id = device_id++;
-    qxl_init_ramsize(qxl);
-    memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size);
-    vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
-    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
-
-    return qxl_init_common(qxl);
-}
-
-static void qxl_pre_save(void *opaque)
-{
-    PCIQXLDevice* d = opaque;
-    uint8_t *ram_start = d->vga.vram_ptr;
-
-    trace_qxl_pre_save(d->id);
-    if (d->last_release == NULL) {
-        d->last_release_offset = 0;
-    } else {
-        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
-    }
-    assert(d->last_release_offset < d->vga.vram_size);
-}
-
-static int qxl_pre_load(void *opaque)
-{
-    PCIQXLDevice* d = opaque;
-
-    trace_qxl_pre_load(d->id);
-    qxl_hard_reset(d, 1);
-    qxl_exit_vga_mode(d);
-    return 0;
-}
-
-static void qxl_create_memslots(PCIQXLDevice *d)
-{
-    int i;
-
-    for (i = 0; i < NUM_MEMSLOTS; i++) {
-        if (!d->guest_slots[i].active) {
-            continue;
-        }
-        qxl_add_memslot(d, i, 0, QXL_SYNC);
-    }
-}
-
-static int qxl_post_load(void *opaque, int version)
-{
-    PCIQXLDevice* d = opaque;
-    uint8_t *ram_start = d->vga.vram_ptr;
-    QXLCommandExt *cmds;
-    int in, out, newmode;
-
-    assert(d->last_release_offset < d->vga.vram_size);
-    if (d->last_release_offset == 0) {
-        d->last_release = NULL;
-    } else {
-        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
-    }
-
-    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
-
-    trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode));
-    newmode = d->mode;
-    d->mode = QXL_MODE_UNDEFINED;
-
-    switch (newmode) {
-    case QXL_MODE_UNDEFINED:
-        qxl_create_memslots(d);
-        break;
-    case QXL_MODE_VGA:
-        qxl_create_memslots(d);
-        qxl_enter_vga_mode(d);
-        break;
-    case QXL_MODE_NATIVE:
-        qxl_create_memslots(d);
-        qxl_create_guest_primary(d, 1, QXL_SYNC);
-
-        /* replay surface-create and cursor-set commands */
-        cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
-        for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
-            if (d->guest_surfaces.cmds[in] == 0) {
-                continue;
-            }
-            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
-            cmds[out].cmd.type = QXL_CMD_SURFACE;
-            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-            out++;
-        }
-        if (d->guest_cursor) {
-            cmds[out].cmd.data = d->guest_cursor;
-            cmds[out].cmd.type = QXL_CMD_CURSOR;
-            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-            out++;
-        }
-        qxl_spice_loadvm_commands(d, cmds, out);
-        g_free(cmds);
-        if (d->guest_monitors_config) {
-            qxl_spice_monitors_config_async(d, 1);
-        }
-        break;
-    case QXL_MODE_COMPAT:
-        /* note: no need to call qxl_create_memslots, qxl_set_mode
-         * creates the mem slot. */
-        qxl_set_mode(d, d->shadow_rom.mode, 1);
-        break;
-    }
-    return 0;
-}
-
-#define QXL_SAVE_VERSION 21
-
-static bool qxl_monitors_config_needed(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    return qxl->guest_monitors_config != 0;
-}
-
-
-static VMStateDescription qxl_memslot = {
-    .name               = "qxl-memslot",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
-        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
-        VMSTATE_UINT32(active,         struct guest_slots),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static VMStateDescription qxl_surface = {
-    .name               = "qxl-surface",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(width,      QXLSurfaceCreate),
-        VMSTATE_UINT32(height,     QXLSurfaceCreate),
-        VMSTATE_INT32(stride,      QXLSurfaceCreate),
-        VMSTATE_UINT32(format,     QXLSurfaceCreate),
-        VMSTATE_UINT32(position,   QXLSurfaceCreate),
-        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
-        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
-        VMSTATE_UINT32(type,       QXLSurfaceCreate),
-        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static VMStateDescription qxl_vmstate_monitors_config = {
-    .name               = "qxl/monitors-config",
-    .version_id         = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-static VMStateDescription qxl_vmstate = {
-    .name               = "qxl",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .pre_save           = qxl_pre_save,
-    .pre_load           = qxl_pre_load,
-    .post_load          = qxl_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
-        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
-        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
-        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
-        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
-        VMSTATE_UINT32(mode, PCIQXLDevice),
-        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
-        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
-        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
-                             qxl_memslot, struct guest_slots),
-        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
-                       qxl_surface, QXLSurfaceCreate),
-        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
-        VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
-                             ssd.num_surfaces, 0,
-                             vmstate_info_uint64, uint64_t),
-        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &qxl_vmstate_monitors_config,
-            .needed = qxl_monitors_config_needed,
-        }, {
-            /* empty */
-        }
-    }
-};
-
-static Property qxl_properties[] = {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-                           QXL_DEFAULT_REVISION),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
-        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
-        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
-        DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
-        DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
-        DEFINE_PROP_END_OF_LIST(),
-};
-
-static void qxl_primary_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = qxl_init_primary;
-    k->romfile = "vgabios-qxl.bin";
-    k->vendor_id = REDHAT_PCI_VENDOR_ID;
-    k->device_id = QXL_DEVICE_ID_STABLE;
-    k->class_id = PCI_CLASS_DISPLAY_VGA;
-    dc->desc = "Spice QXL GPU (primary, vga compatible)";
-    dc->reset = qxl_reset_handler;
-    dc->vmsd = &qxl_vmstate;
-    dc->props = qxl_properties;
-}
-
-static const TypeInfo qxl_primary_info = {
-    .name          = "qxl-vga",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIQXLDevice),
-    .class_init    = qxl_primary_class_init,
-};
-
-static void qxl_secondary_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = qxl_init_secondary;
-    k->vendor_id = REDHAT_PCI_VENDOR_ID;
-    k->device_id = QXL_DEVICE_ID_STABLE;
-    k->class_id = PCI_CLASS_DISPLAY_OTHER;
-    dc->desc = "Spice QXL GPU (secondary)";
-    dc->reset = qxl_reset_handler;
-    dc->vmsd = &qxl_vmstate;
-    dc->props = qxl_properties;
-}
-
-static const TypeInfo qxl_secondary_info = {
-    .name          = "qxl",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIQXLDevice),
-    .class_init    = qxl_secondary_class_init,
-};
-
-static void qxl_register_types(void)
-{
-    type_register_static(&qxl_primary_info);
-    type_register_static(&qxl_secondary_info);
-}
-
-type_init(qxl_register_types)
index efbb9ebef1a42a9c03b0514ecb3bd8404cb812dd..c9b0416b077b58013ecd5362d475f7f90959f414 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
+obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/sm501.c b/hw/sm501.c
deleted file mode 100644 (file)
index d9fcead..0000000
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*
- * QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * 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
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <stdio.h>
-#include "hw/hw.h"
-#include "hw/char/serial.h"
-#include "ui/console.h"
-#include "hw/arm/devices.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-addr.h"
-#include "qemu/range.h"
-#include "ui/pixel_ops.h"
-
-/*
- * Status: 2010/05/07
- *   - Minimum implementation for Linux console : mmio regs and CRT layer.
- *   - 2D grapihcs acceleration partially supported : only fill rectangle.
- *
- * TODO:
- *   - Panel support
- *   - Touch panel support
- *   - USB support
- *   - UART support
- *   - More 2D graphics engine support
- *   - Performance tuning
- */
-
-//#define DEBUG_SM501
-//#define DEBUG_BITBLT
-
-#ifdef DEBUG_SM501
-#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define SM501_DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-
-#define MMIO_BASE_OFFSET 0x3e00000
-
-/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
-
-/* System Configuration area */
-/* System config base */
-#define SM501_SYS_CONFIG               (0x000000)
-
-/* config 1 */
-#define SM501_SYSTEM_CONTROL           (0x000000)
-
-#define SM501_SYSCTRL_PANEL_TRISTATE   (1<<0)
-#define SM501_SYSCTRL_MEM_TRISTATE     (1<<1)
-#define SM501_SYSCTRL_CRT_TRISTATE     (1<<2)
-
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_1        (0<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_2        (1<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_4        (2<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_8        (3<<4)
-
-#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
-#define SM501_SYSCTRL_PCI_RETRY_DISABLE        (1<<7)
-#define SM501_SYSCTRL_PCI_SUBSYS_LOCK  (1<<11)
-#define SM501_SYSCTRL_PCI_BURST_READ_EN        (1<<15)
-
-/* miscellaneous control */
-
-#define SM501_MISC_CONTROL             (0x000004)
-
-#define SM501_MISC_BUS_SH              (0x0)
-#define SM501_MISC_BUS_PCI             (0x1)
-#define SM501_MISC_BUS_XSCALE          (0x2)
-#define SM501_MISC_BUS_NEC             (0x6)
-#define SM501_MISC_BUS_MASK            (0x7)
-
-#define SM501_MISC_VR_62MB             (1<<3)
-#define SM501_MISC_CDR_RESET           (1<<7)
-#define SM501_MISC_USB_LB              (1<<8)
-#define SM501_MISC_USB_SLAVE           (1<<9)
-#define SM501_MISC_BL_1                        (1<<10)
-#define SM501_MISC_MC                  (1<<11)
-#define SM501_MISC_DAC_POWER           (1<<12)
-#define SM501_MISC_IRQ_INVERT          (1<<16)
-#define SM501_MISC_SH                  (1<<17)
-
-#define SM501_MISC_HOLD_EMPTY          (0<<18)
-#define SM501_MISC_HOLD_8              (1<<18)
-#define SM501_MISC_HOLD_16             (2<<18)
-#define SM501_MISC_HOLD_24             (3<<18)
-#define SM501_MISC_HOLD_32             (4<<18)
-#define SM501_MISC_HOLD_MASK           (7<<18)
-
-#define SM501_MISC_FREQ_12             (1<<24)
-#define SM501_MISC_PNL_24BIT           (1<<25)
-#define SM501_MISC_8051_LE             (1<<26)
-
-
-
-#define SM501_GPIO31_0_CONTROL         (0x000008)
-#define SM501_GPIO63_32_CONTROL                (0x00000C)
-#define SM501_DRAM_CONTROL             (0x000010)
-
-/* command list */
-#define SM501_ARBTRTN_CONTROL          (0x000014)
-
-/* command list */
-#define SM501_COMMAND_LIST_STATUS      (0x000024)
-
-/* interrupt debug */
-#define SM501_RAW_IRQ_STATUS           (0x000028)
-#define SM501_RAW_IRQ_CLEAR            (0x000028)
-#define SM501_IRQ_STATUS               (0x00002C)
-#define SM501_IRQ_MASK                 (0x000030)
-#define SM501_DEBUG_CONTROL            (0x000034)
-
-/* power management */
-#define SM501_POWERMODE_P2X_SRC                (1<<29)
-#define SM501_POWERMODE_V2X_SRC                (1<<20)
-#define SM501_POWERMODE_M_SRC          (1<<12)
-#define SM501_POWERMODE_M1_SRC         (1<<4)
-
-#define SM501_CURRENT_GATE             (0x000038)
-#define SM501_CURRENT_CLOCK            (0x00003C)
-#define SM501_POWER_MODE_0_GATE                (0x000040)
-#define SM501_POWER_MODE_0_CLOCK       (0x000044)
-#define SM501_POWER_MODE_1_GATE                (0x000048)
-#define SM501_POWER_MODE_1_CLOCK       (0x00004C)
-#define SM501_SLEEP_MODE_GATE          (0x000050)
-#define SM501_POWER_MODE_CONTROL       (0x000054)
-
-/* power gates for units within the 501 */
-#define SM501_GATE_HOST                        (0)
-#define SM501_GATE_MEMORY              (1)
-#define SM501_GATE_DISPLAY             (2)
-#define SM501_GATE_2D_ENGINE           (3)
-#define SM501_GATE_CSC                 (4)
-#define SM501_GATE_ZVPORT              (5)
-#define SM501_GATE_GPIO                        (6)
-#define SM501_GATE_UART0               (7)
-#define SM501_GATE_UART1               (8)
-#define SM501_GATE_SSP                 (10)
-#define SM501_GATE_USB_HOST            (11)
-#define SM501_GATE_USB_GADGET          (12)
-#define SM501_GATE_UCONTROLLER         (17)
-#define SM501_GATE_AC97                        (18)
-
-/* panel clock */
-#define SM501_CLOCK_P2XCLK             (24)
-/* crt clock */
-#define SM501_CLOCK_V2XCLK             (16)
-/* main clock */
-#define SM501_CLOCK_MCLK               (8)
-/* SDRAM controller clock */
-#define SM501_CLOCK_M1XCLK             (0)
-
-/* config 2 */
-#define SM501_PCI_MASTER_BASE          (0x000058)
-#define SM501_ENDIAN_CONTROL           (0x00005C)
-#define SM501_DEVICEID                 (0x000060)
-/* 0x050100A0 */
-
-#define SM501_DEVICEID_SM501           (0x05010000)
-#define SM501_DEVICEID_IDMASK          (0xffff0000)
-#define SM501_DEVICEID_REVMASK         (0x000000ff)
-
-#define SM501_PLLCLOCK_COUNT           (0x000064)
-#define SM501_MISC_TIMING              (0x000068)
-#define SM501_CURRENT_SDRAM_CLOCK      (0x00006C)
-
-#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
-
-/* GPIO base */
-#define SM501_GPIO                     (0x010000)
-#define SM501_GPIO_DATA_LOW            (0x00)
-#define SM501_GPIO_DATA_HIGH           (0x04)
-#define SM501_GPIO_DDR_LOW             (0x08)
-#define SM501_GPIO_DDR_HIGH            (0x0C)
-#define SM501_GPIO_IRQ_SETUP           (0x10)
-#define SM501_GPIO_IRQ_STATUS          (0x14)
-#define SM501_GPIO_IRQ_RESET           (0x14)
-
-/* I2C controller base */
-#define SM501_I2C                      (0x010040)
-#define SM501_I2C_BYTE_COUNT           (0x00)
-#define SM501_I2C_CONTROL              (0x01)
-#define SM501_I2C_STATUS               (0x02)
-#define SM501_I2C_RESET                        (0x02)
-#define SM501_I2C_SLAVE_ADDRESS                (0x03)
-#define SM501_I2C_DATA                 (0x04)
-
-/* SSP base */
-#define SM501_SSP                      (0x020000)
-
-/* Uart 0 base */
-#define SM501_UART0                    (0x030000)
-
-/* Uart 1 base */
-#define SM501_UART1                    (0x030020)
-
-/* USB host port base */
-#define SM501_USB_HOST                 (0x040000)
-
-/* USB slave/gadget base */
-#define SM501_USB_GADGET               (0x060000)
-
-/* USB slave/gadget data port base */
-#define SM501_USB_GADGET_DATA          (0x070000)
-
-/* Display controller/video engine base */
-#define SM501_DC                       (0x080000)
-
-/* common defines for the SM501 address registers */
-#define SM501_ADDR_FLIP                        (1<<31)
-#define SM501_ADDR_EXT                 (1<<27)
-#define SM501_ADDR_CS1                 (1<<26)
-#define SM501_ADDR_MASK                        (0x3f << 26)
-
-#define SM501_FIFO_MASK                        (0x3 << 16)
-#define SM501_FIFO_1                   (0x0 << 16)
-#define SM501_FIFO_3                   (0x1 << 16)
-#define SM501_FIFO_7                   (0x2 << 16)
-#define SM501_FIFO_11                  (0x3 << 16)
-
-/* common registers for panel and the crt */
-#define SM501_OFF_DC_H_TOT             (0x000)
-#define SM501_OFF_DC_V_TOT             (0x008)
-#define SM501_OFF_DC_H_SYNC            (0x004)
-#define SM501_OFF_DC_V_SYNC            (0x00C)
-
-#define SM501_DC_PANEL_CONTROL         (0x000)
-
-#define SM501_DC_PANEL_CONTROL_FPEN    (1<<27)
-#define SM501_DC_PANEL_CONTROL_BIAS    (1<<26)
-#define SM501_DC_PANEL_CONTROL_DATA    (1<<25)
-#define SM501_DC_PANEL_CONTROL_VDD     (1<<24)
-#define SM501_DC_PANEL_CONTROL_DP      (1<<23)
-
-#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
-
-#define SM501_DC_PANEL_CONTROL_DE      (1<<20)
-
-#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN8        (1<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
-
-#define SM501_DC_PANEL_CONTROL_CP      (1<<14)
-#define SM501_DC_PANEL_CONTROL_VSP     (1<<13)
-#define SM501_DC_PANEL_CONTROL_HSP     (1<<12)
-#define SM501_DC_PANEL_CONTROL_CK      (1<<9)
-#define SM501_DC_PANEL_CONTROL_TE      (1<<8)
-#define SM501_DC_PANEL_CONTROL_VPD     (1<<7)
-#define SM501_DC_PANEL_CONTROL_VP      (1<<6)
-#define SM501_DC_PANEL_CONTROL_HPD     (1<<5)
-#define SM501_DC_PANEL_CONTROL_HP      (1<<4)
-#define SM501_DC_PANEL_CONTROL_GAMMA   (1<<3)
-#define SM501_DC_PANEL_CONTROL_EN      (1<<2)
-
-#define SM501_DC_PANEL_CONTROL_8BPP    (0<<0)
-#define SM501_DC_PANEL_CONTROL_16BPP   (1<<0)
-#define SM501_DC_PANEL_CONTROL_32BPP   (2<<0)
-
-
-#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
-#define SM501_DC_PANEL_COLOR_KEY       (0x008)
-#define SM501_DC_PANEL_FB_ADDR         (0x00C)
-#define SM501_DC_PANEL_FB_OFFSET       (0x010)
-#define SM501_DC_PANEL_FB_WIDTH                (0x014)
-#define SM501_DC_PANEL_FB_HEIGHT       (0x018)
-#define SM501_DC_PANEL_TL_LOC          (0x01C)
-#define SM501_DC_PANEL_BR_LOC          (0x020)
-#define SM501_DC_PANEL_H_TOT           (0x024)
-#define SM501_DC_PANEL_H_SYNC          (0x028)
-#define SM501_DC_PANEL_V_TOT           (0x02C)
-#define SM501_DC_PANEL_V_SYNC          (0x030)
-#define SM501_DC_PANEL_CUR_LINE                (0x034)
-
-#define SM501_DC_VIDEO_CONTROL         (0x040)
-#define SM501_DC_VIDEO_FB0_ADDR                (0x044)
-#define SM501_DC_VIDEO_FB_WIDTH                (0x048)
-#define SM501_DC_VIDEO_FB0_LAST_ADDR   (0x04C)
-#define SM501_DC_VIDEO_TL_LOC          (0x050)
-#define SM501_DC_VIDEO_BR_LOC          (0x054)
-#define SM501_DC_VIDEO_SCALE           (0x058)
-#define SM501_DC_VIDEO_INIT_SCALE      (0x05C)
-#define SM501_DC_VIDEO_YUV_CONSTANTS   (0x060)
-#define SM501_DC_VIDEO_FB1_ADDR                (0x064)
-#define SM501_DC_VIDEO_FB1_LAST_ADDR   (0x068)
-
-#define SM501_DC_VIDEO_ALPHA_CONTROL   (0x080)
-#define SM501_DC_VIDEO_ALPHA_FB_ADDR   (0x084)
-#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
-#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR      (0x08C)
-#define SM501_DC_VIDEO_ALPHA_TL_LOC    (0x090)
-#define SM501_DC_VIDEO_ALPHA_BR_LOC    (0x094)
-#define SM501_DC_VIDEO_ALPHA_SCALE     (0x098)
-#define SM501_DC_VIDEO_ALPHA_INIT_SCALE        (0x09C)
-#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY        (0x0A0)
-#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP      (0x0A4)
-
-#define SM501_DC_PANEL_HWC_BASE                (0x0F0)
-#define SM501_DC_PANEL_HWC_ADDR                (0x0F0)
-#define SM501_DC_PANEL_HWC_LOC         (0x0F4)
-#define SM501_DC_PANEL_HWC_COLOR_1_2   (0x0F8)
-#define SM501_DC_PANEL_HWC_COLOR_3     (0x0FC)
-
-#define SM501_HWC_EN                   (1<<31)
-
-#define SM501_OFF_HWC_ADDR             (0x00)
-#define SM501_OFF_HWC_LOC              (0x04)
-#define SM501_OFF_HWC_COLOR_1_2                (0x08)
-#define SM501_OFF_HWC_COLOR_3          (0x0C)
-
-#define SM501_DC_ALPHA_CONTROL         (0x100)
-#define SM501_DC_ALPHA_FB_ADDR         (0x104)
-#define SM501_DC_ALPHA_FB_OFFSET       (0x108)
-#define SM501_DC_ALPHA_TL_LOC          (0x10C)
-#define SM501_DC_ALPHA_BR_LOC          (0x110)
-#define SM501_DC_ALPHA_CHROMA_KEY      (0x114)
-#define SM501_DC_ALPHA_COLOR_LOOKUP    (0x118)
-
-#define SM501_DC_CRT_CONTROL           (0x200)
-
-#define SM501_DC_CRT_CONTROL_TVP       (1<<15)
-#define SM501_DC_CRT_CONTROL_CP                (1<<14)
-#define SM501_DC_CRT_CONTROL_VSP       (1<<13)
-#define SM501_DC_CRT_CONTROL_HSP       (1<<12)
-#define SM501_DC_CRT_CONTROL_VS                (1<<11)
-#define SM501_DC_CRT_CONTROL_BLANK     (1<<10)
-#define SM501_DC_CRT_CONTROL_SEL       (1<<9)
-#define SM501_DC_CRT_CONTROL_TE                (1<<8)
-#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
-#define SM501_DC_CRT_CONTROL_GAMMA     (1<<3)
-#define SM501_DC_CRT_CONTROL_ENABLE    (1<<2)
-
-#define SM501_DC_CRT_CONTROL_8BPP      (0<<0)
-#define SM501_DC_CRT_CONTROL_16BPP     (1<<0)
-#define SM501_DC_CRT_CONTROL_32BPP     (2<<0)
-
-#define SM501_DC_CRT_FB_ADDR           (0x204)
-#define SM501_DC_CRT_FB_OFFSET         (0x208)
-#define SM501_DC_CRT_H_TOT             (0x20C)
-#define SM501_DC_CRT_H_SYNC            (0x210)
-#define SM501_DC_CRT_V_TOT             (0x214)
-#define SM501_DC_CRT_V_SYNC            (0x218)
-#define SM501_DC_CRT_SIGNATURE_ANALYZER        (0x21C)
-#define SM501_DC_CRT_CUR_LINE          (0x220)
-#define SM501_DC_CRT_MONITOR_DETECT    (0x224)
-
-#define SM501_DC_CRT_HWC_BASE          (0x230)
-#define SM501_DC_CRT_HWC_ADDR          (0x230)
-#define SM501_DC_CRT_HWC_LOC           (0x234)
-#define SM501_DC_CRT_HWC_COLOR_1_2     (0x238)
-#define SM501_DC_CRT_HWC_COLOR_3       (0x23C)
-
-#define SM501_DC_PANEL_PALETTE         (0x400)
-
-#define SM501_DC_VIDEO_PALETTE         (0x800)
-
-#define SM501_DC_CRT_PALETTE           (0xC00)
-
-/* Zoom Video port base */
-#define SM501_ZVPORT                   (0x090000)
-
-/* AC97/I2S base */
-#define SM501_AC97                     (0x0A0000)
-
-/* 8051 micro controller base */
-#define SM501_UCONTROLLER              (0x0B0000)
-
-/* 8051 micro controller SRAM base */
-#define SM501_UCONTROLLER_SRAM         (0x0C0000)
-
-/* DMA base */
-#define SM501_DMA                      (0x0D0000)
-
-/* 2d engine base */
-#define SM501_2D_ENGINE                        (0x100000)
-#define SM501_2D_SOURCE                        (0x00)
-#define SM501_2D_DESTINATION           (0x04)
-#define SM501_2D_DIMENSION             (0x08)
-#define SM501_2D_CONTROL               (0x0C)
-#define SM501_2D_PITCH                 (0x10)
-#define SM501_2D_FOREGROUND            (0x14)
-#define SM501_2D_BACKGROUND            (0x18)
-#define SM501_2D_STRETCH               (0x1C)
-#define SM501_2D_COLOR_COMPARE         (0x20)
-#define SM501_2D_COLOR_COMPARE_MASK    (0x24)
-#define SM501_2D_MASK                  (0x28)
-#define SM501_2D_CLIP_TL               (0x2C)
-#define SM501_2D_CLIP_BR               (0x30)
-#define SM501_2D_MONO_PATTERN_LOW      (0x34)
-#define SM501_2D_MONO_PATTERN_HIGH     (0x38)
-#define SM501_2D_WINDOW_WIDTH          (0x3C)
-#define SM501_2D_SOURCE_BASE           (0x40)
-#define SM501_2D_DESTINATION_BASE      (0x44)
-#define SM501_2D_ALPHA                 (0x48)
-#define SM501_2D_WRAP                  (0x4C)
-#define SM501_2D_STATUS                        (0x50)
-
-#define SM501_CSC_Y_SOURCE_BASE                (0xC8)
-#define SM501_CSC_CONSTANTS            (0xCC)
-#define SM501_CSC_Y_SOURCE_X           (0xD0)
-#define SM501_CSC_Y_SOURCE_Y           (0xD4)
-#define SM501_CSC_U_SOURCE_BASE                (0xD8)
-#define SM501_CSC_V_SOURCE_BASE                (0xDC)
-#define SM501_CSC_SOURCE_DIMENSION     (0xE0)
-#define SM501_CSC_SOURCE_PITCH         (0xE4)
-#define SM501_CSC_DESTINATION          (0xE8)
-#define SM501_CSC_DESTINATION_DIMENSION        (0xEC)
-#define SM501_CSC_DESTINATION_PITCH    (0xF0)
-#define SM501_CSC_SCALE_FACTOR         (0xF4)
-#define SM501_CSC_DESTINATION_BASE     (0xF8)
-#define SM501_CSC_CONTROL              (0xFC)
-
-/* 2d engine data port base */
-#define SM501_2D_ENGINE_DATA           (0x110000)
-
-/* end of register definitions */
-
-#define SM501_HWC_WIDTH                       (64)
-#define SM501_HWC_HEIGHT                      (64)
-
-/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
-static const uint32_t sm501_mem_local_size[] = {
-       [0]     = 4*1024*1024,
-       [1]     = 8*1024*1024,
-       [2]     = 16*1024*1024,
-       [3]     = 32*1024*1024,
-       [4]     = 64*1024*1024,
-       [5]     = 2*1024*1024,
-};
-#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
-
-typedef struct SM501State {
-    /* graphic console status */
-    QemuConsole *con;
-
-    /* status & internal resources */
-    hwaddr base;
-    uint32_t local_mem_size_index;
-    uint8_t * local_mem;
-    MemoryRegion local_mem_region;
-    uint32_t last_width;
-    uint32_t last_height;
-
-    /* mmio registers */
-    uint32_t system_control;
-    uint32_t misc_control;
-    uint32_t gpio_31_0_control;
-    uint32_t gpio_63_32_control;
-    uint32_t dram_control;
-    uint32_t irq_mask;
-    uint32_t misc_timing;
-    uint32_t power_mode_control;
-
-    uint32_t uart0_ier;
-    uint32_t uart0_lcr;
-    uint32_t uart0_mcr;
-    uint32_t uart0_scr;
-
-    uint8_t dc_palette[0x400 * 3];
-
-    uint32_t dc_panel_control;
-    uint32_t dc_panel_panning_control;
-    uint32_t dc_panel_fb_addr;
-    uint32_t dc_panel_fb_offset;
-    uint32_t dc_panel_fb_width;
-    uint32_t dc_panel_fb_height;
-    uint32_t dc_panel_tl_location;
-    uint32_t dc_panel_br_location;
-    uint32_t dc_panel_h_total;
-    uint32_t dc_panel_h_sync;
-    uint32_t dc_panel_v_total;
-    uint32_t dc_panel_v_sync;
-
-    uint32_t dc_panel_hwc_addr;
-    uint32_t dc_panel_hwc_location;
-    uint32_t dc_panel_hwc_color_1_2;
-    uint32_t dc_panel_hwc_color_3;
-
-    uint32_t dc_crt_control;
-    uint32_t dc_crt_fb_addr;
-    uint32_t dc_crt_fb_offset;
-    uint32_t dc_crt_h_total;
-    uint32_t dc_crt_h_sync;
-    uint32_t dc_crt_v_total;
-    uint32_t dc_crt_v_sync;
-
-    uint32_t dc_crt_hwc_addr;
-    uint32_t dc_crt_hwc_location;
-    uint32_t dc_crt_hwc_color_1_2;
-    uint32_t dc_crt_hwc_color_3;
-
-    uint32_t twoD_source;
-    uint32_t twoD_destination;
-    uint32_t twoD_dimension;
-    uint32_t twoD_control;
-    uint32_t twoD_pitch;
-    uint32_t twoD_foreground;
-    uint32_t twoD_stretch;
-    uint32_t twoD_color_compare_mask;
-    uint32_t twoD_mask;
-    uint32_t twoD_window_width;
-    uint32_t twoD_source_base;
-    uint32_t twoD_destination_base;
-
-} SM501State;
-
-static uint32_t get_local_mem_size_index(uint32_t size)
-{
-    uint32_t norm_size = 0;
-    int i, index = 0;
-
-    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
-       uint32_t new_size = sm501_mem_local_size[i];
-       if (new_size >= size) {
-           if (norm_size == 0 || norm_size > new_size) {
-               norm_size = new_size;
-               index = i;
-           }
-       }
-    }
-
-    return index;
-}
-
-/**
- * Check the availability of hardware cursor.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline int is_hwc_enabled(SM501State *state, int crt)
-{
-    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
-    return addr & 0x80000000;
-}
-
-/**
- * Get the address which holds cursor pattern data.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_address(SM501State *state, int crt)
-{
-    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
-    return (addr & 0x03FFFFF0)/* >> 4*/;
-}
-
-/**
- * Get the cursor position in y coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_y(SM501State *state, int crt)
-{
-    uint32_t location = crt ? state->dc_crt_hwc_location
-                            : state->dc_panel_hwc_location;
-    return (location & 0x07FF0000) >> 16;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_x(SM501State *state, int crt)
-{
-    uint32_t location = crt ? state->dc_crt_hwc_location
-                            : state->dc_panel_hwc_location;
-    return location & 0x000007FF;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
- */
-static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
-{
-    uint32_t color_reg = 0;
-    uint16_t color_565 = 0;
-
-    if (index == 0) {
-        return 0;
-    }
-
-    switch (index) {
-    case 1:
-    case 2:
-        color_reg = crt ? state->dc_crt_hwc_color_1_2
-                        : state->dc_panel_hwc_color_1_2;
-        break;
-    case 3:
-        color_reg = crt ? state->dc_crt_hwc_color_3
-                        : state->dc_panel_hwc_color_3;
-        break;
-    default:
-        printf("invalid hw cursor color.\n");
-        abort();
-    }
-
-    switch (index) {
-    case 1:
-    case 3:
-        color_565 = (uint16_t)(color_reg & 0xFFFF);
-        break;
-    case 2:
-        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
-        break;
-    }
-    return color_565;
-}
-
-static int within_hwc_y_range(SM501State *state, int y, int crt)
-{
-    int hwc_y = get_hwc_y(state, crt);
-    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
-}
-
-static void sm501_2d_operation(SM501State * s)
-{
-    /* obtain operation parameters */
-    int operation = (s->twoD_control >> 16) & 0x1f;
-    int rtl = s->twoD_control & 0x8000000;
-    int src_x = (s->twoD_source >> 16) & 0x01FFF;
-    int src_y = s->twoD_source & 0xFFFF;
-    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
-    int dst_y = s->twoD_destination & 0xFFFF;
-    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
-    int operation_height = s->twoD_dimension & 0xFFFF;
-    uint32_t color = s->twoD_foreground;
-    int format_flags = (s->twoD_stretch >> 20) & 0x3;
-    int addressing = (s->twoD_stretch >> 16) & 0xF;
-
-    /* get frame buffer info */
-    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
-    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
-    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-
-    if (addressing != 0x0) {
-        printf("%s: only XY addressing is supported.\n", __func__);
-        abort();
-    }
-
-    if ((s->twoD_source_base & 0x08000000) ||
-        (s->twoD_destination_base & 0x08000000)) {
-        printf("%s: only local memory is supported.\n", __func__);
-        abort();
-    }
-
-    switch (operation) {
-    case 0x00: /* copy area */
-#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
-        int y, x, index_d, index_s;                                         \
-        for (y = 0; y < operation_height; y++) {                            \
-            for (x = 0; x < operation_width; x++) {                         \
-                if (rtl) {                                                  \
-                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
-                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
-                } else {                                                    \
-                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
-                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
-                }                                                           \
-                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
-            }                                                               \
-        }                                                                   \
-    }
-        switch (format_flags) {
-        case 0:
-            COPY_AREA(1, uint8_t, rtl);
-            break;
-        case 1:
-            COPY_AREA(2, uint16_t, rtl);
-            break;
-        case 2:
-            COPY_AREA(4, uint32_t, rtl);
-            break;
-        }
-        break;
-
-    case 0x01: /* fill rectangle */
-#define FILL_RECT(_bpp, _pixel_type) {                                      \
-        int y, x;                                                           \
-        for (y = 0; y < operation_height; y++) {                            \
-            for (x = 0; x < operation_width; x++) {                         \
-                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
-                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
-            }                                                               \
-        }                                                                   \
-    }
-
-        switch (format_flags) {
-        case 0:
-            FILL_RECT(1, uint8_t);
-            break;
-        case 1:
-            FILL_RECT(2, uint16_t);
-            break;
-        case 2:
-            FILL_RECT(4, uint32_t);
-            break;
-        }
-        break;
-
-    default:
-        printf("non-implemented SM501 2D operation. %d\n", operation);
-        abort();
-        break;
-    }
-}
-
-static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
-                                         unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-    case SM501_SYSTEM_CONTROL:
-       ret = s->system_control;
-       break;
-    case SM501_MISC_CONTROL:
-       ret = s->misc_control;
-       break;
-    case SM501_GPIO31_0_CONTROL:
-       ret = s->gpio_31_0_control;
-       break;
-    case SM501_GPIO63_32_CONTROL:
-       ret = s->gpio_63_32_control;
-       break;
-    case SM501_DEVICEID:
-       ret = 0x050100A0;
-       break;
-    case SM501_DRAM_CONTROL:
-       ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
-       break;
-    case SM501_IRQ_MASK:
-       ret = s->irq_mask;
-       break;
-    case SM501_MISC_TIMING:
-       /* TODO : simulate gate control */
-       ret = s->misc_timing;
-       break;
-    case SM501_CURRENT_GATE:
-       /* TODO : simulate gate control */
-       ret = 0x00021807;
-       break;
-    case SM501_CURRENT_CLOCK:
-       ret = 0x2A1A0A09;
-       break;
-    case SM501_POWER_MODE_CONTROL:
-       ret = s->power_mode_control;
-       break;
-
-    default:
-       printf("sm501 system config : not implemented register read."
-              " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_system_config_write(void *opaque, hwaddr addr,
-                                      uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
-                 (uint32_t)addr, (uint32_t)value);
-
-    switch(addr) {
-    case SM501_SYSTEM_CONTROL:
-       s->system_control = value & 0xE300B8F7;
-       break;
-    case SM501_MISC_CONTROL:
-       s->misc_control = value & 0xFF7FFF20;
-       break;
-    case SM501_GPIO31_0_CONTROL:
-       s->gpio_31_0_control = value;
-       break;
-    case SM501_GPIO63_32_CONTROL:
-       s->gpio_63_32_control = value;
-       break;
-    case SM501_DRAM_CONTROL:
-       s->local_mem_size_index = (value >> 13) & 0x7;
-       /* rODO : check validity of size change */
-       s->dram_control |=  value & 0x7FFFFFC3;
-       break;
-    case SM501_IRQ_MASK:
-       s->irq_mask = value;
-       break;
-    case SM501_MISC_TIMING:
-       s->misc_timing = value & 0xF31F1FFF;
-       break;
-    case SM501_POWER_MODE_0_GATE:
-    case SM501_POWER_MODE_1_GATE:
-    case SM501_POWER_MODE_0_CLOCK:
-    case SM501_POWER_MODE_1_CLOCK:
-       /* TODO : simulate gate & clock control */
-       break;
-    case SM501_POWER_MODE_CONTROL:
-       s->power_mode_control = value & 0x00000003;
-       break;
-
-    default:
-       printf("sm501 system config : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_system_config_ops = {
-    .read = sm501_system_config_read,
-    .write = sm501_system_config_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
-
-    /* TODO : consider BYTE/WORD access */
-    /* TODO : consider endian */
-
-    assert(range_covers_byte(0, 0x400 * 3, addr));
-    return *(uint32_t*)&s->dc_palette[addr];
-}
-
-static void sm501_palette_write(void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
-                 (int)addr, value);
-
-    /* TODO : consider BYTE/WORD access */
-    /* TODO : consider endian */
-
-    assert(range_covers_byte(0, 0x400 * 3, addr));
-    *(uint32_t*)&s->dc_palette[addr] = value;
-}
-
-static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-
-    case SM501_DC_PANEL_CONTROL:
-       ret = s->dc_panel_control;
-       break;
-    case SM501_DC_PANEL_PANNING_CONTROL:
-       ret = s->dc_panel_panning_control;
-       break;
-    case SM501_DC_PANEL_FB_ADDR:
-       ret = s->dc_panel_fb_addr;
-       break;
-    case SM501_DC_PANEL_FB_OFFSET:
-       ret = s->dc_panel_fb_offset;
-       break;
-    case SM501_DC_PANEL_FB_WIDTH:
-       ret = s->dc_panel_fb_width;
-       break;
-    case SM501_DC_PANEL_FB_HEIGHT:
-       ret = s->dc_panel_fb_height;
-       break;
-    case SM501_DC_PANEL_TL_LOC:
-       ret = s->dc_panel_tl_location;
-       break;
-    case SM501_DC_PANEL_BR_LOC:
-       ret = s->dc_panel_br_location;
-       break;
-
-    case SM501_DC_PANEL_H_TOT:
-       ret = s->dc_panel_h_total;
-       break;
-    case SM501_DC_PANEL_H_SYNC:
-       ret = s->dc_panel_h_sync;
-       break;
-    case SM501_DC_PANEL_V_TOT:
-       ret = s->dc_panel_v_total;
-       break;
-    case SM501_DC_PANEL_V_SYNC:
-       ret = s->dc_panel_v_sync;
-       break;
-
-    case SM501_DC_CRT_CONTROL:
-       ret = s->dc_crt_control;
-       break;
-    case SM501_DC_CRT_FB_ADDR:
-       ret = s->dc_crt_fb_addr;
-       break;
-    case SM501_DC_CRT_FB_OFFSET:
-       ret = s->dc_crt_fb_offset;
-       break;
-    case SM501_DC_CRT_H_TOT:
-       ret = s->dc_crt_h_total;
-       break;
-    case SM501_DC_CRT_H_SYNC:
-       ret = s->dc_crt_h_sync;
-       break;
-    case SM501_DC_CRT_V_TOT:
-       ret = s->dc_crt_v_total;
-       break;
-    case SM501_DC_CRT_V_SYNC:
-       ret = s->dc_crt_v_sync;
-       break;
-
-    case SM501_DC_CRT_HWC_ADDR:
-       ret = s->dc_crt_hwc_addr;
-       break;
-    case SM501_DC_CRT_HWC_LOC:
-       ret = s->dc_crt_hwc_location;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_1_2:
-       ret = s->dc_crt_hwc_color_1_2;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_3:
-       ret = s->dc_crt_hwc_color_3;
-       break;
-
-    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
-        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
-        break;
-
-    default:
-       printf("sm501 disp ctrl : not implemented register read."
-              " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
-                 (unsigned)addr, (unsigned)value);
-
-    switch(addr) {
-    case SM501_DC_PANEL_CONTROL:
-       s->dc_panel_control = value & 0x0FFF73FF;
-       break;
-    case SM501_DC_PANEL_PANNING_CONTROL:
-       s->dc_panel_panning_control = value & 0xFF3FFF3F;
-       break;
-    case SM501_DC_PANEL_FB_ADDR:
-       s->dc_panel_fb_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_PANEL_FB_OFFSET:
-       s->dc_panel_fb_offset = value & 0x3FF03FF0;
-       break;
-    case SM501_DC_PANEL_FB_WIDTH:
-       s->dc_panel_fb_width = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_FB_HEIGHT:
-       s->dc_panel_fb_height = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_TL_LOC:
-       s->dc_panel_tl_location = value & 0x07FF07FF;
-       break;
-    case SM501_DC_PANEL_BR_LOC:
-       s->dc_panel_br_location = value & 0x07FF07FF;
-       break;
-
-    case SM501_DC_PANEL_H_TOT:
-       s->dc_panel_h_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_H_SYNC:
-       s->dc_panel_h_sync = value & 0x00FF0FFF;
-       break;
-    case SM501_DC_PANEL_V_TOT:
-       s->dc_panel_v_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_V_SYNC:
-       s->dc_panel_v_sync = value & 0x003F0FFF;
-       break;
-
-    case SM501_DC_PANEL_HWC_ADDR:
-       s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_PANEL_HWC_LOC:
-       s->dc_panel_hwc_location = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_HWC_COLOR_1_2:
-       s->dc_panel_hwc_color_1_2 = value;
-       break;
-    case SM501_DC_PANEL_HWC_COLOR_3:
-       s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
-       break;
-
-    case SM501_DC_CRT_CONTROL:
-       s->dc_crt_control = value & 0x0003FFFF;
-       break;
-    case SM501_DC_CRT_FB_ADDR:
-       s->dc_crt_fb_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_CRT_FB_OFFSET:
-       s->dc_crt_fb_offset = value & 0x3FF03FF0;
-       break;
-    case SM501_DC_CRT_H_TOT:
-       s->dc_crt_h_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_H_SYNC:
-       s->dc_crt_h_sync = value & 0x00FF0FFF;
-       break;
-    case SM501_DC_CRT_V_TOT:
-       s->dc_crt_v_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_V_SYNC:
-       s->dc_crt_v_sync = value & 0x003F0FFF;
-       break;
-
-    case SM501_DC_CRT_HWC_ADDR:
-       s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_CRT_HWC_LOC:
-       s->dc_crt_hwc_location = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_1_2:
-       s->dc_crt_hwc_color_1_2 = value;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_3:
-       s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
-       break;
-
-    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
-        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
-        break;
-
-    default:
-       printf("sm501 disp ctrl : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, (unsigned)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_disp_ctrl_ops = {
-    .read = sm501_disp_ctrl_read,
-    .write = sm501_disp_ctrl_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-    case SM501_2D_SOURCE_BASE:
-        ret = s->twoD_source_base;
-        break;
-    default:
-        printf("sm501 disp ctrl : not implemented register read."
-               " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_2d_engine_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
-                  (unsigned)addr, (unsigned)value);
-
-    switch(addr) {
-    case SM501_2D_SOURCE:
-        s->twoD_source = value;
-        break;
-    case SM501_2D_DESTINATION:
-        s->twoD_destination = value;
-        break;
-    case SM501_2D_DIMENSION:
-        s->twoD_dimension = value;
-        break;
-    case SM501_2D_CONTROL:
-        s->twoD_control = value;
-
-        /* do 2d operation if start flag is set. */
-        if (value & 0x80000000) {
-            sm501_2d_operation(s);
-            s->twoD_control &= ~0x80000000; /* start flag down */
-        }
-
-        break;
-    case SM501_2D_PITCH:
-        s->twoD_pitch = value;
-        break;
-    case SM501_2D_FOREGROUND:
-        s->twoD_foreground = value;
-        break;
-    case SM501_2D_STRETCH:
-        s->twoD_stretch = value;
-        break;
-    case SM501_2D_COLOR_COMPARE_MASK:
-        s->twoD_color_compare_mask = value;
-        break;
-    case SM501_2D_MASK:
-        s->twoD_mask = value;
-        break;
-    case SM501_2D_WINDOW_WIDTH:
-        s->twoD_window_width = value;
-        break;
-    case SM501_2D_SOURCE_BASE:
-        s->twoD_source_base = value;
-        break;
-    case SM501_2D_DESTINATION_BASE:
-        s->twoD_destination_base = value;
-        break;
-    default:
-        printf("sm501 2d engine : not implemented register write."
-               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_2d_engine_ops = {
-    .read = sm501_2d_engine_read,
-    .write = sm501_2d_engine_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* draw line functions for all console modes */
-
-typedef void draw_line_func(uint8_t *d, const uint8_t *s,
-                           int width, const uint32_t *pal);
-
-typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
-                                int c_y, uint8_t *d, int width);
-
-#define DEPTH 8
-#include "hw/sm501_template.h"
-
-#define DEPTH 15
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "hw/sm501_template.h"
-
-#define DEPTH 16
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "hw/sm501_template.h"
-
-#define DEPTH 32
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "hw/sm501_template.h"
-
-static draw_line_func * draw_line8_funcs[] = {
-    draw_line8_8,
-    draw_line8_15,
-    draw_line8_16,
-    draw_line8_32,
-    draw_line8_32bgr,
-    draw_line8_15bgr,
-    draw_line8_16bgr,
-};
-
-static draw_line_func * draw_line16_funcs[] = {
-    draw_line16_8,
-    draw_line16_15,
-    draw_line16_16,
-    draw_line16_32,
-    draw_line16_32bgr,
-    draw_line16_15bgr,
-    draw_line16_16bgr,
-};
-
-static draw_line_func * draw_line32_funcs[] = {
-    draw_line32_8,
-    draw_line32_15,
-    draw_line32_16,
-    draw_line32_32,
-    draw_line32_32bgr,
-    draw_line32_15bgr,
-    draw_line32_16bgr,
-};
-
-static draw_hwc_line_func * draw_hwc_line_funcs[] = {
-    draw_hwc_line_8,
-    draw_hwc_line_15,
-    draw_hwc_line_16,
-    draw_hwc_line_32,
-    draw_hwc_line_32bgr,
-    draw_hwc_line_15bgr,
-    draw_hwc_line_16bgr,
-};
-
-static inline int get_depth_index(DisplaySurface *surface)
-{
-    switch (surface_bits_per_pixel(surface)) {
-    default:
-    case 8:
-       return 0;
-    case 15:
-        return 1;
-    case 16:
-        return 2;
-    case 32:
-        if (is_surface_bgr(surface)) {
-            return 4;
-        } else {
-            return 3;
-        }
-    }
-}
-
-static void sm501_draw_crt(SM501State * s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y;
-    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
-
-    uint8_t  * src = s->local_mem;
-    int src_bpp = 0;
-    int dst_bpp = surface_bytes_per_pixel(surface);
-    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
-                                                   - SM501_DC_PANEL_PALETTE];
-    uint8_t hwc_palette[3 * 3];
-    int ds_depth_index = get_depth_index(surface);
-    draw_line_func * draw_line = NULL;
-    draw_hwc_line_func * draw_hwc_line = NULL;
-    int full_update = 0;
-    int y_start = -1;
-    ram_addr_t page_min = ~0l;
-    ram_addr_t page_max = 0l;
-    ram_addr_t offset = 0;
-
-    /* choose draw_line function */
-    switch (s->dc_crt_control & 3) {
-    case SM501_DC_CRT_CONTROL_8BPP:
-       src_bpp = 1;
-       draw_line = draw_line8_funcs[ds_depth_index];
-       break;
-    case SM501_DC_CRT_CONTROL_16BPP:
-       src_bpp = 2;
-       draw_line = draw_line16_funcs[ds_depth_index];
-       break;
-    case SM501_DC_CRT_CONTROL_32BPP:
-       src_bpp = 4;
-       draw_line = draw_line32_funcs[ds_depth_index];
-       break;
-    default:
-       printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
-              s->dc_crt_control);
-        abort();
-       break;
-    }
-
-    /* set up to draw hardware cursor */
-    if (is_hwc_enabled(s, 1)) {
-        int i;
-
-        /* get cursor palette */
-        for (i = 0; i < 3; i++) {
-            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
-            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
-            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
-            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
-        }
-
-        /* choose cursor draw line function */
-        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
-    }
-
-    /* adjust console size */
-    if (s->last_width != width || s->last_height != height) {
-        qemu_console_resize(s->con, width, height);
-        surface = qemu_console_surface(s->con);
-       s->last_width = width;
-       s->last_height = height;
-       full_update = 1;
-    }
-
-    /* draw each line according to conditions */
-    for (y = 0; y < height; y++) {
-       int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
-       int update = full_update || update_hwc;
-        ram_addr_t page0 = offset;
-        ram_addr_t page1 = offset + width * src_bpp - 1;
-
-       /* check dirty flags for each line */
-        update = memory_region_get_dirty(&s->local_mem_region, page0,
-                                         page1 - page0, DIRTY_MEMORY_VGA);
-
-       /* draw line and change status */
-       if (update) {
-            uint8_t *d = surface_data(surface);
-            d +=  y * width * dst_bpp;
-
-            /* draw graphics layer */
-            draw_line(d, src, width, palette);
-
-            /* draw haredware cursor */
-            if (update_hwc) {
-                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
-            }
-
-           if (y_start < 0)
-               y_start = y;
-           if (page0 < page_min)
-               page_min = page0;
-           if (page1 > page_max)
-               page_max = page1;
-       } else {
-           if (y_start >= 0) {
-               /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
-               y_start = -1;
-           }
-       }
-
-       src += width * src_bpp;
-       offset += width * src_bpp;
-    }
-
-    /* complete flush to display */
-    if (y_start >= 0)
-        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
-
-    /* clear dirty flags */
-    if (page_min != ~0l) {
-       memory_region_reset_dirty(&s->local_mem_region,
-                                  page_min, page_max + TARGET_PAGE_SIZE,
-                                  DIRTY_MEMORY_VGA);
-    }
-}
-
-static void sm501_update_display(void *opaque)
-{
-    SM501State * s = (SM501State *)opaque;
-
-    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
-       sm501_draw_crt(s);
-}
-
-void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
-                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
-{
-    SM501State * s;
-    DeviceState *dev;
-    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
-    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
-    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
-
-    /* allocate management data region */
-    s = (SM501State *)g_malloc0(sizeof(SM501State));
-    s->base = base;
-    s->local_mem_size_index
-       = get_local_mem_size_index(local_mem_bytes);
-    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
-                 s->local_mem_size_index);
-    s->system_control = 0x00100000;
-    s->misc_control = 0x00001000; /* assumes SH, active=low */
-    s->dc_panel_control = 0x00010000;
-    s->dc_crt_control = 0x00010000;
-
-    /* allocate local memory */
-    memory_region_init_ram(&s->local_mem_region, "sm501.local",
-                           local_mem_bytes);
-    vmstate_register_ram_global(&s->local_mem_region);
-    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
-    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
-
-    /* map mmio */
-    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
-                          "sm501-system-config", 0x6c);
-    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
-                                sm501_system_config);
-    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
-                          "sm501-disp-ctrl", 0x1000);
-    memory_region_add_subregion(address_space_mem,
-                                base + MMIO_BASE_OFFSET + SM501_DC,
-                                sm501_disp_ctrl);
-    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
-                          "sm501-2d-engine", 0x54);
-    memory_region_add_subregion(address_space_mem,
-                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
-                                sm501_2d_engine);
-
-    /* bridge to usb host emulation module */
-    dev = qdev_create(NULL, "sysbus-ohci");
-    qdev_prop_set_uint32(dev, "num-ports", 2);
-    qdev_prop_set_taddr(dev, "dma-offset", base);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
-                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    /* bridge to serial emulation module */
-    if (chr) {
-        serial_mm_init(address_space_mem,
-                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
-                       NULL, /* TODO : chain irq to IRL */
-                       115200, chr, DEVICE_NATIVE_ENDIAN);
-    }
-
-    /* create qemu graphic console */
-    s->con = graphic_console_init(sm501_update_display, NULL,
-                                  NULL, NULL, s);
-}
index b2a921e7e10e1bd5035f2ba4b0aea3fa9604ee0f..235461696848be0590927edebf91bb41242c928c 100644 (file)
@@ -1,4 +1,4 @@
-obj-y = tcx.o sun4m_iommu.o slavio_intctl.o
+obj-y = sun4m_iommu.o slavio_intctl.o
 obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o
 obj-y += eccmemctl.o sbi.o sun4c_intctl.o
 
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
deleted file mode 100644 (file)
index 2d5fa89..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * Most features are currently unsupported!!!
- *
- * This code is licensed under the GNU GPL v2.
- *
- * 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/hw.h"
-#include "hw/arm/devices.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "sysemu/blockdev.h"
-
-#define IRQ_TC6393_NAND                0
-#define IRQ_TC6393_MMC         1
-#define IRQ_TC6393_OHCI                2
-#define IRQ_TC6393_SERIAL      3
-#define IRQ_TC6393_FB          4
-
-#define        TC6393XB_NR_IRQS        8
-
-#define TC6393XB_GPIOS  16
-
-#define SCR_REVID      0x08            /* b Revision ID        */
-#define SCR_ISR                0x50            /* b Interrupt Status   */
-#define SCR_IMR                0x52            /* b Interrupt Mask     */
-#define SCR_IRR                0x54            /* b Interrupt Routing  */
-#define SCR_GPER       0x60            /* w GP Enable          */
-#define SCR_GPI_SR(i)  (0x64 + (i))    /* b3 GPI Status        */
-#define SCR_GPI_IMR(i) (0x68 + (i))    /* b3 GPI INT Mask      */
-#define SCR_GPI_EDER(i)        (0x6c + (i))    /* b3 GPI Edge Detect Enable */
-#define SCR_GPI_LIR(i) (0x70 + (i))    /* b3 GPI Level Invert  */
-#define SCR_GPO_DSR(i) (0x78 + (i))    /* b3 GPO Data Set      */
-#define SCR_GPO_DOECR(i) (0x7c + (i))  /* b3 GPO Data OE Control */
-#define SCR_GP_IARCR(i)        (0x80 + (i))    /* b3 GP Internal Active Register Control */
-#define SCR_GP_IARLCR(i) (0x84 + (i))  /* b3 GP INTERNAL Active Register Level Control */
-#define SCR_GPI_BCR(i) (0x88 + (i))    /* b3 GPI Buffer Control */
-#define SCR_GPA_IARCR  0x8c            /* w GPa Internal Active Register Control */
-#define SCR_GPA_IARLCR 0x90            /* w GPa Internal Active Register Level Control */
-#define SCR_GPA_BCR    0x94            /* w GPa Buffer Control */
-#define SCR_CCR                0x98            /* w Clock Control      */
-#define SCR_PLL2CR     0x9a            /* w PLL2 Control       */
-#define SCR_PLL1CR     0x9c            /* l PLL1 Control       */
-#define SCR_DIARCR     0xa0            /* b Device Internal Active Register Control */
-#define SCR_DBOCR      0xa1            /* b Device Buffer Off Control */
-#define SCR_FER                0xe0            /* b Function Enable    */
-#define SCR_MCR                0xe4            /* w Mode Control       */
-#define SCR_CONFIG     0xfc            /* b Configuration Control */
-#define SCR_DEBUG      0xff            /* b Debug              */
-
-#define NAND_CFG_COMMAND    0x04    /* w Command        */
-#define NAND_CFG_BASE       0x10    /* l Control Base Address */
-#define NAND_CFG_INTP       0x3d    /* b Interrupt Pin  */
-#define NAND_CFG_INTE       0x48    /* b Int Enable     */
-#define NAND_CFG_EC         0x4a    /* b Event Control  */
-#define NAND_CFG_ICC        0x4c    /* b Internal Clock Control */
-#define NAND_CFG_ECCC       0x5b    /* b ECC Control    */
-#define NAND_CFG_NFTC       0x60    /* b NAND Flash Transaction Control */
-#define NAND_CFG_NFM        0x61    /* b NAND Flash Monitor */
-#define NAND_CFG_NFPSC      0x62    /* b NAND Flash Power Supply Control */
-#define NAND_CFG_NFDC       0x63    /* b NAND Flash Detect Control */
-
-#define NAND_DATA   0x00        /* l Data       */
-#define NAND_MODE   0x04        /* b Mode       */
-#define NAND_STATUS 0x05        /* b Status     */
-#define NAND_ISR    0x06        /* b Interrupt Status */
-#define NAND_IMR    0x07        /* b Interrupt Mask */
-
-#define NAND_MODE_WP        0x80
-#define NAND_MODE_CE        0x10
-#define NAND_MODE_ALE       0x02
-#define NAND_MODE_CLE       0x01
-#define NAND_MODE_ECC_MASK  0x60
-#define NAND_MODE_ECC_EN    0x20
-#define NAND_MODE_ECC_READ  0x40
-#define NAND_MODE_ECC_RST   0x60
-
-struct TC6393xbState {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq *sub_irqs;
-    struct {
-        uint8_t ISR;
-        uint8_t IMR;
-        uint8_t IRR;
-        uint16_t GPER;
-        uint8_t GPI_SR[3];
-        uint8_t GPI_IMR[3];
-        uint8_t GPI_EDER[3];
-        uint8_t GPI_LIR[3];
-        uint8_t GP_IARCR[3];
-        uint8_t GP_IARLCR[3];
-        uint8_t GPI_BCR[3];
-        uint16_t GPA_IARCR;
-        uint16_t GPA_IARLCR;
-        uint16_t CCR;
-        uint16_t PLL2CR;
-        uint32_t PLL1CR;
-        uint8_t DIARCR;
-        uint8_t DBOCR;
-        uint8_t FER;
-        uint16_t MCR;
-        uint8_t CONFIG;
-        uint8_t DEBUG;
-    } scr;
-    uint32_t gpio_dir;
-    uint32_t gpio_level;
-    uint32_t prev_level;
-    qemu_irq handler[TC6393XB_GPIOS];
-    qemu_irq *gpio_in;
-
-    struct {
-        uint8_t mode;
-        uint8_t isr;
-        uint8_t imr;
-    } nand;
-    int nand_enable;
-    uint32_t nand_phys;
-    DeviceState *flash;
-    ECCState ecc;
-
-    QemuConsole *con;
-    MemoryRegion vram;
-    uint16_t *vram_ptr;
-    uint32_t scr_width, scr_height; /* in pixels */
-    qemu_irq l3v;
-    unsigned blank : 1,
-             blanked : 1;
-};
-
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
-{
-    return s->gpio_in;
-}
-
-static void tc6393xb_gpio_set(void *opaque, int line, int level)
-{
-//    TC6393xbState *s = opaque;
-
-    if (line > TC6393XB_GPIOS) {
-        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
-        return;
-    }
-
-    // FIXME: how does the chip reflect the GPIO input level change?
-}
-
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
-                    qemu_irq handler)
-{
-    if (line >= TC6393XB_GPIOS) {
-        fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
-        return;
-    }
-
-    s->handler[line] = handler;
-}
-
-static void tc6393xb_gpio_handler_update(TC6393xbState *s)
-{
-    uint32_t level, diff;
-    int bit;
-
-    level = s->gpio_level & s->gpio_dir;
-
-    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-        bit = ffs(diff) - 1;
-        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
-    }
-
-    s->prev_level = level;
-}
-
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
-{
-    return s->l3v;
-}
-
-static void tc6393xb_l3v(void *opaque, int line, int level)
-{
-    TC6393xbState *s = opaque;
-    s->blank = !level;
-    fprintf(stderr, "L3V: %d\n", level);
-}
-
-static void tc6393xb_sub_irq(void *opaque, int line, int level) {
-    TC6393xbState *s = opaque;
-    uint8_t isr = s->scr.ISR;
-    if (level)
-        isr |= 1 << line;
-    else
-        isr &= ~(1 << line);
-    s->scr.ISR = isr;
-    qemu_set_irq(s->irq, isr & s->scr.IMR);
-}
-
-#define SCR_REG_B(N)                            \
-    case SCR_ ##N: return s->scr.N
-#define SCR_REG_W(N)                            \
-    case SCR_ ##N: return s->scr.N;             \
-    case SCR_ ##N + 1: return s->scr.N >> 8;
-#define SCR_REG_L(N)                            \
-    case SCR_ ##N: return s->scr.N;             \
-    case SCR_ ##N + 1: return s->scr.N >> 8;    \
-    case SCR_ ##N + 2: return s->scr.N >> 16;   \
-    case SCR_ ##N + 3: return s->scr.N >> 24;
-#define SCR_REG_A(N)                            \
-    case SCR_ ##N(0): return s->scr.N[0];       \
-    case SCR_ ##N(1): return s->scr.N[1];       \
-    case SCR_ ##N(2): return s->scr.N[2]
-
-static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
-{
-    switch (addr) {
-        case SCR_REVID:
-            return 3;
-        case SCR_REVID+1:
-            return 0;
-        SCR_REG_B(ISR);
-        SCR_REG_B(IMR);
-        SCR_REG_B(IRR);
-        SCR_REG_W(GPER);
-        SCR_REG_A(GPI_SR);
-        SCR_REG_A(GPI_IMR);
-        SCR_REG_A(GPI_EDER);
-        SCR_REG_A(GPI_LIR);
-        case SCR_GPO_DSR(0):
-        case SCR_GPO_DSR(1):
-        case SCR_GPO_DSR(2):
-            return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
-        case SCR_GPO_DOECR(0):
-        case SCR_GPO_DOECR(1):
-        case SCR_GPO_DOECR(2):
-            return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
-        SCR_REG_A(GP_IARCR);
-        SCR_REG_A(GP_IARLCR);
-        SCR_REG_A(GPI_BCR);
-        SCR_REG_W(GPA_IARCR);
-        SCR_REG_W(GPA_IARLCR);
-        SCR_REG_W(CCR);
-        SCR_REG_W(PLL2CR);
-        SCR_REG_L(PLL1CR);
-        SCR_REG_B(DIARCR);
-        SCR_REG_B(DBOCR);
-        SCR_REG_B(FER);
-        SCR_REG_W(MCR);
-        SCR_REG_B(CONFIG);
-        SCR_REG_B(DEBUG);
-    }
-    fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-#define SCR_REG_B(N)                                \
-    case SCR_ ##N: s->scr.N = value; return;
-#define SCR_REG_W(N)                                \
-    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
-    case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
-#define SCR_REG_L(N)                                \
-    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return;   \
-    case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return;     \
-    case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return;   \
-    case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
-#define SCR_REG_A(N)                                \
-    case SCR_ ##N(0): s->scr.N[0] = value; return;   \
-    case SCR_ ##N(1): s->scr.N[1] = value; return;   \
-    case SCR_ ##N(2): s->scr.N[2] = value; return
-
-static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
-{
-    switch (addr) {
-        SCR_REG_B(ISR);
-        SCR_REG_B(IMR);
-        SCR_REG_B(IRR);
-        SCR_REG_W(GPER);
-        SCR_REG_A(GPI_SR);
-        SCR_REG_A(GPI_IMR);
-        SCR_REG_A(GPI_EDER);
-        SCR_REG_A(GPI_LIR);
-        case SCR_GPO_DSR(0):
-        case SCR_GPO_DSR(1):
-        case SCR_GPO_DSR(2):
-            s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
-            tc6393xb_gpio_handler_update(s);
-            return;
-        case SCR_GPO_DOECR(0):
-        case SCR_GPO_DOECR(1):
-        case SCR_GPO_DOECR(2):
-            s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
-            tc6393xb_gpio_handler_update(s);
-            return;
-        SCR_REG_A(GP_IARCR);
-        SCR_REG_A(GP_IARLCR);
-        SCR_REG_A(GPI_BCR);
-        SCR_REG_W(GPA_IARCR);
-        SCR_REG_W(GPA_IARLCR);
-        SCR_REG_W(CCR);
-        SCR_REG_W(PLL2CR);
-        SCR_REG_L(PLL1CR);
-        SCR_REG_B(DIARCR);
-        SCR_REG_B(DBOCR);
-        SCR_REG_B(FER);
-        SCR_REG_W(MCR);
-        SCR_REG_B(CONFIG);
-        SCR_REG_B(DEBUG);
-    }
-    fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-static void tc6393xb_nand_irq(TC6393xbState *s) {
-    qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
-            (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
-}
-
-static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
-    switch (addr) {
-        case NAND_CFG_COMMAND:
-            return s->nand_enable ? 2 : 0;
-        case NAND_CFG_BASE:
-        case NAND_CFG_BASE + 1:
-        case NAND_CFG_BASE + 2:
-        case NAND_CFG_BASE + 3:
-            return s->nand_phys >> (addr - NAND_CFG_BASE);
-    }
-    fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-    switch (addr) {
-        case NAND_CFG_COMMAND:
-            s->nand_enable = (value & 0x2);
-            return;
-        case NAND_CFG_BASE:
-        case NAND_CFG_BASE + 1:
-        case NAND_CFG_BASE + 2:
-        case NAND_CFG_BASE + 3:
-            s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
-            s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
-            return;
-    }
-    fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
-    switch (addr) {
-        case NAND_DATA + 0:
-        case NAND_DATA + 1:
-        case NAND_DATA + 2:
-        case NAND_DATA + 3:
-            return nand_getio(s->flash);
-        case NAND_MODE:
-            return s->nand.mode;
-        case NAND_STATUS:
-            return 0x14;
-        case NAND_ISR:
-            return s->nand.isr;
-        case NAND_IMR:
-            return s->nand.imr;
-    }
-    fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-//    fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
-//                                     (uint32_t) addr, value & 0xff);
-    switch (addr) {
-        case NAND_DATA + 0:
-        case NAND_DATA + 1:
-        case NAND_DATA + 2:
-        case NAND_DATA + 3:
-            nand_setio(s->flash, value);
-            s->nand.isr |= 1;
-            tc6393xb_nand_irq(s);
-            return;
-        case NAND_MODE:
-            s->nand.mode = value;
-            nand_setpins(s->flash,
-                    value & NAND_MODE_CLE,
-                    value & NAND_MODE_ALE,
-                    !(value & NAND_MODE_CE),
-                    value & NAND_MODE_WP,
-                    0); // FIXME: gnd
-            switch (value & NAND_MODE_ECC_MASK) {
-                case NAND_MODE_ECC_RST:
-                    ecc_reset(&s->ecc);
-                    break;
-                case NAND_MODE_ECC_READ:
-                    // FIXME
-                    break;
-                case NAND_MODE_ECC_EN:
-                    ecc_reset(&s->ecc);
-            }
-            return;
-        case NAND_ISR:
-            s->nand.isr = value;
-            tc6393xb_nand_irq(s);
-            return;
-        case NAND_IMR:
-            s->nand.imr = value;
-            tc6393xb_nand_irq(s);
-            return;
-    }
-    fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-
-#define BITS 8
-#include "hw/tc6393xb_template.h"
-#define BITS 15
-#include "hw/tc6393xb_template.h"
-#define BITS 16
-#include "hw/tc6393xb_template.h"
-#define BITS 24
-#include "hw/tc6393xb_template.h"
-#define BITS 32
-#include "hw/tc6393xb_template.h"
-
-static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            tc6393xb_draw_graphic8(s);
-            break;
-        case 15:
-            tc6393xb_draw_graphic15(s);
-            break;
-        case 16:
-            tc6393xb_draw_graphic16(s);
-            break;
-        case 24:
-            tc6393xb_draw_graphic24(s);
-            break;
-        case 32:
-            tc6393xb_draw_graphic32(s);
-            break;
-        default:
-            printf("tc6393xb: unknown depth %d\n",
-                   surface_bits_per_pixel(surface));
-            return;
-    }
-
-    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w;
-    uint8_t *d;
-
-    if (!full_update)
-        return;
-
-    w = s->scr_width * surface_bytes_per_pixel(surface);
-    d = surface_data(surface);
-    for(i = 0; i < s->scr_height; i++) {
-        memset(d, 0, w);
-        d += surface_stride(surface);
-    }
-
-    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_update_display(void *opaque)
-{
-    TC6393xbState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int full_update;
-
-    if (s->scr_width == 0 || s->scr_height == 0)
-        return;
-
-    full_update = 0;
-    if (s->blanked != s->blank) {
-        s->blanked = s->blank;
-        full_update = 1;
-    }
-    if (s->scr_width != surface_width(surface) ||
-        s->scr_height != surface_height(surface)) {
-        qemu_console_resize(s->con, s->scr_width, s->scr_height);
-        full_update = 1;
-    }
-    if (s->blanked)
-        tc6393xb_draw_blank(s, full_update);
-    else
-        tc6393xb_draw_graphic(s, full_update);
-}
-
-
-static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    TC6393xbState *s = opaque;
-
-    switch (addr >> 8) {
-        case 0:
-            return tc6393xb_scr_readb(s, addr & 0xff);
-        case 1:
-            return tc6393xb_nand_cfg_readb(s, addr & 0xff);
-    };
-
-    if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
-//        return tc6393xb_nand_readb(s, addr & 0xff);
-        uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
-//        fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
-        return d;
-    }
-
-//    fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-
-static void tc6393xb_writeb(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size) {
-    TC6393xbState *s = opaque;
-
-    switch (addr >> 8) {
-        case 0:
-            tc6393xb_scr_writeb(s, addr & 0xff, value);
-            return;
-        case 1:
-            tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
-            return;
-    };
-
-    if ((addr &~0xff) == s->nand_phys && s->nand_enable)
-        tc6393xb_nand_writeb(s, addr & 0xff, value);
-    else
-        fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
-                (uint32_t) addr, (int)value & 0xff);
-}
-
-TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
-{
-    TC6393xbState *s;
-    DriveInfo *nand;
-    static const MemoryRegionOps tc6393xb_ops = {
-        .read = tc6393xb_readb,
-        .write = tc6393xb_writeb,
-        .endianness = DEVICE_NATIVE_ENDIAN,
-        .impl = {
-            .min_access_size = 1,
-            .max_access_size = 1,
-        },
-    };
-
-    s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
-    s->irq = irq;
-    s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
-
-    s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
-    s->blanked = 1;
-
-    s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
-
-    nand = drive_get(IF_MTD, 0, 0);
-    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
-
-    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    memory_region_init_ram(&s->vram, "tc6393xb.vram", 0x100000);
-    vmstate_register_ram_global(&s->vram);
-    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
-    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
-    s->scr_width = 480;
-    s->scr_height = 640;
-    s->con = graphic_console_init(tc6393xb_update_display,
-            NULL, /* invalidate */
-            NULL, /* screen_dump */
-            NULL, /* text_update */
-            s);
-
-    return s;
-}
diff --git a/hw/tcx.c b/hw/tcx.c
deleted file mode 100644 (file)
index c44068e..0000000
--- a/hw/tcx.c
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * QEMU TCX Frame buffer
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * 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
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-addr.h"
-
-#define MAXX 1024
-#define MAXY 768
-#define TCX_DAC_NREGS 16
-#define TCX_THC_NREGS_8  0x081c
-#define TCX_THC_NREGS_24 0x1000
-#define TCX_TEC_NREGS    0x1000
-
-typedef struct TCXState {
-    SysBusDevice busdev;
-    QemuConsole *con;
-    uint8_t *vram;
-    uint32_t *vram24, *cplane;
-    MemoryRegion vram_mem;
-    MemoryRegion vram_8bit;
-    MemoryRegion vram_24bit;
-    MemoryRegion vram_cplane;
-    MemoryRegion dac;
-    MemoryRegion tec;
-    MemoryRegion thc24;
-    MemoryRegion thc8;
-    ram_addr_t vram24_offset, cplane_offset;
-    uint32_t vram_size;
-    uint32_t palette[256];
-    uint8_t r[256], g[256], b[256];
-    uint16_t width, height, depth;
-    uint8_t dac_index, dac_state;
-} TCXState;
-
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-
-static void tcx_set_dirty(TCXState *s)
-{
-    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
-}
-
-static void tcx24_set_dirty(TCXState *s)
-{
-    memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
-    memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
-}
-
-static void update_palette_entries(TCXState *s, int start, int end)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i;
-
-    for (i = start; i < end; i++) {
-        switch (surface_bits_per_pixel(surface)) {
-        default:
-        case 8:
-            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 15:
-            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 16:
-            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 32:
-            if (is_surface_bgr(surface)) {
-                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
-            } else {
-                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
-            }
-            break;
-        }
-    }
-    if (s->depth == 24) {
-        tcx24_set_dirty(s);
-    } else {
-        tcx_set_dirty(s);
-    }
-}
-
-static void tcx_draw_line32(TCXState *s1, uint8_t *d,
-                            const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-    uint32_t *p = (uint32_t *)d;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *p++ = s1->palette[val];
-    }
-}
-
-static void tcx_draw_line16(TCXState *s1, uint8_t *d,
-                            const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-    uint16_t *p = (uint16_t *)d;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *p++ = s1->palette[val];
-    }
-}
-
-static void tcx_draw_line8(TCXState *s1, uint8_t *d,
-                           const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *d++ = s1->palette[val];
-    }
-}
-
-/*
-  XXX Could be much more optimal:
-  * detect if line/page/whole screen is in 24 bit mode
-  * if destination is also BGR, use memcpy
-  */
-static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
-                                     const uint8_t *s, int width,
-                                     const uint32_t *cplane,
-                                     const uint32_t *s24)
-{
-    DisplaySurface *surface = qemu_console_surface(s1->con);
-    int x, bgr, r, g, b;
-    uint8_t val, *p8;
-    uint32_t *p = (uint32_t *)d;
-    uint32_t dval;
-
-    bgr = is_surface_bgr(surface);
-    for(x = 0; x < width; x++, s++, s24++) {
-        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
-            // 24-bit direct, BGR order
-            p8 = (uint8_t *)s24;
-            p8++;
-            b = *p8++;
-            g = *p8++;
-            r = *p8;
-            if (bgr)
-                dval = rgb_to_pixel32bgr(r, g, b);
-            else
-                dval = rgb_to_pixel32(r, g, b);
-        } else {
-            val = *s;
-            dval = s1->palette[val];
-        }
-        *p++ = dval;
-    }
-}
-
-static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
-                              ram_addr_t cpage)
-{
-    int ret;
-
-    ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
-                                  DIRTY_MEMORY_VGA);
-    ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
-                                   DIRTY_MEMORY_VGA);
-    ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
-                                   DIRTY_MEMORY_VGA);
-    return ret;
-}
-
-static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
-                               ram_addr_t page_max, ram_addr_t page24,
-                              ram_addr_t cpage)
-{
-    memory_region_reset_dirty(&ts->vram_mem,
-                              page_min, page_max + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-    memory_region_reset_dirty(&ts->vram_mem,
-                              page24 + page_min * 4,
-                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-    memory_region_reset_dirty(&ts->vram_mem,
-                              cpage + page_min * 4,
-                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-}
-
-/* Fixed line length 1024 allows us to do nice tricks not possible on
-   VGA... */
-static void tcx_update_display(void *opaque)
-{
-    TCXState *ts = opaque;
-    DisplaySurface *surface = qemu_console_surface(ts->con);
-    ram_addr_t page, page_min, page_max;
-    int y, y_start, dd, ds;
-    uint8_t *d, *s;
-    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
-
-    if (surface_bits_per_pixel(surface) == 0) {
-        return;
-    }
-
-    page = 0;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    s = ts->vram;
-    dd = surface_stride(surface);
-    ds = 1024;
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 32:
-        f = tcx_draw_line32;
-        break;
-    case 15:
-    case 16:
-        f = tcx_draw_line16;
-        break;
-    default:
-    case 8:
-        f = tcx_draw_line8;
-        break;
-    case 0:
-        return;
-    }
-
-    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
-                                    DIRTY_MEMORY_VGA)) {
-            if (y_start < 0)
-                y_start = y;
-            if (page < page_min)
-                page_min = page;
-            if (page > page_max)
-                page_max = page;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
-                y_start = -1;
-            }
-            d += dd * 4;
-            s += ds * 4;
-        }
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        memory_region_reset_dirty(&ts->vram_mem,
-                                  page_min, page_max + TARGET_PAGE_SIZE,
-                                  DIRTY_MEMORY_VGA);
-    }
-}
-
-static void tcx24_update_display(void *opaque)
-{
-    TCXState *ts = opaque;
-    DisplaySurface *surface = qemu_console_surface(ts->con);
-    ram_addr_t page, page_min, page_max, cpage, page24;
-    int y, y_start, dd, ds;
-    uint8_t *d, *s;
-    uint32_t *cptr, *s24;
-
-    if (surface_bits_per_pixel(surface) != 32) {
-            return;
-    }
-
-    page = 0;
-    page24 = ts->vram24_offset;
-    cpage = ts->cplane_offset;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    s = ts->vram;
-    s24 = ts->vram24;
-    cptr = ts->cplane;
-    dd = surface_stride(surface);
-    ds = 1024;
-
-    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
-            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
-        if (check_dirty(ts, page, page24, cpage)) {
-            if (y_start < 0)
-                y_start = y;
-            if (page < page_min)
-                page_min = page;
-            if (page > page_max)
-                page_max = page;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
-                y_start = -1;
-            }
-            d += dd * 4;
-            s += ds * 4;
-            cptr += ds * 4;
-            s24 += ds * 4;
-        }
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        reset_dirty(ts, page_min, page_max, page24, cpage);
-    }
-}
-
-static void tcx_invalidate_display(void *opaque)
-{
-    TCXState *s = opaque;
-
-    tcx_set_dirty(s);
-    qemu_console_resize(s->con, s->width, s->height);
-}
-
-static void tcx24_invalidate_display(void *opaque)
-{
-    TCXState *s = opaque;
-
-    tcx_set_dirty(s);
-    tcx24_set_dirty(s);
-    qemu_console_resize(s->con, s->width, s->height);
-}
-
-static int vmstate_tcx_post_load(void *opaque, int version_id)
-{
-    TCXState *s = opaque;
-
-    update_palette_entries(s, 0, 256);
-    if (s->depth == 24) {
-        tcx24_set_dirty(s);
-    } else {
-        tcx_set_dirty(s);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_tcx = {
-    .name ="tcx",
-    .version_id = 4,
-    .minimum_version_id = 4,
-    .minimum_version_id_old = 4,
-    .post_load = vmstate_tcx_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16(height, TCXState),
-        VMSTATE_UINT16(width, TCXState),
-        VMSTATE_UINT16(depth, TCXState),
-        VMSTATE_BUFFER(r, TCXState),
-        VMSTATE_BUFFER(g, TCXState),
-        VMSTATE_BUFFER(b, TCXState),
-        VMSTATE_UINT8(dac_index, TCXState),
-        VMSTATE_UINT8(dac_state, TCXState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void tcx_reset(DeviceState *d)
-{
-    TCXState *s = container_of(d, TCXState, busdev.qdev);
-
-    /* Initialize palette */
-    memset(s->r, 0, 256);
-    memset(s->g, 0, 256);
-    memset(s->b, 0, 256);
-    s->r[255] = s->g[255] = s->b[255] = 255;
-    update_palette_entries(s, 0, 256);
-    memset(s->vram, 0, MAXX*MAXY);
-    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
-                              DIRTY_MEMORY_VGA);
-    s->dac_index = 0;
-    s->dac_state = 0;
-}
-
-static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    return 0;
-}
-
-static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
-                           unsigned size)
-{
-    TCXState *s = opaque;
-
-    switch (addr) {
-    case 0:
-        s->dac_index = val >> 24;
-        s->dac_state = 0;
-        break;
-    case 4:
-        switch (s->dac_state) {
-        case 0:
-            s->r[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_state++;
-            break;
-        case 1:
-            s->g[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_state++;
-            break;
-        case 2:
-            s->b[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
-        default:
-            s->dac_state = 0;
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps tcx_dac_ops = {
-    .read = tcx_dac_readl,
-    .write = tcx_dac_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t dummy_readl(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    return 0;
-}
-
-static void dummy_writel(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps dummy_ops = {
-    .read = dummy_readl,
-    .write = dummy_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int tcx_init1(SysBusDevice *dev)
-{
-    TCXState *s = FROM_SYSBUS(TCXState, dev);
-    ram_addr_t vram_offset = 0;
-    int size;
-    uint8_t *vram_base;
-
-    memory_region_init_ram(&s->vram_mem, "tcx.vram",
-                           s->vram_size * (1 + 4 + 4));
-    vmstate_register_ram_global(&s->vram_mem);
-    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
-
-    /* 8-bit plane */
-    s->vram = vram_base;
-    size = s->vram_size;
-    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
-                             &s->vram_mem, vram_offset, size);
-    sysbus_init_mmio(dev, &s->vram_8bit);
-    vram_offset += size;
-    vram_base += size;
-
-    /* DAC */
-    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
-    sysbus_init_mmio(dev, &s->dac);
-
-    /* TEC (dummy) */
-    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
-    sysbus_init_mmio(dev, &s->tec);
-    /* THC: NetBSD writes here even with 8-bit display: dummy */
-    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
-                          TCX_THC_NREGS_24);
-    sysbus_init_mmio(dev, &s->thc24);
-
-    if (s->depth == 24) {
-        /* 24-bit plane */
-        size = s->vram_size * 4;
-        s->vram24 = (uint32_t *)vram_base;
-        s->vram24_offset = vram_offset;
-        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
-                                 &s->vram_mem, vram_offset, size);
-        sysbus_init_mmio(dev, &s->vram_24bit);
-        vram_offset += size;
-        vram_base += size;
-
-        /* Control plane */
-        size = s->vram_size * 4;
-        s->cplane = (uint32_t *)vram_base;
-        s->cplane_offset = vram_offset;
-        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
-                                 &s->vram_mem, vram_offset, size);
-        sysbus_init_mmio(dev, &s->vram_cplane);
-
-        s->con = graphic_console_init(tcx24_update_display,
-                                      tcx24_invalidate_display,
-                                      tcx24_screen_dump, NULL, s);
-    } else {
-        /* THC 8 bit (dummy) */
-        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
-                              TCX_THC_NREGS_8);
-        sysbus_init_mmio(dev, &s->thc8);
-
-        s->con = graphic_console_init(tcx_update_display,
-                                      tcx_invalidate_display,
-                                      tcx_screen_dump, NULL, s);
-    }
-
-    qemu_console_resize(s->con, s->width, s->height);
-    return 0;
-}
-
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp)
-{
-    TCXState *s = opaque;
-    FILE *f;
-    uint8_t *d, *d1, v;
-    int ret, y, x;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = s->vram;
-    for(y = 0; y < s->height; y++) {
-        d = d1;
-        for(x = 0; x < s->width; x++) {
-            v = *d;
-            ret = fputc(s->r[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            ret = fputc(s->g[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            ret = fputc(s->b[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            d++;
-        }
-        d1 += MAXX;
-    }
-
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
-                              Error **errp)
-{
-    TCXState *s = opaque;
-    FILE *f;
-    uint8_t *d, *d1, v;
-    uint32_t *s24, *cptr, dval;
-    int ret, y, x;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = s->vram;
-    s24 = s->vram24;
-    cptr = s->cplane;
-    for(y = 0; y < s->height; y++) {
-        d = d1;
-        for(x = 0; x < s->width; x++, d++, s24++) {
-            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
-                dval = *s24 & 0x00ffffff;
-                ret = fputc((dval >> 16) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((dval >> 8) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(dval & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-            } else {
-                v = *d;
-                ret = fputc(s->r[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->g[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->b[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-            }
-        }
-        d1 += MAXX;
-    }
-
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static Property tcx_properties[] = {
-    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
-    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
-    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
-    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tcx_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = tcx_init1;
-    dc->reset = tcx_reset;
-    dc->vmsd = &vmstate_tcx;
-    dc->props = tcx_properties;
-}
-
-static const TypeInfo tcx_info = {
-    .name          = "SUNW,tcx",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(TCXState),
-    .class_init    = tcx_class_init,
-};
-
-static void tcx_register_types(void)
-{
-    type_register_static(&tcx_info);
-}
-
-type_init(tcx_register_types)
diff --git a/hw/vga.c b/hw/vga.c
deleted file mode 100644 (file)
index dc31fd5..0000000
--- a/hw/vga.c
+++ /dev/null
@@ -1,2457 +0,0 @@
-/*
- * QEMU VGA Emulator.
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "hw/hw.h"
-#include "hw/vga.h"
-#include "ui/console.h"
-#include "hw/i386/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/xen/xen.h"
-#include "trace.h"
-
-//#define DEBUG_VGA
-//#define DEBUG_VGA_MEM
-//#define DEBUG_VGA_REG
-
-//#define DEBUG_BOCHS_VBE
-
-/* 16 state changes per vertical frame @60 Hz */
-#define VGA_TEXT_CURSOR_PERIOD_MS       (1000 * 2 * 16 / 60)
-
-/*
- * Video Graphics Array (VGA)
- *
- * Chipset docs for original IBM VGA:
- * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
- *
- * FreeVGA site:
- * http://www.osdever.net/FreeVGA/home.htm
- *
- * Standard VGA features and Bochs VBE extensions are implemented.
- */
-
-/* force some bits to zero */
-const uint8_t sr_mask[8] = {
-    0x03,
-    0x3d,
-    0x0f,
-    0x3f,
-    0x0e,
-    0x00,
-    0x00,
-    0xff,
-};
-
-const uint8_t gr_mask[16] = {
-    0x0f, /* 0x00 */
-    0x0f, /* 0x01 */
-    0x0f, /* 0x02 */
-    0x1f, /* 0x03 */
-    0x03, /* 0x04 */
-    0x7b, /* 0x05 */
-    0x0f, /* 0x06 */
-    0x0f, /* 0x07 */
-    0xff, /* 0x08 */
-    0x00, /* 0x09 */
-    0x00, /* 0x0a */
-    0x00, /* 0x0b */
-    0x00, /* 0x0c */
-    0x00, /* 0x0d */
-    0x00, /* 0x0e */
-    0x00, /* 0x0f */
-};
-
-#define cbswap_32(__x) \
-((uint32_t)( \
-               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
-               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
-               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
-               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) cbswap_32(x)
-#else
-#define PAT(x) (x)
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define BIG 1
-#else
-#define BIG 0
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
-#else
-#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
-#endif
-
-static const uint32_t mask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
-
-#undef PAT
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) (x)
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static const uint32_t dmask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
-
-static const uint32_t dmask4[4] = {
-    PAT(0x00000000),
-    PAT(0x0000ffff),
-    PAT(0xffff0000),
-    PAT(0xffffffff),
-};
-
-static uint32_t expand4[256];
-static uint16_t expand2[256];
-static uint8_t expand4to8[16];
-
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-
-static void vga_update_memory_access(VGACommonState *s)
-{
-    MemoryRegion *region, *old_region = s->chain4_alias;
-    hwaddr base, offset, size;
-
-    s->chain4_alias = NULL;
-
-    if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
-        VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
-        offset = 0;
-        switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
-        case 0:
-            base = 0xa0000;
-            size = 0x20000;
-            break;
-        case 1:
-            base = 0xa0000;
-            size = 0x10000;
-            offset = s->bank_offset;
-            break;
-        case 2:
-            base = 0xb0000;
-            size = 0x8000;
-            break;
-        case 3:
-        default:
-            base = 0xb8000;
-            size = 0x8000;
-            break;
-        }
-        base += isa_mem_base;
-        region = g_malloc(sizeof(*region));
-        memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
-        memory_region_add_subregion_overlap(s->legacy_address_space, base,
-                                            region, 2);
-        s->chain4_alias = region;
-    }
-    if (old_region) {
-        memory_region_del_subregion(s->legacy_address_space, old_region);
-        memory_region_destroy(old_region);
-        g_free(old_region);
-        s->plane_updated = 0xf;
-    }
-}
-
-static void vga_dumb_update_retrace_info(VGACommonState *s)
-{
-    (void) s;
-}
-
-static void vga_precise_update_retrace_info(VGACommonState *s)
-{
-    int htotal_chars;
-    int hretr_start_char;
-    int hretr_skew_chars;
-    int hretr_end_char;
-
-    int vtotal_lines;
-    int vretr_start_line;
-    int vretr_end_line;
-
-    int dots;
-#if 0
-    int div2, sldiv2;
-#endif
-    int clocking_mode;
-    int clock_sel;
-    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
-    int64_t chars_per_sec;
-    struct vga_precise_retrace *r = &s->retrace_info.precise;
-
-    htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
-    hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
-    hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
-    hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
-
-    vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
-                    (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
-                      ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
-    vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
-        ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
-          ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
-    vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
-
-    clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
-    clock_sel = (s->msr >> 2) & 3;
-    dots = (s->msr & 1) ? 8 : 9;
-
-    chars_per_sec = clk_hz[clock_sel] / dots;
-
-    htotal_chars <<= clocking_mode;
-
-    r->total_chars = vtotal_lines * htotal_chars;
-    if (r->freq) {
-        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
-    } else {
-        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
-    }
-
-    r->vstart = vretr_start_line;
-    r->vend = r->vstart + vretr_end_line + 1;
-
-    r->hstart = hretr_start_char + hretr_skew_chars;
-    r->hend = r->hstart + hretr_end_char + 1;
-    r->htotal = htotal_chars;
-
-#if 0
-    div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
-    sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
-    printf (
-        "hz=%f\n"
-        "htotal = %d\n"
-        "hretr_start = %d\n"
-        "hretr_skew = %d\n"
-        "hretr_end = %d\n"
-        "vtotal = %d\n"
-        "vretr_start = %d\n"
-        "vretr_end = %d\n"
-        "div2 = %d sldiv2 = %d\n"
-        "clocking_mode = %d\n"
-        "clock_sel = %d %d\n"
-        "dots = %d\n"
-        "ticks/char = %" PRId64 "\n"
-        "\n",
-        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
-        htotal_chars,
-        hretr_start_char,
-        hretr_skew_chars,
-        hretr_end_char,
-        vtotal_lines,
-        vretr_start_line,
-        vretr_end_line,
-        div2, sldiv2,
-        clocking_mode,
-        clock_sel,
-        clk_hz[clock_sel],
-        dots,
-        r->ticks_per_char
-        );
-#endif
-}
-
-static uint8_t vga_precise_retrace(VGACommonState *s)
-{
-    struct vga_precise_retrace *r = &s->retrace_info.precise;
-    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
-
-    if (r->total_chars) {
-        int cur_line, cur_line_char, cur_char;
-        int64_t cur_tick;
-
-        cur_tick = qemu_get_clock_ns(vm_clock);
-
-        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
-        cur_line = cur_char / r->htotal;
-
-        if (cur_line >= r->vstart && cur_line <= r->vend) {
-            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
-        } else {
-            cur_line_char = cur_char % r->htotal;
-            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
-                val |= ST01_DISP_ENABLE;
-            }
-        }
-
-        return val;
-    } else {
-        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
-    }
-}
-
-static uint8_t vga_dumb_retrace(VGACommonState *s)
-{
-    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
-}
-
-int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
-{
-    if (s->msr & VGA_MIS_COLOR) {
-        /* Color */
-        return (addr >= 0x3b0 && addr <= 0x3bf);
-    } else {
-        /* Monochrome */
-        return (addr >= 0x3d0 && addr <= 0x3df);
-    }
-}
-
-uint32_t vga_ioport_read(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    int val, index;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (vga_ioport_invalid(s, addr)) {
-        val = 0xff;
-    } else {
-        switch(addr) {
-        case VGA_ATT_W:
-            if (s->ar_flip_flop == 0) {
-                val = s->ar_index;
-            } else {
-                val = 0;
-            }
-            break;
-        case VGA_ATT_R:
-            index = s->ar_index & 0x1f;
-            if (index < VGA_ATT_C) {
-                val = s->ar[index];
-            } else {
-                val = 0;
-            }
-            break;
-        case VGA_MIS_W:
-            val = s->st00;
-            break;
-        case VGA_SEQ_I:
-            val = s->sr_index;
-            break;
-        case VGA_SEQ_D:
-            val = s->sr[s->sr_index];
-#ifdef DEBUG_VGA_REG
-            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
-            break;
-        case VGA_PEL_IR:
-            val = s->dac_state;
-            break;
-        case VGA_PEL_IW:
-            val = s->dac_write_index;
-            break;
-        case VGA_PEL_D:
-            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
-            if (++s->dac_sub_index == 3) {
-                s->dac_sub_index = 0;
-                s->dac_read_index++;
-            }
-            break;
-        case VGA_FTC_R:
-            val = s->fcr;
-            break;
-        case VGA_MIS_R:
-            val = s->msr;
-            break;
-        case VGA_GFX_I:
-            val = s->gr_index;
-            break;
-        case VGA_GFX_D:
-            val = s->gr[s->gr_index];
-#ifdef DEBUG_VGA_REG
-            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
-#endif
-            break;
-        case VGA_CRT_IM:
-        case VGA_CRT_IC:
-            val = s->cr_index;
-            break;
-        case VGA_CRT_DM:
-        case VGA_CRT_DC:
-            val = s->cr[s->cr_index];
-#ifdef DEBUG_VGA_REG
-            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
-#endif
-            break;
-        case VGA_IS1_RM:
-        case VGA_IS1_RC:
-            /* just toggle to fool polling */
-            val = s->st01 = s->retrace(s);
-            s->ar_flip_flop = 0;
-            break;
-        default:
-            val = 0x00;
-            break;
-        }
-    }
-#if defined(DEBUG_VGA)
-    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
-void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-    int index;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    /* check port range access depending on color/monochrome mode */
-    if (vga_ioport_invalid(s, addr)) {
-        return;
-    }
-#ifdef DEBUG_VGA
-    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
-    switch(addr) {
-    case VGA_ATT_W:
-        if (s->ar_flip_flop == 0) {
-            val &= 0x3f;
-            s->ar_index = val;
-        } else {
-            index = s->ar_index & 0x1f;
-            switch(index) {
-            case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
-                s->ar[index] = val & 0x3f;
-                break;
-            case VGA_ATC_MODE:
-                s->ar[index] = val & ~0x10;
-                break;
-            case VGA_ATC_OVERSCAN:
-                s->ar[index] = val;
-                break;
-            case VGA_ATC_PLANE_ENABLE:
-                s->ar[index] = val & ~0xc0;
-                break;
-            case VGA_ATC_PEL:
-                s->ar[index] = val & ~0xf0;
-                break;
-            case VGA_ATC_COLOR_PAGE:
-                s->ar[index] = val & ~0xf0;
-                break;
-            default:
-                break;
-            }
-        }
-        s->ar_flip_flop ^= 1;
-        break;
-    case VGA_MIS_W:
-        s->msr = val & ~0x10;
-        s->update_retrace_info(s);
-        break;
-    case VGA_SEQ_I:
-        s->sr_index = val & 7;
-        break;
-    case VGA_SEQ_D:
-#ifdef DEBUG_VGA_REG
-        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
-#endif
-        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
-        if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
-            s->update_retrace_info(s);
-        }
-        vga_update_memory_access(s);
-        break;
-    case VGA_PEL_IR:
-        s->dac_read_index = val;
-        s->dac_sub_index = 0;
-        s->dac_state = 3;
-        break;
-    case VGA_PEL_IW:
-        s->dac_write_index = val;
-        s->dac_sub_index = 0;
-        s->dac_state = 0;
-        break;
-    case VGA_PEL_D:
-        s->dac_cache[s->dac_sub_index] = val;
-        if (++s->dac_sub_index == 3) {
-            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
-            s->dac_sub_index = 0;
-            s->dac_write_index++;
-        }
-        break;
-    case VGA_GFX_I:
-        s->gr_index = val & 0x0f;
-        break;
-    case VGA_GFX_D:
-#ifdef DEBUG_VGA_REG
-        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
-#endif
-        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
-        vga_update_memory_access(s);
-        break;
-    case VGA_CRT_IM:
-    case VGA_CRT_IC:
-        s->cr_index = val;
-        break;
-    case VGA_CRT_DM:
-    case VGA_CRT_DC:
-#ifdef DEBUG_VGA_REG
-        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
-#endif
-        /* handle CR0-7 protection */
-        if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
-            s->cr_index <= VGA_CRTC_OVERFLOW) {
-            /* can always write bit 4 of CR7 */
-            if (s->cr_index == VGA_CRTC_OVERFLOW) {
-                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
-                    (val & 0x10);
-            }
-            return;
-        }
-        s->cr[s->cr_index] = val;
-
-        switch(s->cr_index) {
-        case VGA_CRTC_H_TOTAL:
-        case VGA_CRTC_H_SYNC_START:
-        case VGA_CRTC_H_SYNC_END:
-        case VGA_CRTC_V_TOTAL:
-        case VGA_CRTC_OVERFLOW:
-        case VGA_CRTC_V_SYNC_END:
-        case VGA_CRTC_MODE:
-            s->update_retrace_info(s);
-            break;
-        }
-        break;
-    case VGA_IS1_RM:
-    case VGA_IS1_RC:
-        s->fcr = val & 0x10;
-        break;
-    }
-}
-
-static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    uint32_t val;
-    val = s->vbe_index;
-    return val;
-}
-
-uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    uint32_t val;
-
-    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
-        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
-            switch(s->vbe_index) {
-                /* XXX: do not hardcode ? */
-            case VBE_DISPI_INDEX_XRES:
-                val = VBE_DISPI_MAX_XRES;
-                break;
-            case VBE_DISPI_INDEX_YRES:
-                val = VBE_DISPI_MAX_YRES;
-                break;
-            case VBE_DISPI_INDEX_BPP:
-                val = VBE_DISPI_MAX_BPP;
-                break;
-            default:
-                val = s->vbe_regs[s->vbe_index];
-                break;
-            }
-        } else {
-            val = s->vbe_regs[s->vbe_index];
-        }
-    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
-        val = s->vram_size / (64 * 1024);
-    } else {
-        val = 0;
-    }
-#ifdef DEBUG_BOCHS_VBE
-    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
-    return val;
-}
-
-void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-    s->vbe_index = val;
-}
-
-void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-
-    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
-#ifdef DEBUG_BOCHS_VBE
-        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
-        switch(s->vbe_index) {
-        case VBE_DISPI_INDEX_ID:
-            if (val == VBE_DISPI_ID0 ||
-                val == VBE_DISPI_ID1 ||
-                val == VBE_DISPI_ID2 ||
-                val == VBE_DISPI_ID3 ||
-                val == VBE_DISPI_ID4) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_XRES:
-            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_YRES:
-            if (val <= VBE_DISPI_MAX_YRES) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_BPP:
-            if (val == 0)
-                val = 8;
-            if (val == 4 || val == 8 || val == 15 ||
-                val == 16 || val == 24 || val == 32) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_BANK:
-            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
-              val &= (s->vbe_bank_mask >> 2);
-            } else {
-              val &= s->vbe_bank_mask;
-            }
-            s->vbe_regs[s->vbe_index] = val;
-            s->bank_offset = (val << 16);
-            vga_update_memory_access(s);
-            break;
-        case VBE_DISPI_INDEX_ENABLE:
-            if ((val & VBE_DISPI_ENABLED) &&
-                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
-                int h, shift_control;
-
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
-                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
-                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
-                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
-                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
-
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
-                else
-                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
-                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                s->vbe_start_addr = 0;
-
-                /* clear the screen (should be done in BIOS) */
-                if (!(val & VBE_DISPI_NOCLEARMEM)) {
-                    memset(s->vram_ptr, 0,
-                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
-                }
-
-                /* we initialize the VGA graphic mode (should be done
-                   in BIOS) */
-                /* graphic mode + memory map 1 */
-                s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
-                    VGA_GR06_GRAPHICS_MODE;
-                s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
-                s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
-                /* width */
-                s->cr[VGA_CRTC_H_DISP] =
-                    (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
-                /* height (only meaningful if < 1024) */
-                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
-                s->cr[VGA_CRTC_V_DISP_END] = h;
-                s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
-                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
-                /* line compare to 1023 */
-                s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
-                s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
-                s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
-
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
-                    shift_control = 0;
-                    s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
-                } else {
-                    shift_control = 2;
-                    /* set chain 4 mode */
-                    s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
-                    /* activate all planes */
-                    s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
-                }
-                s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
-                    (shift_control << 5);
-                s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
-            } else {
-                /* XXX: the bios should do that */
-                s->bank_offset = 0;
-            }
-            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
-            s->vbe_regs[s->vbe_index] = val;
-            vga_update_memory_access(s);
-            break;
-        case VBE_DISPI_INDEX_VIRT_WIDTH:
-            {
-                int w, h, line_offset;
-
-                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
-                    return;
-                w = val;
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    line_offset = w >> 1;
-                else
-                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                h = s->vram_size / line_offset;
-                /* XXX: support weird bochs semantics ? */
-                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
-                    return;
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
-                s->vbe_line_offset = line_offset;
-            }
-            break;
-        case VBE_DISPI_INDEX_X_OFFSET:
-        case VBE_DISPI_INDEX_Y_OFFSET:
-            {
-                int x;
-                s->vbe_regs[s->vbe_index] = val;
-                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
-                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    s->vbe_start_addr += x >> 1;
-                else
-                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                s->vbe_start_addr >>= 2;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
-{
-    int memory_map_mode, plane;
-    uint32_t ret;
-
-    /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
-    addr &= 0x1ffff;
-    switch(memory_map_mode) {
-    case 0:
-        break;
-    case 1:
-        if (addr >= 0x10000)
-            return 0xff;
-        addr += s->bank_offset;
-        break;
-    case 2:
-        addr -= 0x10000;
-        if (addr >= 0x8000)
-            return 0xff;
-        break;
-    default:
-    case 3:
-        addr -= 0x18000;
-        if (addr >= 0x8000)
-            return 0xff;
-        break;
-    }
-
-    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
-        /* chain 4 mode : simplest access */
-        ret = s->vram_ptr[addr];
-    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
-        /* odd/even mode (aka text mode mapping) */
-        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
-        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
-    } else {
-        /* standard VGA latched access */
-        s->latch = ((uint32_t *)s->vram_ptr)[addr];
-
-        if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
-            /* read mode 0 */
-            plane = s->gr[VGA_GFX_PLANE_READ];
-            ret = GET_PLANE(s->latch, plane);
-        } else {
-            /* read mode 1 */
-            ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
-                mask16[s->gr[VGA_GFX_COMPARE_MASK]];
-            ret |= ret >> 16;
-            ret |= ret >> 8;
-            ret = (~ret) & 0xff;
-        }
-    }
-    return ret;
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
-{
-    int memory_map_mode, plane, write_mode, b, func_select, mask;
-    uint32_t write_mask, bit_mask, set_mask;
-
-#ifdef DEBUG_VGA_MEM
-    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
-#endif
-    /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
-    addr &= 0x1ffff;
-    switch(memory_map_mode) {
-    case 0:
-        break;
-    case 1:
-        if (addr >= 0x10000)
-            return;
-        addr += s->bank_offset;
-        break;
-    case 2:
-        addr -= 0x10000;
-        if (addr >= 0x8000)
-            return;
-        break;
-    default:
-    case 3:
-        addr -= 0x18000;
-        if (addr >= 0x8000)
-            return;
-        break;
-    }
-
-    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
-        /* chain 4 mode : simplest access */
-        plane = addr & 3;
-        mask = (1 << plane);
-        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
-            s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
-            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
-            s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr, 1);
-        }
-    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
-        /* odd/even mode (aka text mode mapping) */
-        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
-        mask = (1 << plane);
-        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
-            addr = ((addr & ~1) << 1) | plane;
-            s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
-            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
-            s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr, 1);
-        }
-    } else {
-        /* standard VGA latched access */
-        write_mode = s->gr[VGA_GFX_MODE] & 3;
-        switch(write_mode) {
-        default:
-        case 0:
-            /* rotate */
-            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
-            val = ((val >> b) | (val << (8 - b))) & 0xff;
-            val |= val << 8;
-            val |= val << 16;
-
-            /* apply set/reset mask */
-            set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
-            val = (val & ~set_mask) |
-                (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
-            bit_mask = s->gr[VGA_GFX_BIT_MASK];
-            break;
-        case 1:
-            val = s->latch;
-            goto do_write;
-        case 2:
-            val = mask16[val & 0x0f];
-            bit_mask = s->gr[VGA_GFX_BIT_MASK];
-            break;
-        case 3:
-            /* rotate */
-            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
-            val = (val >> b) | (val << (8 - b));
-
-            bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
-            val = mask16[s->gr[VGA_GFX_SR_VALUE]];
-            break;
-        }
-
-        /* apply logical operation */
-        func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
-        switch(func_select) {
-        case 0:
-        default:
-            /* nothing to do */
-            break;
-        case 1:
-            /* and */
-            val &= s->latch;
-            break;
-        case 2:
-            /* or */
-            val |= s->latch;
-            break;
-        case 3:
-            /* xor */
-            val ^= s->latch;
-            break;
-        }
-
-        /* apply bit mask */
-        bit_mask |= bit_mask << 8;
-        bit_mask |= bit_mask << 16;
-        val = (val & bit_mask) | (s->latch & ~bit_mask);
-
-    do_write:
-        /* mask data according to sr[2] */
-        mask = s->sr[VGA_SEQ_PLANE_WRITE];
-        s->plane_updated |= mask; /* only used to detect font change */
-        write_mask = mask16[mask];
-        ((uint32_t *)s->vram_ptr)[addr] =
-            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
-            (val & write_mask);
-#ifdef DEBUG_VGA_MEM
-        printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
-               addr * 4, write_mask, val);
-#endif
-        memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
-    }
-}
-
-typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
-                             const uint8_t *font_ptr, int h,
-                             uint32_t fgcol, uint32_t bgcol);
-typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
-                                  const uint8_t *font_ptr, int h,
-                                  uint32_t fgcol, uint32_t bgcol, int dup9);
-typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
-                                const uint8_t *s, int width);
-
-#define DEPTH 8
-#include "hw/vga_template.h"
-
-#define DEPTH 15
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "hw/vga_template.h"
-
-#define DEPTH 16
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "hw/vga_template.h"
-
-#define DEPTH 32
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "hw/vga_template.h"
-
-static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel8(r, g, b);
-    col |= col << 8;
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel15(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
-                                          unsigned int b)
-{
-    unsigned int col;
-    col = rgb_to_pixel15bgr(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel16(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
-                                          unsigned int b)
-{
-    unsigned int col;
-    col = rgb_to_pixel16bgr(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel32(r, g, b);
-    return col;
-}
-
-static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel32bgr(r, g, b);
-    return col;
-}
-
-/* return true if the palette was modified */
-static int update_palette16(VGACommonState *s)
-{
-    int full_update, i;
-    uint32_t v, col, *palette;
-
-    full_update = 0;
-    palette = s->last_palette;
-    for(i = 0; i < 16; i++) {
-        v = s->ar[i];
-        if (s->ar[VGA_ATC_MODE] & 0x80) {
-            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
-        } else {
-            v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
-        }
-        v = v * 3;
-        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
-                              c6_to_8(s->palette[v + 1]),
-                              c6_to_8(s->palette[v + 2]));
-        if (col != palette[i]) {
-            full_update = 1;
-            palette[i] = col;
-        }
-    }
-    return full_update;
-}
-
-/* return true if the palette was modified */
-static int update_palette256(VGACommonState *s)
-{
-    int full_update, i;
-    uint32_t v, col, *palette;
-
-    full_update = 0;
-    palette = s->last_palette;
-    v = 0;
-    for(i = 0; i < 256; i++) {
-        if (s->dac_8bit) {
-          col = s->rgb_to_pixel(s->palette[v],
-                                s->palette[v + 1],
-                                s->palette[v + 2]);
-        } else {
-          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
-                                c6_to_8(s->palette[v + 1]),
-                                c6_to_8(s->palette[v + 2]));
-        }
-        if (col != palette[i]) {
-            full_update = 1;
-            palette[i] = col;
-        }
-        v += 3;
-    }
-    return full_update;
-}
-
-static void vga_get_offsets(VGACommonState *s,
-                            uint32_t *pline_offset,
-                            uint32_t *pstart_addr,
-                            uint32_t *pline_compare)
-{
-    uint32_t start_addr, line_offset, line_compare;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        line_offset = s->vbe_line_offset;
-        start_addr = s->vbe_start_addr;
-        line_compare = 65535;
-    } else {
-        /* compute line_offset in bytes */
-        line_offset = s->cr[VGA_CRTC_OFFSET];
-        line_offset <<= 3;
-
-        /* starting address */
-        start_addr = s->cr[VGA_CRTC_START_LO] |
-            (s->cr[VGA_CRTC_START_HI] << 8);
-
-        /* line compare */
-        line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
-            ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
-    }
-    *pline_offset = line_offset;
-    *pstart_addr = start_addr;
-    *pline_compare = line_compare;
-}
-
-/* update start_addr and line_offset. Return TRUE if modified */
-static int update_basic_params(VGACommonState *s)
-{
-    int full_update;
-    uint32_t start_addr, line_offset, line_compare;
-
-    full_update = 0;
-
-    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
-
-    if (line_offset != s->line_offset ||
-        start_addr != s->start_addr ||
-        line_compare != s->line_compare) {
-        s->line_offset = line_offset;
-        s->start_addr = start_addr;
-        s->line_compare = line_compare;
-        full_update = 1;
-    }
-    return full_update;
-}
-
-#define NB_DEPTHS 7
-
-static inline int get_depth_index(DisplaySurface *s)
-{
-    switch (surface_bits_per_pixel(s)) {
-    default:
-    case 8:
-        return 0;
-    case 15:
-        return 1;
-    case 16:
-        return 2;
-    case 32:
-        if (is_surface_bgr(s)) {
-            return 4;
-        } else {
-            return 3;
-        }
-    }
-}
-
-static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
-    vga_draw_glyph8_8,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_32,
-    vga_draw_glyph8_32,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_16,
-};
-
-static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
-    vga_draw_glyph16_8,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_32,
-    vga_draw_glyph16_32,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_16,
-};
-
-static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
-    vga_draw_glyph9_8,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_32,
-    vga_draw_glyph9_32,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_16,
-};
-
-static const uint8_t cursor_glyph[32 * 4] = {
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
-                                    int *pcwidth, int *pcheight)
-{
-    int width, cwidth, height, cheight;
-
-    /* total width & height */
-    cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
-    cwidth = 8;
-    if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
-        cwidth = 9;
-    }
-    if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
-        cwidth = 16; /* NOTE: no 18 pixel wide */
-    }
-    width = (s->cr[VGA_CRTC_H_DISP] + 1);
-    if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
-        /* ugly hack for CGA 160x100x16 - explain me the logic */
-        height = 100;
-    } else {
-        height = s->cr[VGA_CRTC_V_DISP_END] |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
-        height = (height + 1) / cheight;
-    }
-
-    *pwidth = width;
-    *pheight = height;
-    *pcwidth = cwidth;
-    *pcheight = cheight;
-}
-
-typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-
-static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
-    rgb_to_pixel8_dup,
-    rgb_to_pixel15_dup,
-    rgb_to_pixel16_dup,
-    rgb_to_pixel32_dup,
-    rgb_to_pixel32bgr_dup,
-    rgb_to_pixel15bgr_dup,
-    rgb_to_pixel16bgr_dup,
-};
-
-/*
- * Text mode update
- * Missing:
- * - double scan
- * - double width
- * - underline
- * - flashing
- */
-static void vga_draw_text(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
-    int cx_min, cx_max, linesize, x_incr, line, line1;
-    uint32_t offset, fgcol, bgcol, v, cursor_offset;
-    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
-    const uint8_t *font_ptr, *font_base[2];
-    int dup9, line_offset, depth_index;
-    uint32_t *palette;
-    uint32_t *ch_attr_ptr;
-    vga_draw_glyph8_func *vga_draw_glyph8;
-    vga_draw_glyph9_func *vga_draw_glyph9;
-    int64_t now = qemu_get_clock_ms(vm_clock);
-
-    /* compute font data address (in plane 2) */
-    v = s->sr[VGA_SEQ_CHARACTER_MAP];
-    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
-    if (offset != s->font_offsets[0]) {
-        s->font_offsets[0] = offset;
-        full_update = 1;
-    }
-    font_base[0] = s->vram_ptr + offset;
-
-    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
-    font_base[1] = s->vram_ptr + offset;
-    if (offset != s->font_offsets[1]) {
-        s->font_offsets[1] = offset;
-        full_update = 1;
-    }
-    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
-        /* if the plane 2 was modified since the last display, it
-           indicates the font may have been modified */
-        s->plane_updated = 0;
-        full_update = 1;
-    }
-    full_update |= update_basic_params(s);
-
-    line_offset = s->line_offset;
-
-    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
-    if ((height * width) <= 1) {
-        /* better than nothing: exit if transient size is too small */
-        return;
-    }
-    if ((height * width) > CH_ATTR_SIZE) {
-        /* better than nothing: exit if transient size is too big */
-        return;
-    }
-
-    if (width != s->last_width || height != s->last_height ||
-        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
-        s->last_scr_width = width * cw;
-        s->last_scr_height = height * cheight;
-        qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
-        surface = qemu_console_surface(s->con);
-        dpy_text_resize(s->con, width, height);
-        s->last_depth = 0;
-        s->last_width = width;
-        s->last_height = height;
-        s->last_ch = cheight;
-        s->last_cw = cw;
-        full_update = 1;
-    }
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-    full_update |= update_palette16(s);
-    palette = s->last_palette;
-    x_incr = cw * surface_bytes_per_pixel(surface);
-
-    if (full_update) {
-        s->full_update_text = 1;
-    }
-    if (s->full_update_gfx) {
-        s->full_update_gfx = 0;
-        full_update |= 1;
-    }
-
-    cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
-                     s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
-    if (cursor_offset != s->cursor_offset ||
-        s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
-        s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
-      /* if the cursor position changed, we update the old and new
-         chars */
-        if (s->cursor_offset < CH_ATTR_SIZE)
-            s->last_ch_attr[s->cursor_offset] = -1;
-        if (cursor_offset < CH_ATTR_SIZE)
-            s->last_ch_attr[cursor_offset] = -1;
-        s->cursor_offset = cursor_offset;
-        s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
-        s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
-    }
-    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
-    if (now >= s->cursor_blink_time) {
-        s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
-        s->cursor_visible_phase = !s->cursor_visible_phase;
-    }
-
-    depth_index = get_depth_index(surface);
-    if (cw == 16)
-        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
-    else
-        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
-    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
-
-    dest = surface_data(surface);
-    linesize = surface_stride(surface);
-    ch_attr_ptr = s->last_ch_attr;
-    line = 0;
-    offset = s->start_addr * 4;
-    for(cy = 0; cy < height; cy++) {
-        d1 = dest;
-        src = s->vram_ptr + offset;
-        cx_min = width;
-        cx_max = -1;
-        for(cx = 0; cx < width; cx++) {
-            ch_attr = *(uint16_t *)src;
-            if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
-                if (cx < cx_min)
-                    cx_min = cx;
-                if (cx > cx_max)
-                    cx_max = cx;
-                *ch_attr_ptr = ch_attr;
-#ifdef HOST_WORDS_BIGENDIAN
-                ch = ch_attr >> 8;
-                cattr = ch_attr & 0xff;
-#else
-                ch = ch_attr & 0xff;
-                cattr = ch_attr >> 8;
-#endif
-                font_ptr = font_base[(cattr >> 3) & 1];
-                font_ptr += 32 * 4 * ch;
-                bgcol = palette[cattr >> 4];
-                fgcol = palette[cattr & 0x0f];
-                if (cw != 9) {
-                    vga_draw_glyph8(d1, linesize,
-                                    font_ptr, cheight, fgcol, bgcol);
-                } else {
-                    dup9 = 0;
-                    if (ch >= 0xb0 && ch <= 0xdf &&
-                        (s->ar[VGA_ATC_MODE] & 0x04)) {
-                        dup9 = 1;
-                    }
-                    vga_draw_glyph9(d1, linesize,
-                                    font_ptr, cheight, fgcol, bgcol, dup9);
-                }
-                if (src == cursor_ptr &&
-                    !(s->cr[VGA_CRTC_CURSOR_START] & 0x20) &&
-                    s->cursor_visible_phase) {
-                    int line_start, line_last, h;
-                    /* draw the cursor */
-                    line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
-                    line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
-                    /* XXX: check that */
-                    if (line_last > cheight - 1)
-                        line_last = cheight - 1;
-                    if (line_last >= line_start && line_start < cheight) {
-                        h = line_last - line_start + 1;
-                        d = d1 + linesize * line_start;
-                        if (cw != 9) {
-                            vga_draw_glyph8(d, linesize,
-                                            cursor_glyph, h, fgcol, bgcol);
-                        } else {
-                            vga_draw_glyph9(d, linesize,
-                                            cursor_glyph, h, fgcol, bgcol, 1);
-                        }
-                    }
-                }
-            }
-            d1 += x_incr;
-            src += 4;
-            ch_attr_ptr++;
-        }
-        if (cx_max != -1) {
-            dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
-                           (cx_max - cx_min + 1) * cw, cheight);
-        }
-        dest += linesize * cheight;
-        line1 = line + cheight;
-        offset += line_offset;
-        if (line < s->line_compare && line1 >= s->line_compare) {
-            offset = 0;
-        }
-        line = line1;
-    }
-}
-
-enum {
-    VGA_DRAW_LINE2,
-    VGA_DRAW_LINE2D2,
-    VGA_DRAW_LINE4,
-    VGA_DRAW_LINE4D2,
-    VGA_DRAW_LINE8D2,
-    VGA_DRAW_LINE8,
-    VGA_DRAW_LINE15,
-    VGA_DRAW_LINE16,
-    VGA_DRAW_LINE24,
-    VGA_DRAW_LINE32,
-    VGA_DRAW_LINE_NB,
-};
-
-static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
-    vga_draw_line2_8,
-    vga_draw_line2_16,
-    vga_draw_line2_16,
-    vga_draw_line2_32,
-    vga_draw_line2_32,
-    vga_draw_line2_16,
-    vga_draw_line2_16,
-
-    vga_draw_line2d2_8,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_32,
-    vga_draw_line2d2_32,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_16,
-
-    vga_draw_line4_8,
-    vga_draw_line4_16,
-    vga_draw_line4_16,
-    vga_draw_line4_32,
-    vga_draw_line4_32,
-    vga_draw_line4_16,
-    vga_draw_line4_16,
-
-    vga_draw_line4d2_8,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_32,
-    vga_draw_line4d2_32,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_16,
-
-    vga_draw_line8d2_8,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_32,
-    vga_draw_line8d2_32,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_16,
-
-    vga_draw_line8_8,
-    vga_draw_line8_16,
-    vga_draw_line8_16,
-    vga_draw_line8_32,
-    vga_draw_line8_32,
-    vga_draw_line8_16,
-    vga_draw_line8_16,
-
-    vga_draw_line15_8,
-    vga_draw_line15_15,
-    vga_draw_line15_16,
-    vga_draw_line15_32,
-    vga_draw_line15_32bgr,
-    vga_draw_line15_15bgr,
-    vga_draw_line15_16bgr,
-
-    vga_draw_line16_8,
-    vga_draw_line16_15,
-    vga_draw_line16_16,
-    vga_draw_line16_32,
-    vga_draw_line16_32bgr,
-    vga_draw_line16_15bgr,
-    vga_draw_line16_16bgr,
-
-    vga_draw_line24_8,
-    vga_draw_line24_15,
-    vga_draw_line24_16,
-    vga_draw_line24_32,
-    vga_draw_line24_32bgr,
-    vga_draw_line24_15bgr,
-    vga_draw_line24_16bgr,
-
-    vga_draw_line32_8,
-    vga_draw_line32_15,
-    vga_draw_line32_16,
-    vga_draw_line32_32,
-    vga_draw_line32_32bgr,
-    vga_draw_line32_15bgr,
-    vga_draw_line32_16bgr,
-};
-
-static int vga_get_bpp(VGACommonState *s)
-{
-    int ret;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
-    } else {
-        ret = 0;
-    }
-    return ret;
-}
-
-static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
-{
-    int width, height;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
-        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
-    } else {
-        width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
-        height = s->cr[VGA_CRTC_V_DISP_END] |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
-        height = (height + 1);
-    }
-    *pwidth = width;
-    *pheight = height;
-}
-
-void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
-{
-    int y;
-    if (y1 >= VGA_MAX_HEIGHT)
-        return;
-    if (y2 >= VGA_MAX_HEIGHT)
-        y2 = VGA_MAX_HEIGHT;
-    for(y = y1; y < y2; y++) {
-        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
-    }
-}
-
-void vga_sync_dirty_bitmap(VGACommonState *s)
-{
-    memory_region_sync_dirty_bitmap(&s->vram);
-}
-
-void vga_dirty_log_start(VGACommonState *s)
-{
-    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
-}
-
-void vga_dirty_log_stop(VGACommonState *s)
-{
-    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
-}
-
-/*
- * graphic modes
- */
-static void vga_draw_graphic(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y1, y, update, linesize, y_start, double_scan, mask, depth;
-    int width, height, shift_control, line_offset, bwidth, bits;
-    ram_addr_t page0, page1, page_min, page_max;
-    int disp_width, multi_scan, multi_run;
-    uint8_t *d;
-    uint32_t v, addr1, addr;
-    vga_draw_line_func *vga_draw_line;
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-    static const bool byteswap = false;
-#else
-    static const bool byteswap = true;
-#endif
-
-    full_update |= update_basic_params(s);
-
-    if (!full_update)
-        vga_sync_dirty_bitmap(s);
-
-    s->get_resolution(s, &width, &height);
-    disp_width = width;
-
-    shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
-    double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
-    if (shift_control != 1) {
-        multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
-            - 1;
-    } else {
-        /* in CGA modes, multi_scan is ignored */
-        /* XXX: is it correct ? */
-        multi_scan = double_scan;
-    }
-    multi_run = multi_scan;
-    if (shift_control != s->shift_control ||
-        double_scan != s->double_scan) {
-        full_update = 1;
-        s->shift_control = shift_control;
-        s->double_scan = double_scan;
-    }
-
-    if (shift_control == 0) {
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            disp_width <<= 1;
-        }
-    } else if (shift_control == 1) {
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            disp_width <<= 1;
-        }
-    }
-
-    depth = s->get_bpp(s);
-    if (s->line_offset != s->last_line_offset ||
-        disp_width != s->last_width ||
-        height != s->last_height ||
-        s->last_depth != depth) {
-        if (depth == 32 || (depth == 16 && !byteswap)) {
-            surface = qemu_create_displaysurface_from(disp_width,
-                    height, depth, s->line_offset,
-                    s->vram_ptr + (s->start_addr * 4), byteswap);
-            dpy_gfx_replace_surface(s->con, surface);
-        } else {
-            qemu_console_resize(s->con, disp_width, height);
-            surface = qemu_console_surface(s->con);
-        }
-        s->last_scr_width = disp_width;
-        s->last_scr_height = height;
-        s->last_width = disp_width;
-        s->last_height = height;
-        s->last_line_offset = s->line_offset;
-        s->last_depth = depth;
-        full_update = 1;
-    } else if (is_buffer_shared(surface) &&
-               (full_update || surface_data(surface) != s->vram_ptr
-                + (s->start_addr * 4))) {
-        DisplaySurface *surface;
-        surface = qemu_create_displaysurface_from(disp_width,
-                height, depth, s->line_offset,
-                s->vram_ptr + (s->start_addr * 4), byteswap);
-        dpy_gfx_replace_surface(s->con, surface);
-    }
-
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-
-    if (shift_control == 0) {
-        full_update |= update_palette16(s);
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            v = VGA_DRAW_LINE4D2;
-        } else {
-            v = VGA_DRAW_LINE4;
-        }
-        bits = 4;
-    } else if (shift_control == 1) {
-        full_update |= update_palette16(s);
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            v = VGA_DRAW_LINE2D2;
-        } else {
-            v = VGA_DRAW_LINE2;
-        }
-        bits = 4;
-    } else {
-        switch(s->get_bpp(s)) {
-        default:
-        case 0:
-            full_update |= update_palette256(s);
-            v = VGA_DRAW_LINE8D2;
-            bits = 4;
-            break;
-        case 8:
-            full_update |= update_palette256(s);
-            v = VGA_DRAW_LINE8;
-            bits = 8;
-            break;
-        case 15:
-            v = VGA_DRAW_LINE15;
-            bits = 16;
-            break;
-        case 16:
-            v = VGA_DRAW_LINE16;
-            bits = 16;
-            break;
-        case 24:
-            v = VGA_DRAW_LINE24;
-            bits = 24;
-            break;
-        case 32:
-            v = VGA_DRAW_LINE32;
-            bits = 32;
-            break;
-        }
-    }
-    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS +
-                                        get_depth_index(surface)];
-
-    if (!is_buffer_shared(surface) && s->cursor_invalidate) {
-        s->cursor_invalidate(s);
-    }
-
-    line_offset = s->line_offset;
-#if 0
-    printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
-           width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
-           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
-#endif
-    addr1 = (s->start_addr * 4);
-    bwidth = (width * bits + 7) / 8;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    linesize = surface_stride(surface);
-    y1 = 0;
-    for(y = 0; y < height; y++) {
-        addr = addr1;
-        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
-            int shift;
-            /* CGA compatibility handling */
-            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
-            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
-        }
-        if (!(s->cr[VGA_CRTC_MODE] & 2)) {
-            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
-        }
-        update = full_update;
-        page0 = addr;
-        page1 = addr + bwidth - 1;
-        update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
-                                          DIRTY_MEMORY_VGA);
-        /* explicit invalidation for the hardware cursor */
-        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
-        if (update) {
-            if (y_start < 0)
-                y_start = y;
-            if (page0 < page_min)
-                page_min = page0;
-            if (page1 > page_max)
-                page_max = page1;
-            if (!(is_buffer_shared(surface))) {
-                vga_draw_line(s, d, s->vram_ptr + addr, width);
-                if (s->cursor_draw_line)
-                    s->cursor_draw_line(s, d, y);
-            }
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start,
-                               disp_width, y - y_start);
-                y_start = -1;
-            }
-        }
-        if (!multi_run) {
-            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
-            if ((y1 & mask) == mask)
-                addr1 += line_offset;
-            y1++;
-            multi_run = multi_scan;
-        } else {
-            multi_run--;
-        }
-        /* line compare acts on the displayed lines */
-        if (y == s->line_compare)
-            addr1 = 0;
-        d += linesize;
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(s->con, 0, y_start,
-                       disp_width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        memory_region_reset_dirty(&s->vram,
-                                  page_min,
-                                  page_max - page_min,
-                                  DIRTY_MEMORY_VGA);
-    }
-    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
-}
-
-static void vga_draw_blank(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w, val;
-    uint8_t *d;
-
-    if (!full_update)
-        return;
-    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
-        return;
-
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-    if (surface_bits_per_pixel(surface) == 8) {
-        val = s->rgb_to_pixel(0, 0, 0);
-    } else {
-        val = 0;
-    }
-    w = s->last_scr_width * surface_bytes_per_pixel(surface);
-    d = surface_data(surface);
-    for(i = 0; i < s->last_scr_height; i++) {
-        memset(d, val, w);
-        d += surface_stride(surface);
-    }
-    dpy_gfx_update(s->con, 0, 0,
-                   s->last_scr_width, s->last_scr_height);
-}
-
-#define GMODE_TEXT     0
-#define GMODE_GRAPH    1
-#define GMODE_BLANK 2
-
-static void vga_update_display(void *opaque)
-{
-    VGACommonState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int full_update, graphic_mode;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (surface_bits_per_pixel(surface) == 0) {
-        /* nothing to do */
-    } else {
-        full_update = 0;
-        if (!(s->ar_index & 0x20)) {
-            graphic_mode = GMODE_BLANK;
-        } else {
-            graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
-        }
-        if (graphic_mode != s->graphic_mode) {
-            s->graphic_mode = graphic_mode;
-            s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
-            full_update = 1;
-        }
-        switch(graphic_mode) {
-        case GMODE_TEXT:
-            vga_draw_text(s, full_update);
-            break;
-        case GMODE_GRAPH:
-            vga_draw_graphic(s, full_update);
-            break;
-        case GMODE_BLANK:
-        default:
-            vga_draw_blank(s, full_update);
-            break;
-        }
-    }
-}
-
-/* force a full display refresh */
-static void vga_invalidate_display(void *opaque)
-{
-    VGACommonState *s = opaque;
-
-    s->last_width = -1;
-    s->last_height = -1;
-}
-
-void vga_common_reset(VGACommonState *s)
-{
-    s->sr_index = 0;
-    memset(s->sr, '\0', sizeof(s->sr));
-    s->gr_index = 0;
-    memset(s->gr, '\0', sizeof(s->gr));
-    s->ar_index = 0;
-    memset(s->ar, '\0', sizeof(s->ar));
-    s->ar_flip_flop = 0;
-    s->cr_index = 0;
-    memset(s->cr, '\0', sizeof(s->cr));
-    s->msr = 0;
-    s->fcr = 0;
-    s->st00 = 0;
-    s->st01 = 0;
-    s->dac_state = 0;
-    s->dac_sub_index = 0;
-    s->dac_read_index = 0;
-    s->dac_write_index = 0;
-    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
-    s->dac_8bit = 0;
-    memset(s->palette, '\0', sizeof(s->palette));
-    s->bank_offset = 0;
-    s->vbe_index = 0;
-    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
-    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
-    s->vbe_start_addr = 0;
-    s->vbe_line_offset = 0;
-    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
-    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
-    s->graphic_mode = -1; /* force full update */
-    s->shift_control = 0;
-    s->double_scan = 0;
-    s->line_offset = 0;
-    s->line_compare = 0;
-    s->start_addr = 0;
-    s->plane_updated = 0;
-    s->last_cw = 0;
-    s->last_ch = 0;
-    s->last_width = 0;
-    s->last_height = 0;
-    s->last_scr_width = 0;
-    s->last_scr_height = 0;
-    s->cursor_start = 0;
-    s->cursor_end = 0;
-    s->cursor_offset = 0;
-    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
-    memset(s->last_palette, '\0', sizeof(s->last_palette));
-    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
-    switch (vga_retrace_method) {
-    case VGA_RETRACE_DUMB:
-        break;
-    case VGA_RETRACE_PRECISE:
-        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
-        break;
-    }
-    vga_update_memory_access(s);
-}
-
-static void vga_reset(void *opaque)
-{
-    VGACommonState *s =  opaque;
-    vga_common_reset(s);
-}
-
-#define TEXTMODE_X(x)  ((x) % width)
-#define TEXTMODE_Y(x)  ((x) / width)
-#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
-        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
-/* relay text rendering to the display driver
- * instead of doing a full vga_update_display() */
-static void vga_update_text(void *opaque, console_ch_t *chardata)
-{
-    VGACommonState *s =  opaque;
-    int graphic_mode, i, cursor_offset, cursor_visible;
-    int cw, cheight, width, height, size, c_min, c_max;
-    uint32_t *src;
-    console_ch_t *dst, val;
-    char msg_buffer[80];
-    int full_update = 0;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (!(s->ar_index & 0x20)) {
-        graphic_mode = GMODE_BLANK;
-    } else {
-        graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
-    }
-    if (graphic_mode != s->graphic_mode) {
-        s->graphic_mode = graphic_mode;
-        full_update = 1;
-    }
-    if (s->last_width == -1) {
-        s->last_width = 0;
-        full_update = 1;
-    }
-
-    switch (graphic_mode) {
-    case GMODE_TEXT:
-        /* TODO: update palette */
-        full_update |= update_basic_params(s);
-
-        /* total width & height */
-        cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
-        cw = 8;
-        if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
-            cw = 9;
-        }
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
-            cw = 16; /* NOTE: no 18 pixel wide */
-        }
-        width = (s->cr[VGA_CRTC_H_DISP] + 1);
-        if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
-            /* ugly hack for CGA 160x100x16 - explain me the logic */
-            height = 100;
-        } else {
-            height = s->cr[VGA_CRTC_V_DISP_END] |
-                ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
-                ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
-            height = (height + 1) / cheight;
-        }
-
-        size = (height * width);
-        if (size > CH_ATTR_SIZE) {
-            if (!full_update)
-                return;
-
-            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
-                     width, height);
-            break;
-        }
-
-        if (width != s->last_width || height != s->last_height ||
-            cw != s->last_cw || cheight != s->last_ch) {
-            s->last_scr_width = width * cw;
-            s->last_scr_height = height * cheight;
-            qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
-            dpy_text_resize(s->con, width, height);
-            s->last_depth = 0;
-            s->last_width = width;
-            s->last_height = height;
-            s->last_ch = cheight;
-            s->last_cw = cw;
-            full_update = 1;
-        }
-
-        if (full_update) {
-            s->full_update_gfx = 1;
-        }
-        if (s->full_update_text) {
-            s->full_update_text = 0;
-            full_update |= 1;
-        }
-
-        /* Update "hardware" cursor */
-        cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
-                         s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
-        if (cursor_offset != s->cursor_offset ||
-            s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
-            s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
-            cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
-            if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
-                dpy_text_cursor(s->con,
-                                TEXTMODE_X(cursor_offset),
-                                TEXTMODE_Y(cursor_offset));
-            else
-                dpy_text_cursor(s->con, -1, -1);
-            s->cursor_offset = cursor_offset;
-            s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
-            s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
-        }
-
-        src = (uint32_t *) s->vram_ptr + s->start_addr;
-        dst = chardata;
-
-        if (full_update) {
-            for (i = 0; i < size; src ++, dst ++, i ++)
-                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
-
-            dpy_text_update(s->con, 0, 0, width, height);
-        } else {
-            c_max = 0;
-
-            for (i = 0; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
-                if (*dst != val) {
-                    *dst = val;
-                    c_max = i;
-                    break;
-                }
-            }
-            c_min = i;
-            for (; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
-                if (*dst != val) {
-                    *dst = val;
-                    c_max = i;
-                }
-            }
-
-            if (c_min <= c_max) {
-                i = TEXTMODE_Y(c_min);
-                dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
-            }
-        }
-
-        return;
-    case GMODE_GRAPH:
-        if (!full_update)
-            return;
-
-        s->get_resolution(s, &width, &height);
-        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
-                 width, height);
-        break;
-    case GMODE_BLANK:
-    default:
-        if (!full_update)
-            return;
-
-        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
-        break;
-    }
-
-    /* Display a message */
-    s->last_width = 60;
-    s->last_height = height = 3;
-    dpy_text_cursor(s->con, -1, -1);
-    dpy_text_resize(s->con, s->last_width, height);
-
-    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
-        console_write_ch(dst ++, ' ');
-
-    size = strlen(msg_buffer);
-    width = (s->last_width - size) / 2;
-    dst = chardata + s->last_width + width;
-    for (i = 0; i < size; i ++)
-        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
-
-    dpy_text_update(s->con, 0, 0, s->last_width, height);
-}
-
-static uint64_t vga_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    VGACommonState *s = opaque;
-
-    return vga_mem_readb(s, addr);
-}
-
-static void vga_mem_write(void *opaque, hwaddr addr,
-                          uint64_t data, unsigned size)
-{
-    VGACommonState *s = opaque;
-
-    return vga_mem_writeb(s, addr, data);
-}
-
-const MemoryRegionOps vga_mem_ops = {
-    .read = vga_mem_read,
-    .write = vga_mem_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static int vga_common_post_load(void *opaque, int version_id)
-{
-    VGACommonState *s = opaque;
-
-    /* force refresh */
-    s->graphic_mode = -1;
-    return 0;
-}
-
-const VMStateDescription vmstate_vga_common = {
-    .name = "vga",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = vga_common_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(latch, VGACommonState),
-        VMSTATE_UINT8(sr_index, VGACommonState),
-        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
-        VMSTATE_UINT8(gr_index, VGACommonState),
-        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
-        VMSTATE_UINT8(ar_index, VGACommonState),
-        VMSTATE_BUFFER(ar, VGACommonState),
-        VMSTATE_INT32(ar_flip_flop, VGACommonState),
-        VMSTATE_UINT8(cr_index, VGACommonState),
-        VMSTATE_BUFFER(cr, VGACommonState),
-        VMSTATE_UINT8(msr, VGACommonState),
-        VMSTATE_UINT8(fcr, VGACommonState),
-        VMSTATE_UINT8(st00, VGACommonState),
-        VMSTATE_UINT8(st01, VGACommonState),
-
-        VMSTATE_UINT8(dac_state, VGACommonState),
-        VMSTATE_UINT8(dac_sub_index, VGACommonState),
-        VMSTATE_UINT8(dac_read_index, VGACommonState),
-        VMSTATE_UINT8(dac_write_index, VGACommonState),
-        VMSTATE_BUFFER(dac_cache, VGACommonState),
-        VMSTATE_BUFFER(palette, VGACommonState),
-
-        VMSTATE_INT32(bank_offset, VGACommonState),
-        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
-        VMSTATE_UINT16(vbe_index, VGACommonState),
-        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
-        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
-        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
-        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void vga_common_init(VGACommonState *s)
-{
-    int i, j, v, b;
-
-    for(i = 0;i < 256; i++) {
-        v = 0;
-        for(j = 0; j < 8; j++) {
-            v |= ((i >> j) & 1) << (j * 4);
-        }
-        expand4[i] = v;
-
-        v = 0;
-        for(j = 0; j < 4; j++) {
-            v |= ((i >> (2 * j)) & 3) << (j * 4);
-        }
-        expand2[i] = v;
-    }
-    for(i = 0; i < 16; i++) {
-        v = 0;
-        for(j = 0; j < 4; j++) {
-            b = ((i >> j) & 1);
-            v |= b << (2 * j);
-            v |= b << (2 * j + 1);
-        }
-        expand4to8[i] = v;
-    }
-
-    /* valid range: 1 MB -> 256 MB */
-    s->vram_size = 1024 * 1024;
-    while (s->vram_size < (s->vram_size_mb << 20) &&
-           s->vram_size < (256 << 20)) {
-        s->vram_size <<= 1;
-    }
-    s->vram_size_mb = s->vram_size >> 20;
-
-    s->is_vbe_vmstate = 1;
-    memory_region_init_ram(&s->vram, "vga.vram", s->vram_size);
-    vmstate_register_ram_global(&s->vram);
-    xen_register_framebuffer(&s->vram);
-    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
-    s->get_bpp = vga_get_bpp;
-    s->get_offsets = vga_get_offsets;
-    s->get_resolution = vga_get_resolution;
-    s->update = vga_update_display;
-    s->invalidate = vga_invalidate_display;
-    s->screen_dump = vga_screen_dump;
-    s->text_update = vga_update_text;
-    switch (vga_retrace_method) {
-    case VGA_RETRACE_DUMB:
-        s->retrace = vga_dumb_retrace;
-        s->update_retrace_info = vga_dumb_update_retrace_info;
-        break;
-
-    case VGA_RETRACE_PRECISE:
-        s->retrace = vga_precise_retrace;
-        s->update_retrace_info = vga_precise_update_retrace_info;
-        break;
-    }
-    vga_dirty_log_start(s);
-}
-
-static const MemoryRegionPortio vga_portio_list[] = {
-    { 0x04,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
-    { 0x0a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
-    { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
-    { 0x24,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
-    { 0x2a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
-    PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio vbe_portio_list[] = {
-    { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
-# ifdef TARGET_I386
-    { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-# endif
-    { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-    PORTIO_END_OF_LIST(),
-};
-
-/* Used by both ISA and PCI */
-MemoryRegion *vga_init_io(VGACommonState *s,
-                          const MemoryRegionPortio **vga_ports,
-                          const MemoryRegionPortio **vbe_ports)
-{
-    MemoryRegion *vga_mem;
-
-    *vga_ports = vga_portio_list;
-    *vbe_ports = vbe_portio_list;
-
-    vga_mem = g_malloc(sizeof(*vga_mem));
-    memory_region_init_io(vga_mem, &vga_mem_ops, s,
-                          "vga-lowmem", 0x20000);
-    memory_region_set_flush_coalesced(vga_mem);
-
-    return vga_mem;
-}
-
-void vga_init(VGACommonState *s, MemoryRegion *address_space,
-              MemoryRegion *address_space_io, bool init_vga_ports)
-{
-    MemoryRegion *vga_io_memory;
-    const MemoryRegionPortio *vga_ports, *vbe_ports;
-    PortioList *vga_port_list = g_new(PortioList, 1);
-    PortioList *vbe_port_list = g_new(PortioList, 1);
-
-    qemu_register_reset(vga_reset, s);
-
-    s->bank_offset = 0;
-
-    s->legacy_address_space = address_space;
-
-    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
-    memory_region_add_subregion_overlap(address_space,
-                                        isa_mem_base + 0x000a0000,
-                                        vga_io_memory,
-                                        1);
-    memory_region_set_coalescing(vga_io_memory);
-    if (init_vga_ports) {
-        portio_list_init(vga_port_list, vga_ports, s, "vga");
-        portio_list_add(vga_port_list, address_space_io, 0x3b0);
-    }
-    if (vbe_ports) {
-        portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
-        portio_list_add(vbe_port_list, address_space_io, 0x1ce);
-    }
-}
-
-void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
-{
-    /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
-     * so use an alias to avoid double-mapping the same region.
-     */
-    memory_region_init_alias(&s->vram_vbe, "vram.vbe",
-                             &s->vram, 0, memory_region_size(&s->vram));
-    /* XXX: use optimized standard vga accesses */
-    memory_region_add_subregion(system_memory,
-                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                &s->vram_vbe);
-    s->vbe_mapped = 1;
-}
-/********************************************************/
-/* vga screen dump */
-
-void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
-{
-    int width = pixman_image_get_width(ds->image);
-    int height = pixman_image_get_height(ds->image);
-    FILE *f;
-    int y;
-    int ret;
-    pixman_image_t *linebuf;
-
-    trace_ppm_save(filename, ds);
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
-    if (ret < 0) {
-        linebuf = NULL;
-        goto write_err;
-    }
-    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
-    for (y = 0; y < height; y++) {
-        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
-        clearerr(f);
-        ret = fwrite(pixman_image_get_data(linebuf), 1,
-                     pixman_image_get_stride(linebuf), f);
-        (void)ret;
-        if (ferror(f)) {
-            goto write_err;
-        }
-    }
-
-out:
-    qemu_pixman_image_unref(linebuf);
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-/* save the vga display in a PPM image even if no display is
-   available */
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp)
-{
-    VGACommonState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    if (cswitch) {
-        vga_invalidate_display(s);
-    }
-    vga_hw_update();
-    ppm_save(filename, surface, errp);
-}