qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

exynos4210_fimd.c (70561B)


      1 /*
      2  * Samsung exynos4210 Display Controller (FIMD)
      3  *
      4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
      5  * All rights reserved.
      6  * Based on LCD controller for Samsung S5PC1xx-based board emulation
      7  * by Kirill Batuzov <batuzovk@ispras.ru>
      8  *
      9  * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
     10  *
     11  * This program is free software; you can redistribute it and/or modify it
     12  * under the terms of the GNU General Public License as published by the
     13  * Free Software Foundation; either version 2 of the License, or (at your
     14  * option) any later version.
     15  *
     16  * This program is distributed in the hope that it will be useful,
     17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     19  * See the GNU General Public License for more details.
     20  *
     21  * You should have received a copy of the GNU General Public License along
     22  * with this program; if not, see <http://www.gnu.org/licenses/>.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "hw/hw.h"
     27 #include "hw/irq.h"
     28 #include "hw/sysbus.h"
     29 #include "migration/vmstate.h"
     30 #include "ui/console.h"
     31 #include "ui/pixel_ops.h"
     32 #include "qemu/bswap.h"
     33 #include "qemu/module.h"
     34 #include "qemu/log.h"
     35 #include "qom/object.h"
     36 
     37 /* Debug messages configuration */
     38 #define EXYNOS4210_FIMD_DEBUG              0
     39 #define EXYNOS4210_FIMD_MODE_TRACE         0
     40 
     41 #if EXYNOS4210_FIMD_DEBUG == 0
     42     #define DPRINT_L1(fmt, args...)       do { } while (0)
     43     #define DPRINT_L2(fmt, args...)       do { } while (0)
     44 #elif EXYNOS4210_FIMD_DEBUG == 1
     45     #define DPRINT_L1(fmt, args...) \
     46         do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
     47     #define DPRINT_L2(fmt, args...)       do { } while (0)
     48 #else
     49     #define DPRINT_L1(fmt, args...) \
     50         do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
     51     #define DPRINT_L2(fmt, args...) \
     52         do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
     53 #endif
     54 
     55 #if EXYNOS4210_FIMD_MODE_TRACE == 0
     56     #define DPRINT_TRACE(fmt, args...)        do { } while (0)
     57 #else
     58     #define DPRINT_TRACE(fmt, args...)        \
     59         do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
     60 #endif
     61 
     62 #define NUM_OF_WINDOWS              5
     63 #define FIMD_REGS_SIZE              0x4114
     64 
     65 /* Video main control registers */
     66 #define FIMD_VIDCON0                0x0000
     67 #define FIMD_VIDCON1                0x0004
     68 #define FIMD_VIDCON2                0x0008
     69 #define FIMD_VIDCON3                0x000C
     70 #define FIMD_VIDCON0_ENVID_F        (1 << 0)
     71 #define FIMD_VIDCON0_ENVID          (1 << 1)
     72 #define FIMD_VIDCON0_ENVID_MASK     ((1 << 0) | (1 << 1))
     73 #define FIMD_VIDCON1_ROMASK         0x07FFE000
     74 
     75 /* Video time control registers */
     76 #define FIMD_VIDTCON_START          0x10
     77 #define FIMD_VIDTCON_END            0x1C
     78 #define FIMD_VIDTCON2_SIZE_MASK     0x07FF
     79 #define FIMD_VIDTCON2_HOR_SHIFT     0
     80 #define FIMD_VIDTCON2_VER_SHIFT     11
     81 
     82 /* Window control registers */
     83 #define FIMD_WINCON_START           0x0020
     84 #define FIMD_WINCON_END             0x0030
     85 #define FIMD_WINCON_ROMASK          0x82200000
     86 #define FIMD_WINCON_ENWIN           (1 << 0)
     87 #define FIMD_WINCON_BLD_PIX         (1 << 6)
     88 #define FIMD_WINCON_ALPHA_MUL       (1 << 7)
     89 #define FIMD_WINCON_ALPHA_SEL       (1 << 1)
     90 #define FIMD_WINCON_SWAP            0x078000
     91 #define FIMD_WINCON_SWAP_SHIFT      15
     92 #define FIMD_WINCON_SWAP_WORD       0x1
     93 #define FIMD_WINCON_SWAP_HWORD      0x2
     94 #define FIMD_WINCON_SWAP_BYTE       0x4
     95 #define FIMD_WINCON_SWAP_BITS       0x8
     96 #define FIMD_WINCON_BUFSTAT_L       (1 << 21)
     97 #define FIMD_WINCON_BUFSTAT_H       (1 << 31)
     98 #define FIMD_WINCON_BUFSTATUS       ((1 << 21) | (1 << 31))
     99 #define FIMD_WINCON_BUF0_STAT       ((0 << 21) | (0 << 31))
    100 #define FIMD_WINCON_BUF1_STAT       ((1 << 21) | (0 << 31))
    101 #define FIMD_WINCON_BUF2_STAT       ((0 << 21) | (1U << 31))
    102 #define FIMD_WINCON_BUFSELECT       ((1 << 20) | (1 << 30))
    103 #define FIMD_WINCON_BUF0_SEL        ((0 << 20) | (0 << 30))
    104 #define FIMD_WINCON_BUF1_SEL        ((1 << 20) | (0 << 30))
    105 #define FIMD_WINCON_BUF2_SEL        ((0 << 20) | (1 << 30))
    106 #define FIMD_WINCON_BUFMODE         (1 << 14)
    107 #define IS_PALETTIZED_MODE(w)       (w->wincon & 0xC)
    108 #define PAL_MODE_WITH_ALPHA(x)       ((x) == 7)
    109 #define WIN_BPP_MODE(w)             ((w->wincon >> 2) & 0xF)
    110 #define WIN_BPP_MODE_WITH_ALPHA(w)     \
    111     (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
    112 
    113 /* Shadow control register */
    114 #define FIMD_SHADOWCON              0x0034
    115 #define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
    116 /* Channel mapping control register */
    117 #define FIMD_WINCHMAP               0x003C
    118 
    119 /* Window position control registers */
    120 #define FIMD_VIDOSD_START           0x0040
    121 #define FIMD_VIDOSD_END             0x0088
    122 #define FIMD_VIDOSD_COORD_MASK      0x07FF
    123 #define FIMD_VIDOSD_HOR_SHIFT       11
    124 #define FIMD_VIDOSD_VER_SHIFT       0
    125 #define FIMD_VIDOSD_ALPHA_AEN0      0xFFF000
    126 #define FIMD_VIDOSD_AEN0_SHIFT      12
    127 #define FIMD_VIDOSD_ALPHA_AEN1      0x000FFF
    128 
    129 /* Frame buffer address registers */
    130 #define FIMD_VIDWADD0_START         0x00A0
    131 #define FIMD_VIDWADD0_END           0x00C4
    132 #define FIMD_VIDWADD0_END           0x00C4
    133 #define FIMD_VIDWADD1_START         0x00D0
    134 #define FIMD_VIDWADD1_END           0x00F4
    135 #define FIMD_VIDWADD2_START         0x0100
    136 #define FIMD_VIDWADD2_END           0x0110
    137 #define FIMD_VIDWADD2_PAGEWIDTH     0x1FFF
    138 #define FIMD_VIDWADD2_OFFSIZE       0x1FFF
    139 #define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
    140 #define FIMD_VIDW0ADD0_B2           0x20A0
    141 #define FIMD_VIDW4ADD0_B2           0x20C0
    142 
    143 /* Video interrupt control registers */
    144 #define FIMD_VIDINTCON0             0x130
    145 #define FIMD_VIDINTCON1             0x134
    146 
    147 /* Window color key registers */
    148 #define FIMD_WKEYCON_START          0x140
    149 #define FIMD_WKEYCON_END            0x15C
    150 #define FIMD_WKEYCON0_COMPKEY       0x00FFFFFF
    151 #define FIMD_WKEYCON0_CTL_SHIFT     24
    152 #define FIMD_WKEYCON0_DIRCON        (1 << 24)
    153 #define FIMD_WKEYCON0_KEYEN         (1 << 25)
    154 #define FIMD_WKEYCON0_KEYBLEN       (1 << 26)
    155 /* Window color key alpha control register */
    156 #define FIMD_WKEYALPHA_START        0x160
    157 #define FIMD_WKEYALPHA_END          0x16C
    158 
    159 /* Dithering control register */
    160 #define FIMD_DITHMODE               0x170
    161 
    162 /* Window alpha control registers */
    163 #define FIMD_VIDALPHA_ALPHA_LOWER   0x000F0F0F
    164 #define FIMD_VIDALPHA_ALPHA_UPPER   0x00F0F0F0
    165 #define FIMD_VIDWALPHA_START        0x21C
    166 #define FIMD_VIDWALPHA_END          0x240
    167 
    168 /* Window color map registers */
    169 #define FIMD_WINMAP_START           0x180
    170 #define FIMD_WINMAP_END             0x190
    171 #define FIMD_WINMAP_EN              (1 << 24)
    172 #define FIMD_WINMAP_COLOR_MASK      0x00FFFFFF
    173 
    174 /* Window palette control registers */
    175 #define FIMD_WPALCON_HIGH           0x019C
    176 #define FIMD_WPALCON_LOW            0x01A0
    177 #define FIMD_WPALCON_UPDATEEN       (1 << 9)
    178 #define FIMD_WPAL_W0PAL_L           0x07
    179 #define FIMD_WPAL_W0PAL_L_SHT        0
    180 #define FIMD_WPAL_W1PAL_L           0x07
    181 #define FIMD_WPAL_W1PAL_L_SHT       3
    182 #define FIMD_WPAL_W2PAL_L           0x01
    183 #define FIMD_WPAL_W2PAL_L_SHT       6
    184 #define FIMD_WPAL_W2PAL_H           0x06
    185 #define FIMD_WPAL_W2PAL_H_SHT       8
    186 #define FIMD_WPAL_W3PAL_L           0x01
    187 #define FIMD_WPAL_W3PAL_L_SHT       7
    188 #define FIMD_WPAL_W3PAL_H           0x06
    189 #define FIMD_WPAL_W3PAL_H_SHT       12
    190 #define FIMD_WPAL_W4PAL_L           0x01
    191 #define FIMD_WPAL_W4PAL_L_SHT       8
    192 #define FIMD_WPAL_W4PAL_H           0x06
    193 #define FIMD_WPAL_W4PAL_H_SHT       16
    194 
    195 /* Trigger control registers */
    196 #define FIMD_TRIGCON                0x01A4
    197 #define FIMD_TRIGCON_ROMASK         0x00000004
    198 
    199 /* LCD I80 Interface Control */
    200 #define FIMD_I80IFCON_START         0x01B0
    201 #define FIMD_I80IFCON_END           0x01BC
    202 /* Color gain control register */
    203 #define FIMD_COLORGAINCON           0x01C0
    204 /* LCD i80 Interface Command Control */
    205 #define FIMD_LDI_CMDCON0            0x01D0
    206 #define FIMD_LDI_CMDCON1            0x01D4
    207 /* I80 System Interface Manual Command Control */
    208 #define FIMD_SIFCCON0               0x01E0
    209 #define FIMD_SIFCCON2               0x01E8
    210 
    211 /* Hue Control Registers */
    212 #define FIMD_HUECOEFCR_START        0x01EC
    213 #define FIMD_HUECOEFCR_END          0x01F4
    214 #define FIMD_HUECOEFCB_START        0x01FC
    215 #define FIMD_HUECOEFCB_END          0x0208
    216 #define FIMD_HUEOFFSET              0x020C
    217 
    218 /* Video interrupt control registers */
    219 #define FIMD_VIDINT_INTFIFOPEND     (1 << 0)
    220 #define FIMD_VIDINT_INTFRMPEND      (1 << 1)
    221 #define FIMD_VIDINT_INTI80PEND      (1 << 2)
    222 #define FIMD_VIDINT_INTEN           (1 << 0)
    223 #define FIMD_VIDINT_INTFIFOEN       (1 << 1)
    224 #define FIMD_VIDINT_INTFRMEN        (1 << 12)
    225 #define FIMD_VIDINT_I80IFDONE       (1 << 17)
    226 
    227 /* Window blend equation control registers */
    228 #define FIMD_BLENDEQ_START          0x0244
    229 #define FIMD_BLENDEQ_END            0x0250
    230 #define FIMD_BLENDCON               0x0260
    231 #define FIMD_ALPHA_8BIT             (1 << 0)
    232 #define FIMD_BLENDEQ_COEF_MASK      0xF
    233 
    234 /* Window RTQOS Control Registers */
    235 #define FIMD_WRTQOSCON_START        0x0264
    236 #define FIMD_WRTQOSCON_END          0x0274
    237 
    238 /* LCD I80 Interface Command */
    239 #define FIMD_I80IFCMD_START         0x0280
    240 #define FIMD_I80IFCMD_END           0x02AC
    241 
    242 /* Shadow windows control registers */
    243 #define FIMD_SHD_ADD0_START         0x40A0
    244 #define FIMD_SHD_ADD0_END           0x40C0
    245 #define FIMD_SHD_ADD1_START         0x40D0
    246 #define FIMD_SHD_ADD1_END           0x40F0
    247 #define FIMD_SHD_ADD2_START         0x4100
    248 #define FIMD_SHD_ADD2_END           0x4110
    249 
    250 /* Palette memory */
    251 #define FIMD_PAL_MEM_START          0x2400
    252 #define FIMD_PAL_MEM_END            0x37FC
    253 /* Palette memory aliases for windows 0 and 1 */
    254 #define FIMD_PALMEM_AL_START        0x0400
    255 #define FIMD_PALMEM_AL_END          0x0BFC
    256 
    257 typedef struct {
    258     uint8_t r, g, b;
    259     /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
    260     uint32_t a;
    261 } rgba;
    262 #define RGBA_SIZE  7
    263 
    264 typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
    265 typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
    266 
    267 struct Exynos4210fimdWindow {
    268     uint32_t wincon;        /* Window control register */
    269     uint32_t buf_start[3];  /* Start address for video frame buffer */
    270     uint32_t buf_end[3];    /* End address for video frame buffer */
    271     uint32_t keycon[2];     /* Window color key registers */
    272     uint32_t keyalpha;      /* Color key alpha control register */
    273     uint32_t winmap;        /* Window color map register */
    274     uint32_t blendeq;       /* Window blending equation control register */
    275     uint32_t rtqoscon;      /* Window RTQOS Control Registers */
    276     uint32_t palette[256];  /* Palette RAM */
    277     uint32_t shadow_buf_start;      /* Start address of shadow frame buffer */
    278     uint32_t shadow_buf_end;        /* End address of shadow frame buffer */
    279     uint32_t shadow_buf_size;       /* Virtual shadow screen width */
    280 
    281     pixel_to_rgb_func *pixel_to_rgb;
    282     void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
    283             bool blend);
    284     uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
    285     uint16_t lefttop_x, lefttop_y;   /* VIDOSD0 register */
    286     uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
    287     uint32_t osdsize;                /* VIDOSD2&3 register */
    288     uint32_t alpha_val[2];           /* VIDOSD2&3, VIDWALPHA registers */
    289     uint16_t virtpage_width;         /* VIDWADD2 register */
    290     uint16_t virtpage_offsize;       /* VIDWADD2 register */
    291     MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
    292     uint8_t *host_fb_addr;           /* Host pointer to window's framebuffer */
    293     hwaddr fb_len;       /* Framebuffer length */
    294 };
    295 
    296 #define TYPE_EXYNOS4210_FIMD "exynos4210.fimd"
    297 OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210fimdState, EXYNOS4210_FIMD)
    298 
    299 struct Exynos4210fimdState {
    300     SysBusDevice parent_obj;
    301 
    302     MemoryRegion iomem;
    303     QemuConsole *console;
    304     qemu_irq irq[3];
    305 
    306     uint32_t vidcon[4];     /* Video main control registers 0-3 */
    307     uint32_t vidtcon[4];    /* Video time control registers 0-3 */
    308     uint32_t shadowcon;     /* Window shadow control register */
    309     uint32_t winchmap;      /* Channel mapping control register */
    310     uint32_t vidintcon[2];  /* Video interrupt control registers */
    311     uint32_t dithmode;      /* Dithering control register */
    312     uint32_t wpalcon[2];    /* Window palette control registers */
    313     uint32_t trigcon;       /* Trigger control register */
    314     uint32_t i80ifcon[4];   /* I80 interface control registers */
    315     uint32_t colorgaincon;  /* Color gain control register */
    316     uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
    317     uint32_t sifccon[3];    /* I80 System Interface Manual Command Control */
    318     uint32_t huecoef_cr[4]; /* Hue control registers */
    319     uint32_t huecoef_cb[4]; /* Hue control registers */
    320     uint32_t hueoffset;     /* Hue offset control register */
    321     uint32_t blendcon;      /* Blending control register */
    322     uint32_t i80ifcmd[12];  /* LCD I80 Interface Command */
    323 
    324     Exynos4210fimdWindow window[5];    /* Window-specific registers */
    325     uint8_t *ifb;           /* Internal frame buffer */
    326     bool invalidate;        /* Image needs to be redrawn */
    327     bool enabled;           /* Display controller is enabled */
    328 };
    329 
    330 /* Perform byte/halfword/word swap of data according to WINCON */
    331 static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
    332 {
    333     int i;
    334     uint64_t res;
    335     uint64_t x = *data;
    336 
    337     if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
    338         res = 0;
    339         for (i = 0; i < 64; i++) {
    340             if (x & (1ULL << (63 - i))) {
    341                 res |= (1ULL << i);
    342             }
    343         }
    344         x = res;
    345     }
    346 
    347     if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
    348         x = bswap64(x);
    349     }
    350 
    351     if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
    352         x = ((x & 0x000000000000FFFFULL) << 48) |
    353             ((x & 0x00000000FFFF0000ULL) << 16) |
    354             ((x & 0x0000FFFF00000000ULL) >> 16) |
    355             ((x & 0xFFFF000000000000ULL) >> 48);
    356     }
    357 
    358     if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
    359         x = ((x & 0x00000000FFFFFFFFULL) << 32) |
    360             ((x & 0xFFFFFFFF00000000ULL) >> 32);
    361     }
    362 
    363     *data = x;
    364 }
    365 
    366 /* Conversion routines of Pixel data from frame buffer area to internal RGBA
    367  * pixel representation.
    368  * Every color component internally represented as 8-bit value. If original
    369  * data has less than 8 bit for component, data is extended to 8 bit. For
    370  * example, if blue component has only two possible values 0 and 1 it will be
    371  * extended to 0 and 0xFF */
    372 
    373 /* One bit for alpha representation */
    374 #define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
    375 static void N(uint32_t pixel, rgba *p) \
    376 { \
    377     p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
    378            ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
    379     pixel >>= (B); \
    380     p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
    381            ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
    382     pixel >>= (G); \
    383     p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
    384            ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
    385     pixel >>= (R); \
    386     p->a = (pixel & 0x1); \
    387 }
    388 
    389 DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
    390 DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
    391 DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
    392 DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
    393 DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
    394 DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
    395 
    396 /* Alpha component is always zero */
    397 #define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
    398 static void N(uint32_t pixel, rgba *p) \
    399 { \
    400     p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
    401            ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
    402     pixel >>= (B); \
    403     p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
    404            ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
    405     pixel >>= (G); \
    406     p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
    407            ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
    408     p->a = 0x0; \
    409 }
    410 
    411 DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb,  5, 6, 5)
    412 DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb,  5, 5, 5)
    413 DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb,  6, 6, 6)
    414 DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb,  8, 8, 8)
    415 
    416 /* Alpha component has some meaningful value */
    417 #define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
    418 static void N(uint32_t pixel, rgba *p) \
    419 { \
    420     p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
    421            ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
    422     pixel >>= (B); \
    423     p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
    424            ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
    425     pixel >>= (G); \
    426     p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
    427            ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
    428     pixel >>= (R); \
    429     p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
    430            ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
    431     p->a = p->a | (p->a << 8) | (p->a << 16); \
    432 }
    433 
    434 DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
    435 DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
    436 
    437 /* Lookup table to extent 2-bit color component to 8 bit */
    438 static const uint8_t pixel_lutable_2b[4] = {
    439      0x0, 0x55, 0xAA, 0xFF
    440 };
    441 /* Lookup table to extent 3-bit color component to 8 bit */
    442 static const uint8_t pixel_lutable_3b[8] = {
    443      0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
    444 };
    445 /* Special case for a232 bpp mode */
    446 static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
    447 {
    448     p->b = pixel_lutable_2b[(pixel & 0x3)];
    449     pixel >>= 2;
    450     p->g = pixel_lutable_3b[(pixel & 0x7)];
    451     pixel >>= 3;
    452     p->r = pixel_lutable_2b[(pixel & 0x3)];
    453     pixel >>= 2;
    454     p->a = (pixel & 0x1);
    455 }
    456 
    457 /* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
    458  * for all three color components */
    459 static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
    460 {
    461     uint8_t comm = (pixel >> 15) & 1;
    462     p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
    463     pixel >>= 5;
    464     p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
    465     pixel >>= 5;
    466     p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
    467     p->a = 0x0;
    468 }
    469 
    470 /* Put/get pixel to/from internal LCD Controller framebuffer */
    471 
    472 static int put_pixel_ifb(const rgba p, uint8_t *d)
    473 {
    474     *(uint8_t *)d++ = p.r;
    475     *(uint8_t *)d++ = p.g;
    476     *(uint8_t *)d++ = p.b;
    477     *(uint32_t *)d = p.a;
    478     return RGBA_SIZE;
    479 }
    480 
    481 static int get_pixel_ifb(const uint8_t *s, rgba *p)
    482 {
    483     p->r = *(uint8_t *)s++;
    484     p->g = *(uint8_t *)s++;
    485     p->b = *(uint8_t *)s++;
    486     p->a = (*(uint32_t *)s) & 0x00FFFFFF;
    487     return RGBA_SIZE;
    488 }
    489 
    490 static pixel_to_rgb_func *palette_data_format[8] = {
    491     [0] = pixel_565_to_rgb,
    492     [1] = pixel_a555_to_rgb,
    493     [2] = pixel_666_to_rgb,
    494     [3] = pixel_a665_to_rgb,
    495     [4] = pixel_a666_to_rgb,
    496     [5] = pixel_888_to_rgb,
    497     [6] = pixel_a888_to_rgb,
    498     [7] = pixel_8888_to_rgb
    499 };
    500 
    501 /* Returns Index in palette data formats table for given window number WINDOW */
    502 static uint32_t
    503 exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
    504 {
    505     uint32_t ret;
    506 
    507     switch (window) {
    508     case 0:
    509         ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
    510         if (ret != 7) {
    511             ret = 6 - ret;
    512         }
    513         break;
    514     case 1:
    515         ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
    516         if (ret != 7) {
    517             ret = 6 - ret;
    518         }
    519         break;
    520     case 2:
    521         ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
    522             ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
    523         break;
    524     case 3:
    525         ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
    526             ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
    527         break;
    528     case 4:
    529         ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
    530             ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
    531         break;
    532     default:
    533         hw_error("exynos4210.fimd: incorrect window number %d\n", window);
    534         ret = 0;
    535         break;
    536     }
    537     return ret;
    538 }
    539 
    540 #define FIMD_1_MINUS_COLOR(x)    \
    541             ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
    542                                   (0xFF0000 - ((x) & 0xFF0000)))
    543 #define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
    544 #define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
    545 
    546 /* Multiply three lower bytes of two 32-bit words with each other.
    547  * Each byte with values 0-255 is considered as a number with possible values
    548  * in a range [0 - 1] */
    549 static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
    550 {
    551     uint32_t tmp;
    552     uint32_t ret;
    553 
    554     ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
    555     ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
    556             0xFF00 : tmp << 8;
    557     ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
    558             0xFF0000 : tmp << 16;
    559     return ret;
    560 }
    561 
    562 /* For each corresponding bytes of two 32-bit words: (a*b + c*d)
    563  * Byte values 0-255 are mapped to a range [0 .. 1] */
    564 static inline uint32_t
    565 fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
    566 {
    567     uint32_t tmp;
    568     uint32_t ret;
    569 
    570     ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
    571             > 0xFF) ? 0xFF : tmp;
    572     ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
    573             ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
    574     ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
    575             ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
    576                     0xFF0000 : tmp << 16;
    577     return ret;
    578 }
    579 
    580 /* These routines cover all possible sources of window's transparent factor
    581  * used in blending equation. Choice of routine is affected by WPALCON
    582  * registers, BLENDCON register and window's WINCON register */
    583 
    584 static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
    585 {
    586     return pix_a;
    587 }
    588 
    589 static uint32_t
    590 fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
    591 {
    592     return EXTEND_LOWER_HALFBYTE(pix_a);
    593 }
    594 
    595 static uint32_t
    596 fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
    597 {
    598     return EXTEND_UPPER_HALFBYTE(pix_a);
    599 }
    600 
    601 static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
    602 {
    603     return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
    604 }
    605 
    606 static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
    607 {
    608     return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
    609             EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
    610 }
    611 
    612 static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
    613 {
    614     return w->alpha_val[pix_a];
    615 }
    616 
    617 static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
    618 {
    619     return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
    620 }
    621 
    622 static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
    623 {
    624     return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
    625 }
    626 
    627 static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
    628 {
    629     return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
    630             FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
    631 }
    632 
    633 /* Updates currently active alpha value get function for specified window */
    634 static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
    635 {
    636     Exynos4210fimdWindow *w = &s->window[win];
    637     const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
    638 
    639     if (w->wincon & FIMD_WINCON_BLD_PIX) {
    640         if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
    641             /* In this case, alpha component contains meaningful value */
    642             if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
    643                 w->get_alpha = alpha_is_8bit ?
    644                         fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
    645             } else {
    646                 w->get_alpha = alpha_is_8bit ?
    647                         fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
    648             }
    649         } else {
    650             if (IS_PALETTIZED_MODE(w) &&
    651                   PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
    652                 /* Alpha component has 8-bit numeric value */
    653                 w->get_alpha = alpha_is_8bit ?
    654                         fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
    655             } else {
    656                 /* Alpha has only two possible values (AEN) */
    657                 w->get_alpha = alpha_is_8bit ?
    658                         fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
    659             }
    660         }
    661     } else {
    662         w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
    663                 fimd_get_alpha_sel_ext;
    664     }
    665 }
    666 
    667 /* Blends current window's (w) pixel (foreground pixel *ret) with background
    668  * window (w_blend) pixel p_bg according to formula:
    669  * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
    670  * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
    671  */
    672 static void
    673 exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
    674 {
    675     rgba p_fg = *ret;
    676     uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
    677             (p_bg.b & 0xFF);
    678     uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
    679             (p_fg.b & 0xFF);
    680     uint32_t alpha_fg = p_fg.a;
    681     int i;
    682     /* It is possible that blending equation parameters a and b do not
    683      * depend on window BLENEQ register. Account for this with first_coef */
    684     enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
    685     uint32_t first_coef = A_COEF;
    686     uint32_t blend_param[COEF_NUM];
    687 
    688     if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
    689         uint32_t colorkey = (w->keycon[1] &
    690               ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
    691 
    692         if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
    693             (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
    694             /* Foreground pixel is displayed */
    695             if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
    696                 alpha_fg = w->keyalpha;
    697                 blend_param[A_COEF] = alpha_fg;
    698                 blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
    699             } else {
    700                 alpha_fg = 0;
    701                 blend_param[A_COEF] = 0xFFFFFF;
    702                 blend_param[B_COEF] = 0x0;
    703             }
    704             first_coef = P_COEF;
    705         } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
    706             (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
    707             /* Background pixel is displayed */
    708             if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
    709                 alpha_fg = w->keyalpha;
    710                 blend_param[A_COEF] = alpha_fg;
    711                 blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
    712             } else {
    713                 alpha_fg = 0;
    714                 blend_param[A_COEF] = 0x0;
    715                 blend_param[B_COEF] = 0xFFFFFF;
    716             }
    717             first_coef = P_COEF;
    718         }
    719     }
    720 
    721     for (i = first_coef; i < COEF_NUM; i++) {
    722         switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
    723         case 0:
    724             blend_param[i] = 0;
    725             break;
    726         case 1:
    727             blend_param[i] = 0xFFFFFF;
    728             break;
    729         case 2:
    730             blend_param[i] = alpha_fg;
    731             break;
    732         case 3:
    733             blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
    734             break;
    735         case 4:
    736             blend_param[i] = p_bg.a;
    737             break;
    738         case 5:
    739             blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
    740             break;
    741         case 6:
    742             blend_param[i] = w->alpha_val[0];
    743             break;
    744         case 10:
    745             blend_param[i] = fg_color;
    746             break;
    747         case 11:
    748             blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
    749             break;
    750         case 12:
    751             blend_param[i] = bg_color;
    752             break;
    753         case 13:
    754             blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
    755             break;
    756         default:
    757             hw_error("exynos4210.fimd: blend equation coef illegal value\n");
    758             break;
    759         }
    760     }
    761 
    762     fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
    763             fg_color, blend_param[A_COEF]);
    764     ret->b = fg_color & 0xFF;
    765     fg_color >>= 8;
    766     ret->g = fg_color & 0xFF;
    767     fg_color >>= 8;
    768     ret->r = fg_color & 0xFF;
    769     ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
    770             p_bg.a, blend_param[Q_COEF]);
    771 }
    772 
    773 /* These routines read data from video frame buffer in system RAM, convert
    774  * this data to display controller internal representation, if necessary,
    775  * perform pixel blending with data, currently presented in internal buffer.
    776  * Result is stored in display controller internal frame buffer. */
    777 
    778 /* Draw line with index in palette table in RAM frame buffer data */
    779 #define DEF_DRAW_LINE_PALETTE(N) \
    780 static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
    781                uint8_t *dst, bool blend) \
    782 { \
    783     int width = w->rightbot_x - w->lefttop_x + 1; \
    784     uint8_t *ifb = dst; \
    785     uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
    786     uint64_t data; \
    787     rgba p, p_old; \
    788     int i; \
    789     do { \
    790         memcpy(&data, src, sizeof(data)); \
    791         src += 8; \
    792         fimd_swap_data(swap, &data); \
    793         for (i = (64 / (N) - 1); i >= 0; i--) { \
    794             w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
    795                                    ((1ULL << (N)) - 1)], &p); \
    796             p.a = w->get_alpha(w, p.a); \
    797             if (blend) { \
    798                 ifb +=  get_pixel_ifb(ifb, &p_old); \
    799                 exynos4210_fimd_blend_pixel(w, p_old, &p); \
    800             } \
    801             dst += put_pixel_ifb(p, dst); \
    802         } \
    803         width -= (64 / (N)); \
    804     } while (width > 0); \
    805 }
    806 
    807 /* Draw line with direct color value in RAM frame buffer data */
    808 #define DEF_DRAW_LINE_NOPALETTE(N) \
    809 static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
    810                     uint8_t *dst, bool blend) \
    811 { \
    812     int width = w->rightbot_x - w->lefttop_x + 1; \
    813     uint8_t *ifb = dst; \
    814     uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
    815     uint64_t data; \
    816     rgba p, p_old; \
    817     int i; \
    818     do { \
    819         memcpy(&data, src, sizeof(data)); \
    820         src += 8; \
    821         fimd_swap_data(swap, &data); \
    822         for (i = (64 / (N) - 1); i >= 0; i--) { \
    823             w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
    824             p.a = w->get_alpha(w, p.a); \
    825             if (blend) { \
    826                 ifb += get_pixel_ifb(ifb, &p_old); \
    827                 exynos4210_fimd_blend_pixel(w, p_old, &p); \
    828             } \
    829             dst += put_pixel_ifb(p, dst); \
    830         } \
    831         width -= (64 / (N)); \
    832     } while (width > 0); \
    833 }
    834 
    835 DEF_DRAW_LINE_PALETTE(1)
    836 DEF_DRAW_LINE_PALETTE(2)
    837 DEF_DRAW_LINE_PALETTE(4)
    838 DEF_DRAW_LINE_PALETTE(8)
    839 DEF_DRAW_LINE_NOPALETTE(8)  /* 8bpp mode has palette and non-palette versions */
    840 DEF_DRAW_LINE_NOPALETTE(16)
    841 DEF_DRAW_LINE_NOPALETTE(32)
    842 
    843 /* Special draw line routine for window color map case */
    844 static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
    845                        uint8_t *dst, bool blend)
    846 {
    847     rgba p, p_old;
    848     uint8_t *ifb = dst;
    849     int width = w->rightbot_x - w->lefttop_x + 1;
    850     uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
    851 
    852     do {
    853         pixel_888_to_rgb(map_color, &p);
    854         p.a = w->get_alpha(w, p.a);
    855         if (blend) {
    856             ifb += get_pixel_ifb(ifb, &p_old);
    857             exynos4210_fimd_blend_pixel(w, p_old, &p);
    858         }
    859         dst += put_pixel_ifb(p, dst);
    860     } while (--width);
    861 }
    862 
    863 /* Write RGB to QEMU's GraphicConsole framebuffer */
    864 
    865 static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
    866 {
    867     uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
    868     *(uint8_t *)d = pixel;
    869     return 1;
    870 }
    871 
    872 static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
    873 {
    874     uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
    875     *(uint16_t *)d = pixel;
    876     return 2;
    877 }
    878 
    879 static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
    880 {
    881     uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
    882     *(uint16_t *)d = pixel;
    883     return 2;
    884 }
    885 
    886 static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
    887 {
    888     uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
    889     *(uint8_t *)d++ = (pixel >>  0) & 0xFF;
    890     *(uint8_t *)d++ = (pixel >>  8) & 0xFF;
    891     *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
    892     return 3;
    893 }
    894 
    895 static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
    896 {
    897     uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
    898     *(uint32_t *)d = pixel;
    899     return 4;
    900 }
    901 
    902 /* Routine to copy pixel from internal buffer to QEMU buffer */
    903 static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
    904 static inline void fimd_update_putpix_qemu(int bpp)
    905 {
    906     switch (bpp) {
    907     case 8:
    908         put_pixel_toqemu = put_to_qemufb_pixel8;
    909         break;
    910     case 15:
    911         put_pixel_toqemu = put_to_qemufb_pixel15;
    912         break;
    913     case 16:
    914         put_pixel_toqemu = put_to_qemufb_pixel16;
    915         break;
    916     case 24:
    917         put_pixel_toqemu = put_to_qemufb_pixel24;
    918         break;
    919     case 32:
    920         put_pixel_toqemu = put_to_qemufb_pixel32;
    921         break;
    922     default:
    923         hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
    924         break;
    925     }
    926 }
    927 
    928 /* Routine to copy a line from internal frame buffer to QEMU display */
    929 static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
    930 {
    931     rgba p;
    932 
    933     do {
    934         src += get_pixel_ifb(src, &p);
    935         dst += put_pixel_toqemu(p, dst);
    936     } while (--width);
    937 }
    938 
    939 /* Parse BPPMODE_F = WINCON1[5:2] bits */
    940 static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
    941 {
    942     Exynos4210fimdWindow *w = &s->window[win];
    943 
    944     if (w->winmap & FIMD_WINMAP_EN) {
    945         w->draw_line = draw_line_mapcolor;
    946         return;
    947     }
    948 
    949     switch (WIN_BPP_MODE(w)) {
    950     case 0:
    951         w->draw_line = draw_line_palette_1;
    952         w->pixel_to_rgb =
    953                 palette_data_format[exynos4210_fimd_palette_format(s, win)];
    954         break;
    955     case 1:
    956         w->draw_line = draw_line_palette_2;
    957         w->pixel_to_rgb =
    958                 palette_data_format[exynos4210_fimd_palette_format(s, win)];
    959         break;
    960     case 2:
    961         w->draw_line = draw_line_palette_4;
    962         w->pixel_to_rgb =
    963                 palette_data_format[exynos4210_fimd_palette_format(s, win)];
    964         break;
    965     case 3:
    966         w->draw_line = draw_line_palette_8;
    967         w->pixel_to_rgb =
    968                 palette_data_format[exynos4210_fimd_palette_format(s, win)];
    969         break;
    970     case 4:
    971         w->draw_line = draw_line_8;
    972         w->pixel_to_rgb = pixel_a232_to_rgb;
    973         break;
    974     case 5:
    975         w->draw_line = draw_line_16;
    976         w->pixel_to_rgb = pixel_565_to_rgb;
    977         break;
    978     case 6:
    979         w->draw_line = draw_line_16;
    980         w->pixel_to_rgb = pixel_a555_to_rgb;
    981         break;
    982     case 7:
    983         w->draw_line = draw_line_16;
    984         w->pixel_to_rgb = pixel_1555_to_rgb;
    985         break;
    986     case 8:
    987         w->draw_line = draw_line_32;
    988         w->pixel_to_rgb = pixel_666_to_rgb;
    989         break;
    990     case 9:
    991         w->draw_line = draw_line_32;
    992         w->pixel_to_rgb = pixel_a665_to_rgb;
    993         break;
    994     case 10:
    995         w->draw_line = draw_line_32;
    996         w->pixel_to_rgb = pixel_a666_to_rgb;
    997         break;
    998     case 11:
    999         w->draw_line = draw_line_32;
   1000         w->pixel_to_rgb = pixel_888_to_rgb;
   1001         break;
   1002     case 12:
   1003         w->draw_line = draw_line_32;
   1004         w->pixel_to_rgb = pixel_a887_to_rgb;
   1005         break;
   1006     case 13:
   1007         w->draw_line = draw_line_32;
   1008         if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
   1009                 FIMD_WINCON_ALPHA_SEL)) {
   1010             w->pixel_to_rgb = pixel_8888_to_rgb;
   1011         } else {
   1012             w->pixel_to_rgb = pixel_a888_to_rgb;
   1013         }
   1014         break;
   1015     case 14:
   1016         w->draw_line = draw_line_16;
   1017         if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
   1018                 FIMD_WINCON_ALPHA_SEL)) {
   1019             w->pixel_to_rgb = pixel_4444_to_rgb;
   1020         } else {
   1021             w->pixel_to_rgb = pixel_a444_to_rgb;
   1022         }
   1023         break;
   1024     case 15:
   1025         w->draw_line = draw_line_16;
   1026         w->pixel_to_rgb = pixel_555_to_rgb;
   1027         break;
   1028     }
   1029 }
   1030 
   1031 #if EXYNOS4210_FIMD_MODE_TRACE > 0
   1032 static const char *exynos4210_fimd_get_bppmode(int mode_code)
   1033 {
   1034     switch (mode_code) {
   1035     case 0:
   1036         return "1 bpp";
   1037     case 1:
   1038         return "2 bpp";
   1039     case 2:
   1040         return "4 bpp";
   1041     case 3:
   1042         return "8 bpp (palettized)";
   1043     case 4:
   1044         return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
   1045     case 5:
   1046         return "16 bpp (non-palettized, R:5-G:6-B:5)";
   1047     case 6:
   1048         return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
   1049     case 7:
   1050         return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
   1051     case 8:
   1052         return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
   1053     case 9:
   1054         return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
   1055     case 10:
   1056         return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
   1057     case 11:
   1058         return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
   1059     case 12:
   1060         return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
   1061     case 13:
   1062         return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
   1063     case 14:
   1064         return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
   1065     case 15:
   1066         return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
   1067     default:
   1068         return "Non-existing bpp mode";
   1069     }
   1070 }
   1071 
   1072 static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
   1073                 int win_num, uint32_t val)
   1074 {
   1075     Exynos4210fimdWindow *w = &s->window[win_num];
   1076 
   1077     if (w->winmap & FIMD_WINMAP_EN) {
   1078         printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
   1079                 win_num, w->winmap & 0xFFFFFF);
   1080         return;
   1081     }
   1082 
   1083     if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
   1084         return;
   1085     }
   1086     printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
   1087         exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
   1088 }
   1089 #else
   1090 static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
   1091         int win_num, uint32_t val)
   1092 {
   1093 
   1094 }
   1095 #endif
   1096 
   1097 static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
   1098 {
   1099     switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
   1100     case FIMD_WINCON_BUF0_STAT:
   1101         return 0;
   1102     case FIMD_WINCON_BUF1_STAT:
   1103         return 1;
   1104     case FIMD_WINCON_BUF2_STAT:
   1105         return 2;
   1106     default:
   1107         qemu_log_mask(LOG_GUEST_ERROR, "FIMD: Non-existent buffer index\n");
   1108         return 0;
   1109     }
   1110 }
   1111 
   1112 static void exynos4210_fimd_invalidate(void *opaque)
   1113 {
   1114     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
   1115     s->invalidate = true;
   1116 }
   1117 
   1118 /* Updates specified window's MemorySection based on values of WINCON,
   1119  * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
   1120 static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
   1121 {
   1122     SysBusDevice *sbd = SYS_BUS_DEVICE(s);
   1123     Exynos4210fimdWindow *w = &s->window[win];
   1124     hwaddr fb_start_addr, fb_mapped_len;
   1125 
   1126     if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
   1127             FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
   1128         return;
   1129     }
   1130 
   1131     if (w->host_fb_addr) {
   1132         cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
   1133         w->host_fb_addr = NULL;
   1134         w->fb_len = 0;
   1135     }
   1136 
   1137     fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
   1138     /* Total number of bytes of virtual screen used by current window */
   1139     w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
   1140             (w->rightbot_y - w->lefttop_y + 1);
   1141 
   1142     /* TODO: add .exit and unref the region there.  Not needed yet since sysbus
   1143      * does not support hot-unplug.
   1144      */
   1145     if (w->mem_section.mr) {
   1146         memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA);
   1147         memory_region_unref(w->mem_section.mr);
   1148     }
   1149 
   1150     w->mem_section = memory_region_find(sysbus_address_space(sbd),
   1151                                         fb_start_addr, w->fb_len);
   1152     assert(w->mem_section.mr);
   1153     assert(w->mem_section.offset_within_address_space == fb_start_addr);
   1154     DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
   1155             win, fb_start_addr, w->fb_len);
   1156 
   1157     if (int128_get64(w->mem_section.size) != w->fb_len ||
   1158             !memory_region_is_ram(w->mem_section.mr)) {
   1159         qemu_log_mask(LOG_GUEST_ERROR,
   1160                       "FIMD: Failed to find window %u framebuffer region\n",
   1161                       win);
   1162         goto error_return;
   1163     }
   1164 
   1165     w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len,
   1166                                               false);
   1167     if (!w->host_fb_addr) {
   1168         qemu_log_mask(LOG_GUEST_ERROR,
   1169                       "FIMD: Failed to map window %u framebuffer\n", win);
   1170         goto error_return;
   1171     }
   1172 
   1173     if (fb_mapped_len != w->fb_len) {
   1174         qemu_log_mask(LOG_GUEST_ERROR,
   1175                       "FIMD: Window %u mapped framebuffer length is less than "
   1176                       "expected\n", win);
   1177         cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
   1178         goto error_return;
   1179     }
   1180     memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA);
   1181     exynos4210_fimd_invalidate(s);
   1182     return;
   1183 
   1184 error_return:
   1185     memory_region_unref(w->mem_section.mr);
   1186     w->mem_section.mr = NULL;
   1187     w->mem_section.size = int128_zero();
   1188     w->host_fb_addr = NULL;
   1189     w->fb_len = 0;
   1190 }
   1191 
   1192 static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
   1193 {
   1194     if (enabled && !s->enabled) {
   1195         unsigned w;
   1196         s->enabled = true;
   1197         for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1198             fimd_update_memory_section(s, w);
   1199         }
   1200     }
   1201     s->enabled = enabled;
   1202     DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
   1203 }
   1204 
   1205 static inline uint32_t unpack_upper_4(uint32_t x)
   1206 {
   1207     return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
   1208 }
   1209 
   1210 static inline uint32_t pack_upper_4(uint32_t x)
   1211 {
   1212     return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
   1213             ((x & 0xF0) >> 4)) & 0xFFF;
   1214 }
   1215 
   1216 static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
   1217 {
   1218     if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
   1219         qemu_irq_lower(s->irq[0]);
   1220         qemu_irq_lower(s->irq[1]);
   1221         qemu_irq_lower(s->irq[2]);
   1222         return;
   1223     }
   1224     if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
   1225             (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
   1226         qemu_irq_raise(s->irq[0]);
   1227     } else {
   1228         qemu_irq_lower(s->irq[0]);
   1229     }
   1230     if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
   1231             (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
   1232         qemu_irq_raise(s->irq[1]);
   1233     } else {
   1234         qemu_irq_lower(s->irq[1]);
   1235     }
   1236     if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
   1237             (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
   1238         qemu_irq_raise(s->irq[2]);
   1239     } else {
   1240         qemu_irq_lower(s->irq[2]);
   1241     }
   1242 }
   1243 
   1244 static void exynos4210_update_resolution(Exynos4210fimdState *s)
   1245 {
   1246     DisplaySurface *surface = qemu_console_surface(s->console);
   1247 
   1248     /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
   1249     uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
   1250             FIMD_VIDTCON2_SIZE_MASK) + 1;
   1251     uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
   1252             FIMD_VIDTCON2_SIZE_MASK) + 1;
   1253 
   1254     if (s->ifb == NULL || surface_width(surface) != width ||
   1255             surface_height(surface) != height) {
   1256         DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
   1257            surface_width(surface), surface_height(surface), width, height);
   1258         qemu_console_resize(s->console, width, height);
   1259         s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
   1260         memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
   1261         exynos4210_fimd_invalidate(s);
   1262     }
   1263 }
   1264 
   1265 static void exynos4210_fimd_update(void *opaque)
   1266 {
   1267     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
   1268     DisplaySurface *surface;
   1269     Exynos4210fimdWindow *w;
   1270     DirtyBitmapSnapshot *snap;
   1271     int i, line;
   1272     hwaddr fb_line_addr, inc_size;
   1273     int scrn_height;
   1274     int first_line = -1, last_line = -1, scrn_width;
   1275     bool blend = false;
   1276     uint8_t *host_fb_addr;
   1277     bool is_dirty = false;
   1278     int global_width;
   1279 
   1280     if (!s || !s->console || !s->enabled ||
   1281         surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) {
   1282         return;
   1283     }
   1284 
   1285     global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
   1286     exynos4210_update_resolution(s);
   1287     surface = qemu_console_surface(s->console);
   1288 
   1289     for (i = 0; i < NUM_OF_WINDOWS; i++) {
   1290         w = &s->window[i];
   1291         if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
   1292             scrn_height = w->rightbot_y - w->lefttop_y + 1;
   1293             scrn_width = w->virtpage_width;
   1294             /* Total width of virtual screen page in bytes */
   1295             inc_size = scrn_width + w->virtpage_offsize;
   1296             host_fb_addr = w->host_fb_addr;
   1297             fb_line_addr = w->mem_section.offset_within_region;
   1298             snap = memory_region_snapshot_and_clear_dirty(w->mem_section.mr,
   1299                     fb_line_addr, inc_size * scrn_height, DIRTY_MEMORY_VGA);
   1300 
   1301             for (line = 0; line < scrn_height; line++) {
   1302                 is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr,
   1303                             snap, fb_line_addr, scrn_width);
   1304 
   1305                 if (s->invalidate || is_dirty) {
   1306                     if (first_line == -1) {
   1307                         first_line = line;
   1308                     }
   1309                     last_line = line;
   1310                     w->draw_line(w, host_fb_addr, s->ifb +
   1311                         w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
   1312                         global_width * RGBA_SIZE, blend);
   1313                 }
   1314                 host_fb_addr += inc_size;
   1315                 fb_line_addr += inc_size;
   1316             }
   1317             g_free(snap);
   1318             blend = true;
   1319         }
   1320     }
   1321 
   1322     /* Copy resulting image to QEMU_CONSOLE. */
   1323     if (first_line >= 0) {
   1324         uint8_t *d;
   1325         int bpp;
   1326 
   1327         bpp = surface_bits_per_pixel(surface);
   1328         fimd_update_putpix_qemu(bpp);
   1329         bpp = (bpp + 1) >> 3;
   1330         d = surface_data(surface);
   1331         for (line = first_line; line <= last_line; line++) {
   1332             fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
   1333                     RGBA_SIZE, d + global_width * line * bpp);
   1334         }
   1335         dpy_gfx_update_full(s->console);
   1336     }
   1337     s->invalidate = false;
   1338     s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
   1339     if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
   1340         exynos4210_fimd_enable(s, false);
   1341     }
   1342     exynos4210_fimd_update_irq(s);
   1343 }
   1344 
   1345 static void exynos4210_fimd_reset(DeviceState *d)
   1346 {
   1347     Exynos4210fimdState *s = EXYNOS4210_FIMD(d);
   1348     unsigned w;
   1349 
   1350     DPRINT_TRACE("Display controller reset\n");
   1351     /* Set all display controller registers to 0 */
   1352     memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
   1353     for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1354         memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
   1355         s->window[w].blendeq = 0xC2;
   1356         exynos4210_fimd_update_win_bppmode(s, w);
   1357         exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
   1358         fimd_update_get_alpha(s, w);
   1359     }
   1360 
   1361     g_free(s->ifb);
   1362     s->ifb = NULL;
   1363 
   1364     exynos4210_fimd_invalidate(s);
   1365     exynos4210_fimd_enable(s, false);
   1366     /* Some registers have non-zero initial values */
   1367     s->winchmap = 0x7D517D51;
   1368     s->colorgaincon = 0x10040100;
   1369     s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
   1370     s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
   1371     s->hueoffset = 0x01800080;
   1372 }
   1373 
   1374 static void exynos4210_fimd_write(void *opaque, hwaddr offset,
   1375                               uint64_t val, unsigned size)
   1376 {
   1377     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
   1378     unsigned w, i;
   1379     uint32_t old_value;
   1380 
   1381     DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
   1382             (long long unsigned int)val, (long long unsigned int)val);
   1383 
   1384     switch (offset) {
   1385     case FIMD_VIDCON0:
   1386         if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
   1387             exynos4210_fimd_enable(s, true);
   1388         } else {
   1389             if ((val & FIMD_VIDCON0_ENVID) == 0) {
   1390                 exynos4210_fimd_enable(s, false);
   1391             }
   1392         }
   1393         s->vidcon[0] = val;
   1394         break;
   1395     case FIMD_VIDCON1:
   1396         /* Leave read-only bits as is */
   1397         val = (val & (~FIMD_VIDCON1_ROMASK)) |
   1398                 (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
   1399         s->vidcon[1] = val;
   1400         break;
   1401     case FIMD_VIDCON2 ... FIMD_VIDCON3:
   1402         s->vidcon[(offset) >> 2] = val;
   1403         break;
   1404     case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
   1405         s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
   1406         break;
   1407     case FIMD_WINCON_START ... FIMD_WINCON_END:
   1408         w = (offset - FIMD_WINCON_START) >> 2;
   1409         /* Window's current buffer ID */
   1410         i = fimd_get_buffer_id(&s->window[w]);
   1411         old_value = s->window[w].wincon;
   1412         val = (val & ~FIMD_WINCON_ROMASK) |
   1413                 (s->window[w].wincon & FIMD_WINCON_ROMASK);
   1414         if (w == 0) {
   1415             /* Window 0 wincon ALPHA_MUL bit must always be 0 */
   1416             val &= ~FIMD_WINCON_ALPHA_MUL;
   1417         }
   1418         exynos4210_fimd_trace_bppmode(s, w, val);
   1419         switch (val & FIMD_WINCON_BUFSELECT) {
   1420         case FIMD_WINCON_BUF0_SEL:
   1421             val &= ~FIMD_WINCON_BUFSTATUS;
   1422             break;
   1423         case FIMD_WINCON_BUF1_SEL:
   1424             val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
   1425             break;
   1426         case FIMD_WINCON_BUF2_SEL:
   1427             if (val & FIMD_WINCON_BUFMODE) {
   1428                 val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
   1429             }
   1430             break;
   1431         default:
   1432             break;
   1433         }
   1434         s->window[w].wincon = val;
   1435         exynos4210_fimd_update_win_bppmode(s, w);
   1436         fimd_update_get_alpha(s, w);
   1437         if ((i != fimd_get_buffer_id(&s->window[w])) ||
   1438                 (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
   1439                         FIMD_WINCON_ENWIN))) {
   1440             fimd_update_memory_section(s, w);
   1441         }
   1442         break;
   1443     case FIMD_SHADOWCON:
   1444         old_value = s->shadowcon;
   1445         s->shadowcon = val;
   1446         for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1447             if (FIMD_WINDOW_PROTECTED(old_value, w) &&
   1448                     !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
   1449                 fimd_update_memory_section(s, w);
   1450             }
   1451         }
   1452         break;
   1453     case FIMD_WINCHMAP:
   1454         s->winchmap = val;
   1455         break;
   1456     case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
   1457         w = (offset - FIMD_VIDOSD_START) >> 4;
   1458         i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
   1459         switch (i) {
   1460         case 0:
   1461             old_value = s->window[w].lefttop_y;
   1462             s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
   1463                                       FIMD_VIDOSD_COORD_MASK;
   1464             s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
   1465                                       FIMD_VIDOSD_COORD_MASK;
   1466             if (s->window[w].lefttop_y != old_value) {
   1467                 fimd_update_memory_section(s, w);
   1468             }
   1469             break;
   1470         case 1:
   1471             old_value = s->window[w].rightbot_y;
   1472             s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
   1473                                        FIMD_VIDOSD_COORD_MASK;
   1474             s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
   1475                                        FIMD_VIDOSD_COORD_MASK;
   1476             if (s->window[w].rightbot_y != old_value) {
   1477                 fimd_update_memory_section(s, w);
   1478             }
   1479             break;
   1480         case 2:
   1481             if (w == 0) {
   1482                 s->window[w].osdsize = val;
   1483             } else {
   1484                 s->window[w].alpha_val[0] =
   1485                     unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
   1486                     FIMD_VIDOSD_AEN0_SHIFT) |
   1487                     (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
   1488                 s->window[w].alpha_val[1] =
   1489                     unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
   1490                     (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
   1491             }
   1492             break;
   1493         case 3:
   1494             if (w != 1 && w != 2) {
   1495                 qemu_log_mask(LOG_GUEST_ERROR,
   1496                               "FIMD: Bad write offset 0x%08"HWADDR_PRIx"\n",
   1497                               offset);
   1498                 return;
   1499             }
   1500             s->window[w].osdsize = val;
   1501             break;
   1502         }
   1503         break;
   1504     case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
   1505         w = (offset - FIMD_VIDWADD0_START) >> 3;
   1506         i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
   1507         if (i == fimd_get_buffer_id(&s->window[w]) &&
   1508                 s->window[w].buf_start[i] != val) {
   1509             s->window[w].buf_start[i] = val;
   1510             fimd_update_memory_section(s, w);
   1511             break;
   1512         }
   1513         s->window[w].buf_start[i] = val;
   1514         break;
   1515     case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
   1516         w = (offset - FIMD_VIDWADD1_START) >> 3;
   1517         i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
   1518         s->window[w].buf_end[i] = val;
   1519         break;
   1520     case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
   1521         w = (offset - FIMD_VIDWADD2_START) >> 2;
   1522         if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
   1523             (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
   1524                         s->window[w].virtpage_offsize)) {
   1525             s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
   1526             s->window[w].virtpage_offsize =
   1527                 (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
   1528             fimd_update_memory_section(s, w);
   1529         }
   1530         break;
   1531     case FIMD_VIDINTCON0:
   1532         s->vidintcon[0] = val;
   1533         break;
   1534     case FIMD_VIDINTCON1:
   1535         s->vidintcon[1] &= ~(val & 7);
   1536         exynos4210_fimd_update_irq(s);
   1537         break;
   1538     case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
   1539         w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
   1540         i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
   1541         s->window[w].keycon[i] = val;
   1542         break;
   1543     case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
   1544         w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
   1545         s->window[w].keyalpha = val;
   1546         break;
   1547     case FIMD_DITHMODE:
   1548         s->dithmode = val;
   1549         break;
   1550     case FIMD_WINMAP_START ... FIMD_WINMAP_END:
   1551         w = (offset - FIMD_WINMAP_START) >> 2;
   1552         old_value = s->window[w].winmap;
   1553         s->window[w].winmap = val;
   1554         if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
   1555             exynos4210_fimd_invalidate(s);
   1556             exynos4210_fimd_update_win_bppmode(s, w);
   1557             exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
   1558             exynos4210_fimd_update(s);
   1559         }
   1560         break;
   1561     case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
   1562         i = (offset - FIMD_WPALCON_HIGH) >> 2;
   1563         s->wpalcon[i] = val;
   1564         if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
   1565             for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1566                 exynos4210_fimd_update_win_bppmode(s, w);
   1567                 fimd_update_get_alpha(s, w);
   1568             }
   1569         }
   1570         break;
   1571     case FIMD_TRIGCON:
   1572         val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
   1573         s->trigcon = val;
   1574         break;
   1575     case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
   1576         s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
   1577         break;
   1578     case FIMD_COLORGAINCON:
   1579         s->colorgaincon = val;
   1580         break;
   1581     case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
   1582         s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
   1583         break;
   1584     case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
   1585         i = (offset - FIMD_SIFCCON0) >> 2;
   1586         if (i != 2) {
   1587             s->sifccon[i] = val;
   1588         }
   1589         break;
   1590     case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
   1591         i = (offset - FIMD_HUECOEFCR_START) >> 2;
   1592         s->huecoef_cr[i] = val;
   1593         break;
   1594     case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
   1595         i = (offset - FIMD_HUECOEFCB_START) >> 2;
   1596         s->huecoef_cb[i] = val;
   1597         break;
   1598     case FIMD_HUEOFFSET:
   1599         s->hueoffset = val;
   1600         break;
   1601     case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
   1602         w = ((offset - FIMD_VIDWALPHA_START) >> 3);
   1603         i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
   1604         if (w == 0) {
   1605             s->window[w].alpha_val[i] = val;
   1606         } else {
   1607             s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
   1608                 (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
   1609         }
   1610         break;
   1611     case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
   1612         s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
   1613         break;
   1614     case FIMD_BLENDCON:
   1615         old_value = s->blendcon;
   1616         s->blendcon = val;
   1617         if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
   1618             for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1619                 fimd_update_get_alpha(s, w);
   1620             }
   1621         }
   1622         break;
   1623     case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
   1624         s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
   1625         break;
   1626     case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
   1627         s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
   1628         break;
   1629     case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
   1630         if (offset & 0x0004) {
   1631             qemu_log_mask(LOG_GUEST_ERROR,
   1632                           "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
   1633                           offset);
   1634             break;
   1635         }
   1636         w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
   1637         if (fimd_get_buffer_id(&s->window[w]) == 2 &&
   1638                 s->window[w].buf_start[2] != val) {
   1639             s->window[w].buf_start[2] = val;
   1640             fimd_update_memory_section(s, w);
   1641             break;
   1642         }
   1643         s->window[w].buf_start[2] = val;
   1644         break;
   1645     case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
   1646         if (offset & 0x0004) {
   1647             qemu_log_mask(LOG_GUEST_ERROR,
   1648                           "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
   1649                           offset);
   1650             break;
   1651         }
   1652         s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
   1653         break;
   1654     case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
   1655         if (offset & 0x0004) {
   1656             qemu_log_mask(LOG_GUEST_ERROR,
   1657                           "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n",
   1658                           offset);
   1659             break;
   1660         }
   1661         s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
   1662         break;
   1663     case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
   1664         s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
   1665         break;
   1666     case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
   1667         w = (offset - FIMD_PAL_MEM_START) >> 10;
   1668         i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
   1669         s->window[w].palette[i] = val;
   1670         break;
   1671     case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
   1672         /* Palette memory aliases for windows 0 and 1 */
   1673         w = (offset - FIMD_PALMEM_AL_START) >> 10;
   1674         i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
   1675         s->window[w].palette[i] = val;
   1676         break;
   1677     default:
   1678         qemu_log_mask(LOG_GUEST_ERROR,
   1679                       "FIMD: bad write offset 0x%08"HWADDR_PRIx"\n", offset);
   1680         break;
   1681     }
   1682 }
   1683 
   1684 static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
   1685                                   unsigned size)
   1686 {
   1687     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
   1688     int w, i;
   1689     uint32_t ret = 0;
   1690 
   1691     DPRINT_L2("read offset 0x%08x\n", offset);
   1692 
   1693     switch (offset) {
   1694     case FIMD_VIDCON0 ... FIMD_VIDCON3:
   1695         return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
   1696     case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
   1697         return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
   1698     case FIMD_WINCON_START ... FIMD_WINCON_END:
   1699         return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
   1700     case FIMD_SHADOWCON:
   1701         return s->shadowcon;
   1702     case FIMD_WINCHMAP:
   1703         return s->winchmap;
   1704     case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
   1705         w = (offset - FIMD_VIDOSD_START) >> 4;
   1706         i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
   1707         switch (i) {
   1708         case 0:
   1709             ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
   1710             FIMD_VIDOSD_HOR_SHIFT) |
   1711             (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
   1712             break;
   1713         case 1:
   1714             ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
   1715                 FIMD_VIDOSD_HOR_SHIFT) |
   1716                 (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
   1717             break;
   1718         case 2:
   1719             if (w == 0) {
   1720                 ret = s->window[w].osdsize;
   1721             } else {
   1722                 ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
   1723                     FIMD_VIDOSD_AEN0_SHIFT) |
   1724                     pack_upper_4(s->window[w].alpha_val[1]);
   1725             }
   1726             break;
   1727         case 3:
   1728             if (w != 1 && w != 2) {
   1729                 qemu_log_mask(LOG_GUEST_ERROR,
   1730                               "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n",
   1731                               offset);
   1732                 return 0xBAADBAAD;
   1733             }
   1734             ret = s->window[w].osdsize;
   1735             break;
   1736         }
   1737         return ret;
   1738     case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
   1739         w = (offset - FIMD_VIDWADD0_START) >> 3;
   1740         i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
   1741         return s->window[w].buf_start[i];
   1742     case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
   1743         w = (offset - FIMD_VIDWADD1_START) >> 3;
   1744         i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
   1745         return s->window[w].buf_end[i];
   1746     case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
   1747         w = (offset - FIMD_VIDWADD2_START) >> 2;
   1748         return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
   1749             FIMD_VIDWADD2_OFFSIZE_SHIFT);
   1750     case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
   1751         return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
   1752     case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
   1753         w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
   1754         i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
   1755         return s->window[w].keycon[i];
   1756     case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
   1757         w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
   1758         return s->window[w].keyalpha;
   1759     case FIMD_DITHMODE:
   1760         return s->dithmode;
   1761     case FIMD_WINMAP_START ... FIMD_WINMAP_END:
   1762         return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
   1763     case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
   1764         return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
   1765     case FIMD_TRIGCON:
   1766         return s->trigcon;
   1767     case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
   1768         return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
   1769     case FIMD_COLORGAINCON:
   1770         return s->colorgaincon;
   1771     case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
   1772         return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
   1773     case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
   1774         i = (offset - FIMD_SIFCCON0) >> 2;
   1775         return s->sifccon[i];
   1776     case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
   1777         i = (offset - FIMD_HUECOEFCR_START) >> 2;
   1778         return s->huecoef_cr[i];
   1779     case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
   1780         i = (offset - FIMD_HUECOEFCB_START) >> 2;
   1781         return s->huecoef_cb[i];
   1782     case FIMD_HUEOFFSET:
   1783         return s->hueoffset;
   1784     case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
   1785         w = ((offset - FIMD_VIDWALPHA_START) >> 3);
   1786         i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
   1787         return s->window[w].alpha_val[i] &
   1788                 (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
   1789     case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
   1790         return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
   1791     case FIMD_BLENDCON:
   1792         return s->blendcon;
   1793     case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
   1794         return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
   1795     case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
   1796         return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
   1797     case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
   1798         if (offset & 0x0004) {
   1799             break;
   1800         }
   1801         return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
   1802     case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
   1803         if (offset & 0x0004) {
   1804             break;
   1805         }
   1806         return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
   1807     case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
   1808         if (offset & 0x0004) {
   1809             break;
   1810         }
   1811         return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
   1812     case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
   1813         return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
   1814     case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
   1815         w = (offset - FIMD_PAL_MEM_START) >> 10;
   1816         i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
   1817         return s->window[w].palette[i];
   1818     case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
   1819         /* Palette aliases for win 0,1 */
   1820         w = (offset - FIMD_PALMEM_AL_START) >> 10;
   1821         i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
   1822         return s->window[w].palette[i];
   1823     }
   1824 
   1825     qemu_log_mask(LOG_GUEST_ERROR,
   1826                   "FIMD: bad read offset 0x%08"HWADDR_PRIx"\n", offset);
   1827     return 0xBAADBAAD;
   1828 }
   1829 
   1830 static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
   1831     .read = exynos4210_fimd_read,
   1832     .write = exynos4210_fimd_write,
   1833     .valid = {
   1834         .min_access_size = 4,
   1835         .max_access_size = 4,
   1836         .unaligned = false
   1837     },
   1838     .endianness = DEVICE_NATIVE_ENDIAN,
   1839 };
   1840 
   1841 static int exynos4210_fimd_load(void *opaque, int version_id)
   1842 {
   1843     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
   1844     int w;
   1845 
   1846     if (version_id != 1) {
   1847         return -EINVAL;
   1848     }
   1849 
   1850     for (w = 0; w < NUM_OF_WINDOWS; w++) {
   1851         exynos4210_fimd_update_win_bppmode(s, w);
   1852         fimd_update_get_alpha(s, w);
   1853         fimd_update_memory_section(s, w);
   1854     }
   1855 
   1856     /* Redraw the whole screen */
   1857     exynos4210_update_resolution(s);
   1858     exynos4210_fimd_invalidate(s);
   1859     exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
   1860             FIMD_VIDCON0_ENVID_MASK);
   1861     return 0;
   1862 }
   1863 
   1864 static const VMStateDescription exynos4210_fimd_window_vmstate = {
   1865     .name = "exynos4210.fimd_window",
   1866     .version_id = 1,
   1867     .minimum_version_id = 1,
   1868     .fields = (VMStateField[]) {
   1869         VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
   1870         VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
   1871         VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
   1872         VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
   1873         VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
   1874         VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
   1875         VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
   1876         VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
   1877         VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
   1878         VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
   1879         VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
   1880         VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
   1881         VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
   1882         VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
   1883         VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
   1884         VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
   1885         VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
   1886         VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
   1887         VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
   1888         VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
   1889         VMSTATE_END_OF_LIST()
   1890     }
   1891 };
   1892 
   1893 static const VMStateDescription exynos4210_fimd_vmstate = {
   1894     .name = "exynos4210.fimd",
   1895     .version_id = 1,
   1896     .minimum_version_id = 1,
   1897     .post_load = exynos4210_fimd_load,
   1898     .fields = (VMStateField[]) {
   1899         VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
   1900         VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
   1901         VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
   1902         VMSTATE_UINT32(winchmap, Exynos4210fimdState),
   1903         VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
   1904         VMSTATE_UINT32(dithmode, Exynos4210fimdState),
   1905         VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
   1906         VMSTATE_UINT32(trigcon, Exynos4210fimdState),
   1907         VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
   1908         VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
   1909         VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
   1910         VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
   1911         VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
   1912         VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
   1913         VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
   1914         VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
   1915         VMSTATE_UINT32(blendcon, Exynos4210fimdState),
   1916         VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
   1917                 exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
   1918         VMSTATE_END_OF_LIST()
   1919     }
   1920 };
   1921 
   1922 static const GraphicHwOps exynos4210_fimd_ops = {
   1923     .invalidate  = exynos4210_fimd_invalidate,
   1924     .gfx_update  = exynos4210_fimd_update,
   1925 };
   1926 
   1927 static void exynos4210_fimd_init(Object *obj)
   1928 {
   1929     Exynos4210fimdState *s = EXYNOS4210_FIMD(obj);
   1930     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
   1931 
   1932     s->ifb = NULL;
   1933 
   1934     sysbus_init_irq(dev, &s->irq[0]);
   1935     sysbus_init_irq(dev, &s->irq[1]);
   1936     sysbus_init_irq(dev, &s->irq[2]);
   1937 
   1938     memory_region_init_io(&s->iomem, obj, &exynos4210_fimd_mmio_ops, s,
   1939             "exynos4210.fimd", FIMD_REGS_SIZE);
   1940     sysbus_init_mmio(dev, &s->iomem);
   1941 }
   1942 
   1943 static void exynos4210_fimd_realize(DeviceState *dev, Error **errp)
   1944 {
   1945     Exynos4210fimdState *s = EXYNOS4210_FIMD(dev);
   1946 
   1947     s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s);
   1948 }
   1949 
   1950 static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
   1951 {
   1952     DeviceClass *dc = DEVICE_CLASS(klass);
   1953 
   1954     dc->vmsd = &exynos4210_fimd_vmstate;
   1955     dc->reset = exynos4210_fimd_reset;
   1956     dc->realize = exynos4210_fimd_realize;
   1957 }
   1958 
   1959 static const TypeInfo exynos4210_fimd_info = {
   1960     .name = TYPE_EXYNOS4210_FIMD,
   1961     .parent = TYPE_SYS_BUS_DEVICE,
   1962     .instance_size = sizeof(Exynos4210fimdState),
   1963     .instance_init = exynos4210_fimd_init,
   1964     .class_init = exynos4210_fimd_class_init,
   1965 };
   1966 
   1967 static void exynos4210_fimd_register_types(void)
   1968 {
   1969     type_register_static(&exynos4210_fimd_info);
   1970 }
   1971 
   1972 type_init(exynos4210_fimd_register_types)