cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

pxa2xx_lcd.c (41128B)


      1/*
      2 * Intel XScale PXA255/270 LCDC emulation.
      3 *
      4 * Copyright (c) 2006 Openedhand Ltd.
      5 * Written by Andrzej Zaborowski <balrog@zabor.org>
      6 *
      7 * This code is licensed under the GPLv2.
      8 *
      9 * Contributions after 2012-01-13 are licensed under the terms of the
     10 * GNU GPL, version 2 or (at your option) any later version.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qemu/log.h"
     15#include "hw/irq.h"
     16#include "migration/vmstate.h"
     17#include "ui/console.h"
     18#include "hw/arm/pxa.h"
     19#include "ui/pixel_ops.h"
     20#include "hw/boards.h"
     21/* FIXME: For graphic_rotate. Should probably be done in common code.  */
     22#include "sysemu/sysemu.h"
     23#include "framebuffer.h"
     24
     25struct DMAChannel {
     26    uint32_t branch;
     27    uint8_t up;
     28    uint8_t palette[1024];
     29    uint8_t pbuffer[1024];
     30    void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
     31                   int *miny, int *maxy);
     32
     33    uint32_t descriptor;
     34    uint32_t source;
     35    uint32_t id;
     36    uint32_t command;
     37};
     38
     39struct PXA2xxLCDState {
     40    MemoryRegion *sysmem;
     41    MemoryRegion iomem;
     42    MemoryRegionSection fbsection;
     43    qemu_irq irq;
     44    int irqlevel;
     45
     46    int invalidated;
     47    QemuConsole *con;
     48    int dest_width;
     49    int xres, yres;
     50    int pal_for;
     51    int transp;
     52    enum {
     53        pxa_lcdc_2bpp = 1,
     54        pxa_lcdc_4bpp = 2,
     55        pxa_lcdc_8bpp = 3,
     56        pxa_lcdc_16bpp = 4,
     57        pxa_lcdc_18bpp = 5,
     58        pxa_lcdc_18pbpp = 6,
     59        pxa_lcdc_19bpp = 7,
     60        pxa_lcdc_19pbpp = 8,
     61        pxa_lcdc_24bpp = 9,
     62        pxa_lcdc_25bpp = 10,
     63    } bpp;
     64
     65    uint32_t control[6];
     66    uint32_t status[2];
     67    uint32_t ovl1c[2];
     68    uint32_t ovl2c[2];
     69    uint32_t ccr;
     70    uint32_t cmdcr;
     71    uint32_t trgbr;
     72    uint32_t tcr;
     73    uint32_t liidr;
     74    uint8_t bscntr;
     75
     76    struct DMAChannel dma_ch[7];
     77
     78    qemu_irq vsync_cb;
     79    int orientation;
     80};
     81
     82typedef struct QEMU_PACKED {
     83    uint32_t fdaddr;
     84    uint32_t fsaddr;
     85    uint32_t fidr;
     86    uint32_t ldcmd;
     87} PXAFrameDescriptor;
     88
     89#define LCCR0	0x000	/* LCD Controller Control register 0 */
     90#define LCCR1	0x004	/* LCD Controller Control register 1 */
     91#define LCCR2	0x008	/* LCD Controller Control register 2 */
     92#define LCCR3	0x00c	/* LCD Controller Control register 3 */
     93#define LCCR4	0x010	/* LCD Controller Control register 4 */
     94#define LCCR5	0x014	/* LCD Controller Control register 5 */
     95
     96#define FBR0	0x020	/* DMA Channel 0 Frame Branch register */
     97#define FBR1	0x024	/* DMA Channel 1 Frame Branch register */
     98#define FBR2	0x028	/* DMA Channel 2 Frame Branch register */
     99#define FBR3	0x02c	/* DMA Channel 3 Frame Branch register */
    100#define FBR4	0x030	/* DMA Channel 4 Frame Branch register */
    101#define FBR5	0x110	/* DMA Channel 5 Frame Branch register */
    102#define FBR6	0x114	/* DMA Channel 6 Frame Branch register */
    103
    104#define LCSR1	0x034	/* LCD Controller Status register 1 */
    105#define LCSR0	0x038	/* LCD Controller Status register 0 */
    106#define LIIDR	0x03c	/* LCD Controller Interrupt ID register */
    107
    108#define TRGBR	0x040	/* TMED RGB Seed register */
    109#define TCR	0x044	/* TMED Control register */
    110
    111#define OVL1C1	0x050	/* Overlay 1 Control register 1 */
    112#define OVL1C2	0x060	/* Overlay 1 Control register 2 */
    113#define OVL2C1	0x070	/* Overlay 2 Control register 1 */
    114#define OVL2C2	0x080	/* Overlay 2 Control register 2 */
    115#define CCR	0x090	/* Cursor Control register */
    116
    117#define CMDCR	0x100	/* Command Control register */
    118#define PRSR	0x104	/* Panel Read Status register */
    119
    120#define PXA_LCDDMA_CHANS	7
    121#define DMA_FDADR		0x00	/* Frame Descriptor Address register */
    122#define DMA_FSADR		0x04	/* Frame Source Address register */
    123#define DMA_FIDR		0x08	/* Frame ID register */
    124#define DMA_LDCMD		0x0c	/* Command register */
    125
    126/* LCD Buffer Strength Control register */
    127#define BSCNTR	0x04000054
    128
    129/* Bitfield masks */
    130#define LCCR0_ENB	(1 << 0)
    131#define LCCR0_CMS	(1 << 1)
    132#define LCCR0_SDS	(1 << 2)
    133#define LCCR0_LDM	(1 << 3)
    134#define LCCR0_SOFM0	(1 << 4)
    135#define LCCR0_IUM	(1 << 5)
    136#define LCCR0_EOFM0	(1 << 6)
    137#define LCCR0_PAS	(1 << 7)
    138#define LCCR0_DPD	(1 << 9)
    139#define LCCR0_DIS	(1 << 10)
    140#define LCCR0_QDM	(1 << 11)
    141#define LCCR0_PDD	(0xff << 12)
    142#define LCCR0_BSM0	(1 << 20)
    143#define LCCR0_OUM	(1 << 21)
    144#define LCCR0_LCDT	(1 << 22)
    145#define LCCR0_RDSTM	(1 << 23)
    146#define LCCR0_CMDIM	(1 << 24)
    147#define LCCR0_OUC	(1 << 25)
    148#define LCCR0_LDDALT	(1 << 26)
    149#define LCCR1_PPL(x)	((x) & 0x3ff)
    150#define LCCR2_LPP(x)	((x) & 0x3ff)
    151#define LCCR3_API	(15 << 16)
    152#define LCCR3_BPP(x)	((((x) >> 24) & 7) | (((x) >> 26) & 8))
    153#define LCCR3_PDFOR(x)	(((x) >> 30) & 3)
    154#define LCCR4_K1(x)	(((x) >> 0) & 7)
    155#define LCCR4_K2(x)	(((x) >> 3) & 7)
    156#define LCCR4_K3(x)	(((x) >> 6) & 7)
    157#define LCCR4_PALFOR(x)	(((x) >> 15) & 3)
    158#define LCCR5_SOFM(ch)	(1 << (ch - 1))
    159#define LCCR5_EOFM(ch)	(1 << (ch + 7))
    160#define LCCR5_BSM(ch)	(1 << (ch + 15))
    161#define LCCR5_IUM(ch)	(1 << (ch + 23))
    162#define OVLC1_EN	(1 << 31)
    163#define CCR_CEN		(1 << 31)
    164#define FBR_BRA		(1 << 0)
    165#define FBR_BINT	(1 << 1)
    166#define FBR_SRCADDR	(0xfffffff << 4)
    167#define LCSR0_LDD	(1 << 0)
    168#define LCSR0_SOF0	(1 << 1)
    169#define LCSR0_BER	(1 << 2)
    170#define LCSR0_ABC	(1 << 3)
    171#define LCSR0_IU0	(1 << 4)
    172#define LCSR0_IU1	(1 << 5)
    173#define LCSR0_OU	(1 << 6)
    174#define LCSR0_QD	(1 << 7)
    175#define LCSR0_EOF0	(1 << 8)
    176#define LCSR0_BS0	(1 << 9)
    177#define LCSR0_SINT	(1 << 10)
    178#define LCSR0_RDST	(1 << 11)
    179#define LCSR0_CMDINT	(1 << 12)
    180#define LCSR0_BERCH(x)	(((x) & 7) << 28)
    181#define LCSR1_SOF(ch)	(1 << (ch - 1))
    182#define LCSR1_EOF(ch)	(1 << (ch + 7))
    183#define LCSR1_BS(ch)	(1 << (ch + 15))
    184#define LCSR1_IU(ch)	(1 << (ch + 23))
    185#define LDCMD_LENGTH(x)	((x) & 0x001ffffc)
    186#define LDCMD_EOFINT	(1 << 21)
    187#define LDCMD_SOFINT	(1 << 22)
    188#define LDCMD_PAL	(1 << 26)
    189
    190/* Size of a pixel in the QEMU UI output surface, in bytes */
    191#define DEST_PIXEL_WIDTH 4
    192
    193/* Line drawing code to handle the various possible guest pixel formats */
    194
    195# define SKIP_PIXEL(to) do { to += deststep; } while (0)
    196# define COPY_PIXEL(to, from)    \
    197    do {                         \
    198        *(uint32_t *) to = from; \
    199        SKIP_PIXEL(to);          \
    200    } while (0)
    201
    202#ifdef HOST_WORDS_BIGENDIAN
    203# define SWAP_WORDS 1
    204#endif
    205
    206#define FN_2(x) FN(x + 1) FN(x)
    207#define FN_4(x) FN_2(x + 2) FN_2(x)
    208
    209static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src,
    210                              int width, int deststep)
    211{
    212    uint32_t *palette = opaque;
    213    uint32_t data;
    214    while (width > 0) {
    215        data = *(uint32_t *) src;
    216#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
    217#ifdef SWAP_WORDS
    218        FN_4(12)
    219        FN_4(8)
    220        FN_4(4)
    221        FN_4(0)
    222#else
    223        FN_4(0)
    224        FN_4(4)
    225        FN_4(8)
    226        FN_4(12)
    227#endif
    228#undef FN
    229        width -= 16;
    230        src += 4;
    231    }
    232}
    233
    234static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src,
    235                              int width, int deststep)
    236{
    237    uint32_t *palette = opaque;
    238    uint32_t data;
    239    while (width > 0) {
    240        data = *(uint32_t *) src;
    241#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
    242#ifdef SWAP_WORDS
    243        FN_2(6)
    244        FN_2(4)
    245        FN_2(2)
    246        FN_2(0)
    247#else
    248        FN_2(0)
    249        FN_2(2)
    250        FN_2(4)
    251        FN_2(6)
    252#endif
    253#undef FN
    254        width -= 8;
    255        src += 4;
    256    }
    257}
    258
    259static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src,
    260                              int width, int deststep)
    261{
    262    uint32_t *palette = opaque;
    263    uint32_t data;
    264    while (width > 0) {
    265        data = *(uint32_t *) src;
    266#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
    267#ifdef SWAP_WORDS
    268        FN(24)
    269        FN(16)
    270        FN(8)
    271        FN(0)
    272#else
    273        FN(0)
    274        FN(8)
    275        FN(16)
    276        FN(24)
    277#endif
    278#undef FN
    279        width -= 4;
    280        src += 4;
    281    }
    282}
    283
    284static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src,
    285                               int width, int deststep)
    286{
    287    uint32_t data;
    288    unsigned int r, g, b;
    289    while (width > 0) {
    290        data = *(uint32_t *) src;
    291#ifdef SWAP_WORDS
    292        data = bswap32(data);
    293#endif
    294        b = (data & 0x1f) << 3;
    295        data >>= 5;
    296        g = (data & 0x3f) << 2;
    297        data >>= 6;
    298        r = (data & 0x1f) << 3;
    299        data >>= 5;
    300        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    301        b = (data & 0x1f) << 3;
    302        data >>= 5;
    303        g = (data & 0x3f) << 2;
    304        data >>= 6;
    305        r = (data & 0x1f) << 3;
    306        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    307        width -= 2;
    308        src += 4;
    309    }
    310}
    311
    312static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src,
    313                                int width, int deststep)
    314{
    315    uint32_t data;
    316    unsigned int r, g, b;
    317    while (width > 0) {
    318        data = *(uint32_t *) src;
    319#ifdef SWAP_WORDS
    320        data = bswap32(data);
    321#endif
    322        b = (data & 0x1f) << 3;
    323        data >>= 5;
    324        g = (data & 0x1f) << 3;
    325        data >>= 5;
    326        r = (data & 0x1f) << 3;
    327        data >>= 5;
    328        if (data & 1) {
    329            SKIP_PIXEL(dest);
    330        } else {
    331            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    332        }
    333        data >>= 1;
    334        b = (data & 0x1f) << 3;
    335        data >>= 5;
    336        g = (data & 0x1f) << 3;
    337        data >>= 5;
    338        r = (data & 0x1f) << 3;
    339        data >>= 5;
    340        if (data & 1) {
    341            SKIP_PIXEL(dest);
    342        } else {
    343            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    344        }
    345        width -= 2;
    346        src += 4;
    347    }
    348}
    349
    350static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src,
    351                               int width, int deststep)
    352{
    353    uint32_t data;
    354    unsigned int r, g, b;
    355    while (width > 0) {
    356        data = *(uint32_t *) src;
    357#ifdef SWAP_WORDS
    358        data = bswap32(data);
    359#endif
    360        b = (data & 0x3f) << 2;
    361        data >>= 6;
    362        g = (data & 0x3f) << 2;
    363        data >>= 6;
    364        r = (data & 0x3f) << 2;
    365        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    366        width -= 1;
    367        src += 4;
    368    }
    369}
    370
    371/* The wicked packed format */
    372static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src,
    373                                int width, int deststep)
    374{
    375    uint32_t data[3];
    376    unsigned int r, g, b;
    377    while (width > 0) {
    378        data[0] = *(uint32_t *) src;
    379        src += 4;
    380        data[1] = *(uint32_t *) src;
    381        src += 4;
    382        data[2] = *(uint32_t *) src;
    383        src += 4;
    384#ifdef SWAP_WORDS
    385        data[0] = bswap32(data[0]);
    386        data[1] = bswap32(data[1]);
    387        data[2] = bswap32(data[2]);
    388#endif
    389        b = (data[0] & 0x3f) << 2;
    390        data[0] >>= 6;
    391        g = (data[0] & 0x3f) << 2;
    392        data[0] >>= 6;
    393        r = (data[0] & 0x3f) << 2;
    394        data[0] >>= 12;
    395        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    396        b = (data[0] & 0x3f) << 2;
    397        data[0] >>= 6;
    398        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
    399        data[1] >>= 4;
    400        r = (data[1] & 0x3f) << 2;
    401        data[1] >>= 12;
    402        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    403        b = (data[1] & 0x3f) << 2;
    404        data[1] >>= 6;
    405        g = (data[1] & 0x3f) << 2;
    406        data[1] >>= 6;
    407        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
    408        data[2] >>= 8;
    409        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    410        b = (data[2] & 0x3f) << 2;
    411        data[2] >>= 6;
    412        g = (data[2] & 0x3f) << 2;
    413        data[2] >>= 6;
    414        r = data[2] << 2;
    415        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    416        width -= 4;
    417    }
    418}
    419
    420static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src,
    421                               int width, int deststep)
    422{
    423    uint32_t data;
    424    unsigned int r, g, b;
    425    while (width > 0) {
    426        data = *(uint32_t *) src;
    427#ifdef SWAP_WORDS
    428        data = bswap32(data);
    429#endif
    430        b = (data & 0x3f) << 2;
    431        data >>= 6;
    432        g = (data & 0x3f) << 2;
    433        data >>= 6;
    434        r = (data & 0x3f) << 2;
    435        data >>= 6;
    436        if (data & 1) {
    437            SKIP_PIXEL(dest);
    438        } else {
    439            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    440        }
    441        width -= 1;
    442        src += 4;
    443    }
    444}
    445
    446/* The wicked packed format */
    447static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src,
    448                                int width, int deststep)
    449{
    450    uint32_t data[3];
    451    unsigned int r, g, b;
    452    while (width > 0) {
    453        data[0] = *(uint32_t *) src;
    454        src += 4;
    455        data[1] = *(uint32_t *) src;
    456        src += 4;
    457        data[2] = *(uint32_t *) src;
    458        src += 4;
    459# ifdef SWAP_WORDS
    460        data[0] = bswap32(data[0]);
    461        data[1] = bswap32(data[1]);
    462        data[2] = bswap32(data[2]);
    463# endif
    464        b = (data[0] & 0x3f) << 2;
    465        data[0] >>= 6;
    466        g = (data[0] & 0x3f) << 2;
    467        data[0] >>= 6;
    468        r = (data[0] & 0x3f) << 2;
    469        data[0] >>= 6;
    470        if (data[0] & 1) {
    471            SKIP_PIXEL(dest);
    472        } else {
    473            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    474        }
    475        data[0] >>= 6;
    476        b = (data[0] & 0x3f) << 2;
    477        data[0] >>= 6;
    478        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
    479        data[1] >>= 4;
    480        r = (data[1] & 0x3f) << 2;
    481        data[1] >>= 6;
    482        if (data[1] & 1) {
    483            SKIP_PIXEL(dest);
    484        } else {
    485            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    486        }
    487        data[1] >>= 6;
    488        b = (data[1] & 0x3f) << 2;
    489        data[1] >>= 6;
    490        g = (data[1] & 0x3f) << 2;
    491        data[1] >>= 6;
    492        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
    493        data[2] >>= 2;
    494        if (data[2] & 1) {
    495            SKIP_PIXEL(dest);
    496        } else {
    497            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    498        }
    499        data[2] >>= 6;
    500        b = (data[2] & 0x3f) << 2;
    501        data[2] >>= 6;
    502        g = (data[2] & 0x3f) << 2;
    503        data[2] >>= 6;
    504        r = data[2] << 2;
    505        data[2] >>= 6;
    506        if (data[2] & 1) {
    507            SKIP_PIXEL(dest);
    508        } else {
    509            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    510        }
    511        width -= 4;
    512    }
    513}
    514
    515static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src,
    516                               int width, int deststep)
    517{
    518    uint32_t data;
    519    unsigned int r, g, b;
    520    while (width > 0) {
    521        data = *(uint32_t *) src;
    522#ifdef SWAP_WORDS
    523        data = bswap32(data);
    524#endif
    525        b = data & 0xff;
    526        data >>= 8;
    527        g = data & 0xff;
    528        data >>= 8;
    529        r = data & 0xff;
    530        COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    531        width -= 1;
    532        src += 4;
    533    }
    534}
    535
    536static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src,
    537                                int width, int deststep)
    538{
    539    uint32_t data;
    540    unsigned int r, g, b;
    541    while (width > 0) {
    542        data = *(uint32_t *) src;
    543#ifdef SWAP_WORDS
    544        data = bswap32(data);
    545#endif
    546        b = (data & 0x7f) << 1;
    547        data >>= 7;
    548        g = data & 0xff;
    549        data >>= 8;
    550        r = data & 0xff;
    551        data >>= 8;
    552        if (data & 1) {
    553            SKIP_PIXEL(dest);
    554        } else {
    555            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    556        }
    557        width -= 1;
    558        src += 4;
    559    }
    560}
    561
    562static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src,
    563                               int width, int deststep)
    564{
    565    uint32_t data;
    566    unsigned int r, g, b;
    567    while (width > 0) {
    568        data = *(uint32_t *) src;
    569#ifdef SWAP_WORDS
    570        data = bswap32(data);
    571#endif
    572        b = data & 0xff;
    573        data >>= 8;
    574        g = data & 0xff;
    575        data >>= 8;
    576        r = data & 0xff;
    577        data >>= 8;
    578        if (data & 1) {
    579            SKIP_PIXEL(dest);
    580        } else {
    581            COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
    582        }
    583        width -= 1;
    584        src += 4;
    585    }
    586}
    587
    588/* Overlay planes disabled, no transparency */
    589static drawfn pxa2xx_draw_fn_32[16] = {
    590    [0 ... 0xf]       = NULL,
    591    [pxa_lcdc_2bpp]   = pxa2xx_draw_line2,
    592    [pxa_lcdc_4bpp]   = pxa2xx_draw_line4,
    593    [pxa_lcdc_8bpp]   = pxa2xx_draw_line8,
    594    [pxa_lcdc_16bpp]  = pxa2xx_draw_line16,
    595    [pxa_lcdc_18bpp]  = pxa2xx_draw_line18,
    596    [pxa_lcdc_18pbpp] = pxa2xx_draw_line18p,
    597    [pxa_lcdc_24bpp]  = pxa2xx_draw_line24,
    598};
    599
    600/* Overlay planes enabled, transparency used */
    601static drawfn pxa2xx_draw_fn_32t[16] = {
    602    [0 ... 0xf]       = NULL,
    603    [pxa_lcdc_4bpp]   = pxa2xx_draw_line4,
    604    [pxa_lcdc_8bpp]   = pxa2xx_draw_line8,
    605    [pxa_lcdc_16bpp]  = pxa2xx_draw_line16t,
    606    [pxa_lcdc_19bpp]  = pxa2xx_draw_line19,
    607    [pxa_lcdc_19pbpp] = pxa2xx_draw_line19p,
    608    [pxa_lcdc_24bpp]  = pxa2xx_draw_line24t,
    609    [pxa_lcdc_25bpp]  = pxa2xx_draw_line25,
    610};
    611
    612#undef COPY_PIXEL
    613#undef SKIP_PIXEL
    614
    615#ifdef SWAP_WORDS
    616# undef SWAP_WORDS
    617#endif
    618
    619/* Route internal interrupt lines to the global IC */
    620static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
    621{
    622    int level = 0;
    623    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
    624    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
    625    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
    626    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
    627    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
    628    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
    629    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
    630    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
    631    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
    632    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
    633    level |= (s->status[1] & ~s->control[5]);
    634
    635    qemu_set_irq(s->irq, !!level);
    636    s->irqlevel = level;
    637}
    638
    639/* Set Branch Status interrupt high and poke associated registers */
    640static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
    641{
    642    int unmasked;
    643    if (ch == 0) {
    644        s->status[0] |= LCSR0_BS0;
    645        unmasked = !(s->control[0] & LCCR0_BSM0);
    646    } else {
    647        s->status[1] |= LCSR1_BS(ch);
    648        unmasked = !(s->control[5] & LCCR5_BSM(ch));
    649    }
    650
    651    if (unmasked) {
    652        if (s->irqlevel)
    653            s->status[0] |= LCSR0_SINT;
    654        else
    655            s->liidr = s->dma_ch[ch].id;
    656    }
    657}
    658
    659/* Set Start Of Frame Status interrupt high and poke associated registers */
    660static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
    661{
    662    int unmasked;
    663    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
    664        return;
    665
    666    if (ch == 0) {
    667        s->status[0] |= LCSR0_SOF0;
    668        unmasked = !(s->control[0] & LCCR0_SOFM0);
    669    } else {
    670        s->status[1] |= LCSR1_SOF(ch);
    671        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
    672    }
    673
    674    if (unmasked) {
    675        if (s->irqlevel)
    676            s->status[0] |= LCSR0_SINT;
    677        else
    678            s->liidr = s->dma_ch[ch].id;
    679    }
    680}
    681
    682/* Set End Of Frame Status interrupt high and poke associated registers */
    683static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
    684{
    685    int unmasked;
    686    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
    687        return;
    688
    689    if (ch == 0) {
    690        s->status[0] |= LCSR0_EOF0;
    691        unmasked = !(s->control[0] & LCCR0_EOFM0);
    692    } else {
    693        s->status[1] |= LCSR1_EOF(ch);
    694        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
    695    }
    696
    697    if (unmasked) {
    698        if (s->irqlevel)
    699            s->status[0] |= LCSR0_SINT;
    700        else
    701            s->liidr = s->dma_ch[ch].id;
    702    }
    703}
    704
    705/* Set Bus Error Status interrupt high and poke associated registers */
    706static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
    707{
    708    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
    709    if (s->irqlevel)
    710        s->status[0] |= LCSR0_SINT;
    711    else
    712        s->liidr = s->dma_ch[ch].id;
    713}
    714
    715/* Load new Frame Descriptors from DMA */
    716static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
    717{
    718    PXAFrameDescriptor desc;
    719    hwaddr descptr;
    720    int i;
    721
    722    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
    723        s->dma_ch[i].source = 0;
    724
    725        if (!s->dma_ch[i].up)
    726            continue;
    727
    728        if (s->dma_ch[i].branch & FBR_BRA) {
    729            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
    730            if (s->dma_ch[i].branch & FBR_BINT)
    731                pxa2xx_dma_bs_set(s, i);
    732            s->dma_ch[i].branch &= ~FBR_BRA;
    733        } else
    734            descptr = s->dma_ch[i].descriptor;
    735
    736        if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
    737                 sizeof(desc) <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
    738                (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
    739                 PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
    740            continue;
    741        }
    742
    743        cpu_physical_memory_read(descptr, &desc, sizeof(desc));
    744        s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr);
    745        s->dma_ch[i].source = le32_to_cpu(desc.fsaddr);
    746        s->dma_ch[i].id = le32_to_cpu(desc.fidr);
    747        s->dma_ch[i].command = le32_to_cpu(desc.ldcmd);
    748    }
    749}
    750
    751static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
    752                                 unsigned size)
    753{
    754    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
    755    int ch;
    756
    757    switch (offset) {
    758    case LCCR0:
    759        return s->control[0];
    760    case LCCR1:
    761        return s->control[1];
    762    case LCCR2:
    763        return s->control[2];
    764    case LCCR3:
    765        return s->control[3];
    766    case LCCR4:
    767        return s->control[4];
    768    case LCCR5:
    769        return s->control[5];
    770
    771    case OVL1C1:
    772        return s->ovl1c[0];
    773    case OVL1C2:
    774        return s->ovl1c[1];
    775    case OVL2C1:
    776        return s->ovl2c[0];
    777    case OVL2C2:
    778        return s->ovl2c[1];
    779
    780    case CCR:
    781        return s->ccr;
    782
    783    case CMDCR:
    784        return s->cmdcr;
    785
    786    case TRGBR:
    787        return s->trgbr;
    788    case TCR:
    789        return s->tcr;
    790
    791    case 0x200 ... 0x1000:	/* DMA per-channel registers */
    792        ch = (offset - 0x200) >> 4;
    793        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
    794            goto fail;
    795
    796        switch (offset & 0xf) {
    797        case DMA_FDADR:
    798            return s->dma_ch[ch].descriptor;
    799        case DMA_FSADR:
    800            return s->dma_ch[ch].source;
    801        case DMA_FIDR:
    802            return s->dma_ch[ch].id;
    803        case DMA_LDCMD:
    804            return s->dma_ch[ch].command;
    805        default:
    806            goto fail;
    807        }
    808
    809    case FBR0:
    810        return s->dma_ch[0].branch;
    811    case FBR1:
    812        return s->dma_ch[1].branch;
    813    case FBR2:
    814        return s->dma_ch[2].branch;
    815    case FBR3:
    816        return s->dma_ch[3].branch;
    817    case FBR4:
    818        return s->dma_ch[4].branch;
    819    case FBR5:
    820        return s->dma_ch[5].branch;
    821    case FBR6:
    822        return s->dma_ch[6].branch;
    823
    824    case BSCNTR:
    825        return s->bscntr;
    826
    827    case PRSR:
    828        return 0;
    829
    830    case LCSR0:
    831        return s->status[0];
    832    case LCSR1:
    833        return s->status[1];
    834    case LIIDR:
    835        return s->liidr;
    836
    837    default:
    838    fail:
    839        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
    840                      __func__, offset);
    841    }
    842
    843    return 0;
    844}
    845
    846static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
    847                              uint64_t value, unsigned size)
    848{
    849    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
    850    int ch;
    851
    852    switch (offset) {
    853    case LCCR0:
    854        /* ACK Quick Disable done */
    855        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
    856            s->status[0] |= LCSR0_QD;
    857
    858        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) {
    859            qemu_log_mask(LOG_UNIMP,
    860                          "%s: internal frame buffer unsupported\n", __func__);
    861        }
    862        if ((s->control[3] & LCCR3_API) &&
    863                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
    864            s->status[0] |= LCSR0_ABC;
    865
    866        s->control[0] = value & 0x07ffffff;
    867        pxa2xx_lcdc_int_update(s);
    868
    869        s->dma_ch[0].up = !!(value & LCCR0_ENB);
    870        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
    871        break;
    872
    873    case LCCR1:
    874        s->control[1] = value;
    875        break;
    876
    877    case LCCR2:
    878        s->control[2] = value;
    879        break;
    880
    881    case LCCR3:
    882        s->control[3] = value & 0xefffffff;
    883        s->bpp = LCCR3_BPP(value);
    884        break;
    885
    886    case LCCR4:
    887        s->control[4] = value & 0x83ff81ff;
    888        break;
    889
    890    case LCCR5:
    891        s->control[5] = value & 0x3f3f3f3f;
    892        break;
    893
    894    case OVL1C1:
    895        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
    896            qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__);
    897        }
    898        s->ovl1c[0] = value & 0x80ffffff;
    899        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
    900        break;
    901
    902    case OVL1C2:
    903        s->ovl1c[1] = value & 0x000fffff;
    904        break;
    905
    906    case OVL2C1:
    907        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
    908            qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__);
    909        }
    910        s->ovl2c[0] = value & 0x80ffffff;
    911        s->dma_ch[2].up = !!(value & OVLC1_EN);
    912        s->dma_ch[3].up = !!(value & OVLC1_EN);
    913        s->dma_ch[4].up = !!(value & OVLC1_EN);
    914        break;
    915
    916    case OVL2C2:
    917        s->ovl2c[1] = value & 0x007fffff;
    918        break;
    919
    920    case CCR:
    921        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) {
    922            qemu_log_mask(LOG_UNIMP,
    923                          "%s: Hardware cursor unimplemented\n", __func__);
    924        }
    925        s->ccr = value & 0x81ffffe7;
    926        s->dma_ch[5].up = !!(value & CCR_CEN);
    927        break;
    928
    929    case CMDCR:
    930        s->cmdcr = value & 0xff;
    931        break;
    932
    933    case TRGBR:
    934        s->trgbr = value & 0x00ffffff;
    935        break;
    936
    937    case TCR:
    938        s->tcr = value & 0x7fff;
    939        break;
    940
    941    case 0x200 ... 0x1000:	/* DMA per-channel registers */
    942        ch = (offset - 0x200) >> 4;
    943        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
    944            goto fail;
    945
    946        switch (offset & 0xf) {
    947        case DMA_FDADR:
    948            s->dma_ch[ch].descriptor = value & 0xfffffff0;
    949            break;
    950
    951        default:
    952            goto fail;
    953        }
    954        break;
    955
    956    case FBR0:
    957        s->dma_ch[0].branch = value & 0xfffffff3;
    958        break;
    959    case FBR1:
    960        s->dma_ch[1].branch = value & 0xfffffff3;
    961        break;
    962    case FBR2:
    963        s->dma_ch[2].branch = value & 0xfffffff3;
    964        break;
    965    case FBR3:
    966        s->dma_ch[3].branch = value & 0xfffffff3;
    967        break;
    968    case FBR4:
    969        s->dma_ch[4].branch = value & 0xfffffff3;
    970        break;
    971    case FBR5:
    972        s->dma_ch[5].branch = value & 0xfffffff3;
    973        break;
    974    case FBR6:
    975        s->dma_ch[6].branch = value & 0xfffffff3;
    976        break;
    977
    978    case BSCNTR:
    979        s->bscntr = value & 0xf;
    980        break;
    981
    982    case PRSR:
    983        break;
    984
    985    case LCSR0:
    986        s->status[0] &= ~(value & 0xfff);
    987        if (value & LCSR0_BER)
    988            s->status[0] &= ~LCSR0_BERCH(7);
    989        break;
    990
    991    case LCSR1:
    992        s->status[1] &= ~(value & 0x3e3f3f);
    993        break;
    994
    995    default:
    996    fail:
    997        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
    998                      __func__, offset);
    999    }
   1000}
   1001
   1002static const MemoryRegionOps pxa2xx_lcdc_ops = {
   1003    .read = pxa2xx_lcdc_read,
   1004    .write = pxa2xx_lcdc_write,
   1005    .endianness = DEVICE_NATIVE_ENDIAN,
   1006};
   1007
   1008/* Load new palette for a given DMA channel, convert to internal format */
   1009static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
   1010{
   1011    DisplaySurface *surface = qemu_console_surface(s->con);
   1012    int i, n, format, r, g, b, alpha;
   1013    uint32_t *dest;
   1014    uint8_t *src;
   1015    s->pal_for = LCCR4_PALFOR(s->control[4]);
   1016    format = s->pal_for;
   1017
   1018    switch (bpp) {
   1019    case pxa_lcdc_2bpp:
   1020        n = 4;
   1021        break;
   1022    case pxa_lcdc_4bpp:
   1023        n = 16;
   1024        break;
   1025    case pxa_lcdc_8bpp:
   1026        n = 256;
   1027        break;
   1028    default:
   1029        return;
   1030    }
   1031
   1032    src = (uint8_t *) s->dma_ch[ch].pbuffer;
   1033    dest = (uint32_t *) s->dma_ch[ch].palette;
   1034    alpha = r = g = b = 0;
   1035
   1036    for (i = 0; i < n; i ++) {
   1037        switch (format) {
   1038        case 0: /* 16 bpp, no transparency */
   1039            alpha = 0;
   1040            if (s->control[0] & LCCR0_CMS) {
   1041                r = g = b = *(uint16_t *) src & 0xff;
   1042            }
   1043            else {
   1044                r = (*(uint16_t *) src & 0xf800) >> 8;
   1045                g = (*(uint16_t *) src & 0x07e0) >> 3;
   1046                b = (*(uint16_t *) src & 0x001f) << 3;
   1047            }
   1048            src += 2;
   1049            break;
   1050        case 1: /* 16 bpp plus transparency */
   1051            alpha = *(uint32_t *) src & (1 << 24);
   1052            if (s->control[0] & LCCR0_CMS)
   1053                r = g = b = *(uint32_t *) src & 0xff;
   1054            else {
   1055                r = (*(uint32_t *) src & 0xf80000) >> 16;
   1056                g = (*(uint32_t *) src & 0x00fc00) >> 8;
   1057                b = (*(uint32_t *) src & 0x0000f8);
   1058            }
   1059            src += 4;
   1060            break;
   1061        case 2: /* 18 bpp plus transparency */
   1062            alpha = *(uint32_t *) src & (1 << 24);
   1063            if (s->control[0] & LCCR0_CMS)
   1064                r = g = b = *(uint32_t *) src & 0xff;
   1065            else {
   1066                r = (*(uint32_t *) src & 0xfc0000) >> 16;
   1067                g = (*(uint32_t *) src & 0x00fc00) >> 8;
   1068                b = (*(uint32_t *) src & 0x0000fc);
   1069            }
   1070            src += 4;
   1071            break;
   1072        case 3: /* 24 bpp plus transparency */
   1073            alpha = *(uint32_t *) src & (1 << 24);
   1074            if (s->control[0] & LCCR0_CMS)
   1075                r = g = b = *(uint32_t *) src & 0xff;
   1076            else {
   1077                r = (*(uint32_t *) src & 0xff0000) >> 16;
   1078                g = (*(uint32_t *) src & 0x00ff00) >> 8;
   1079                b = (*(uint32_t *) src & 0x0000ff);
   1080            }
   1081            src += 4;
   1082            break;
   1083        }
   1084        switch (surface_bits_per_pixel(surface)) {
   1085        case 8:
   1086            *dest = rgb_to_pixel8(r, g, b) | alpha;
   1087            break;
   1088        case 15:
   1089            *dest = rgb_to_pixel15(r, g, b) | alpha;
   1090            break;
   1091        case 16:
   1092            *dest = rgb_to_pixel16(r, g, b) | alpha;
   1093            break;
   1094        case 24:
   1095            *dest = rgb_to_pixel24(r, g, b) | alpha;
   1096            break;
   1097        case 32:
   1098            *dest = rgb_to_pixel32(r, g, b) | alpha;
   1099            break;
   1100        }
   1101        dest ++;
   1102    }
   1103}
   1104
   1105static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s)
   1106{
   1107    if (s->transp) {
   1108        return pxa2xx_draw_fn_32t[s->bpp];
   1109    } else {
   1110        return pxa2xx_draw_fn_32[s->bpp];
   1111    }
   1112}
   1113
   1114static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
   1115                hwaddr addr, int *miny, int *maxy)
   1116{
   1117    DisplaySurface *surface = qemu_console_surface(s->con);
   1118    int src_width, dest_width;
   1119    drawfn fn = pxa2xx_drawfn(s);
   1120    if (!fn)
   1121        return;
   1122
   1123    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
   1124    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
   1125        src_width *= 3;
   1126    else if (s->bpp > pxa_lcdc_16bpp)
   1127        src_width *= 4;
   1128    else if (s->bpp > pxa_lcdc_8bpp)
   1129        src_width *= 2;
   1130
   1131    dest_width = s->xres * DEST_PIXEL_WIDTH;
   1132    *miny = 0;
   1133    if (s->invalidated) {
   1134        framebuffer_update_memory_section(&s->fbsection, s->sysmem,
   1135                                          addr, s->yres, src_width);
   1136    }
   1137    framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
   1138                               src_width, dest_width, DEST_PIXEL_WIDTH,
   1139                               s->invalidated,
   1140                               fn, s->dma_ch[0].palette, miny, maxy);
   1141}
   1142
   1143static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
   1144               hwaddr addr, int *miny, int *maxy)
   1145{
   1146    DisplaySurface *surface = qemu_console_surface(s->con);
   1147    int src_width, dest_width;
   1148    drawfn fn = pxa2xx_drawfn(s);
   1149    if (!fn)
   1150        return;
   1151
   1152    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
   1153    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
   1154        src_width *= 3;
   1155    else if (s->bpp > pxa_lcdc_16bpp)
   1156        src_width *= 4;
   1157    else if (s->bpp > pxa_lcdc_8bpp)
   1158        src_width *= 2;
   1159
   1160    dest_width = s->yres * DEST_PIXEL_WIDTH;
   1161    *miny = 0;
   1162    if (s->invalidated) {
   1163        framebuffer_update_memory_section(&s->fbsection, s->sysmem,
   1164                                          addr, s->yres, src_width);
   1165    }
   1166    framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
   1167                               src_width, DEST_PIXEL_WIDTH, -dest_width,
   1168                               s->invalidated,
   1169                               fn, s->dma_ch[0].palette,
   1170                               miny, maxy);
   1171}
   1172
   1173static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
   1174                hwaddr addr, int *miny, int *maxy)
   1175{
   1176    DisplaySurface *surface = qemu_console_surface(s->con);
   1177    int src_width, dest_width;
   1178    drawfn fn = pxa2xx_drawfn(s);
   1179    if (!fn) {
   1180        return;
   1181    }
   1182
   1183    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
   1184    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
   1185        src_width *= 3;
   1186    } else if (s->bpp > pxa_lcdc_16bpp) {
   1187        src_width *= 4;
   1188    } else if (s->bpp > pxa_lcdc_8bpp) {
   1189        src_width *= 2;
   1190    }
   1191
   1192    dest_width = s->xres * DEST_PIXEL_WIDTH;
   1193    *miny = 0;
   1194    if (s->invalidated) {
   1195        framebuffer_update_memory_section(&s->fbsection, s->sysmem,
   1196                                          addr, s->yres, src_width);
   1197    }
   1198    framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
   1199                               src_width, -dest_width, -DEST_PIXEL_WIDTH,
   1200                               s->invalidated,
   1201                               fn, s->dma_ch[0].palette, miny, maxy);
   1202}
   1203
   1204static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
   1205               hwaddr addr, int *miny, int *maxy)
   1206{
   1207    DisplaySurface *surface = qemu_console_surface(s->con);
   1208    int src_width, dest_width;
   1209    drawfn fn = pxa2xx_drawfn(s);
   1210    if (!fn) {
   1211        return;
   1212    }
   1213
   1214    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
   1215    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
   1216        src_width *= 3;
   1217    } else if (s->bpp > pxa_lcdc_16bpp) {
   1218        src_width *= 4;
   1219    } else if (s->bpp > pxa_lcdc_8bpp) {
   1220        src_width *= 2;
   1221    }
   1222
   1223    dest_width = s->yres * DEST_PIXEL_WIDTH;
   1224    *miny = 0;
   1225    if (s->invalidated) {
   1226        framebuffer_update_memory_section(&s->fbsection, s->sysmem,
   1227                                          addr, s->yres, src_width);
   1228    }
   1229    framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
   1230                               src_width, -DEST_PIXEL_WIDTH, dest_width,
   1231                               s->invalidated,
   1232                               fn, s->dma_ch[0].palette,
   1233                               miny, maxy);
   1234}
   1235
   1236static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
   1237{
   1238    int width, height;
   1239    if (!(s->control[0] & LCCR0_ENB))
   1240        return;
   1241
   1242    width = LCCR1_PPL(s->control[1]) + 1;
   1243    height = LCCR2_LPP(s->control[2]) + 1;
   1244
   1245    if (width != s->xres || height != s->yres) {
   1246        if (s->orientation == 90 || s->orientation == 270) {
   1247            qemu_console_resize(s->con, height, width);
   1248        } else {
   1249            qemu_console_resize(s->con, width, height);
   1250        }
   1251        s->invalidated = 1;
   1252        s->xres = width;
   1253        s->yres = height;
   1254    }
   1255}
   1256
   1257static void pxa2xx_update_display(void *opaque)
   1258{
   1259    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
   1260    hwaddr fbptr;
   1261    int miny, maxy;
   1262    int ch;
   1263    if (!(s->control[0] & LCCR0_ENB))
   1264        return;
   1265
   1266    pxa2xx_descriptor_load(s);
   1267
   1268    pxa2xx_lcdc_resize(s);
   1269    miny = s->yres;
   1270    maxy = 0;
   1271    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
   1272    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
   1273    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
   1274        if (s->dma_ch[ch].up) {
   1275            if (!s->dma_ch[ch].source) {
   1276                pxa2xx_dma_ber_set(s, ch);
   1277                continue;
   1278            }
   1279            fbptr = s->dma_ch[ch].source;
   1280            if (!((fbptr >= PXA2XX_SDRAM_BASE &&
   1281                     fbptr <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
   1282                    (fbptr >= PXA2XX_INTERNAL_BASE &&
   1283                     fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
   1284                pxa2xx_dma_ber_set(s, ch);
   1285                continue;
   1286            }
   1287
   1288            if (s->dma_ch[ch].command & LDCMD_PAL) {
   1289                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
   1290                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
   1291                        sizeof(s->dma_ch[ch].pbuffer)));
   1292                pxa2xx_palette_parse(s, ch, s->bpp);
   1293            } else {
   1294                /* Do we need to reparse palette */
   1295                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
   1296                    pxa2xx_palette_parse(s, ch, s->bpp);
   1297
   1298                /* ACK frame start */
   1299                pxa2xx_dma_sof_set(s, ch);
   1300
   1301                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
   1302                s->invalidated = 0;
   1303
   1304                /* ACK frame completed */
   1305                pxa2xx_dma_eof_set(s, ch);
   1306            }
   1307        }
   1308
   1309    if (s->control[0] & LCCR0_DIS) {
   1310        /* ACK last frame completed */
   1311        s->control[0] &= ~LCCR0_ENB;
   1312        s->status[0] |= LCSR0_LDD;
   1313    }
   1314
   1315    if (miny >= 0) {
   1316        switch (s->orientation) {
   1317        case 0:
   1318            dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
   1319            break;
   1320        case 90:
   1321            dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
   1322            break;
   1323        case 180:
   1324            maxy = s->yres - maxy - 1;
   1325            miny = s->yres - miny - 1;
   1326            dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
   1327            break;
   1328        case 270:
   1329            maxy = s->yres - maxy - 1;
   1330            miny = s->yres - miny - 1;
   1331            dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
   1332            break;
   1333        }
   1334    }
   1335    pxa2xx_lcdc_int_update(s);
   1336
   1337    qemu_irq_raise(s->vsync_cb);
   1338}
   1339
   1340static void pxa2xx_invalidate_display(void *opaque)
   1341{
   1342    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
   1343    s->invalidated = 1;
   1344}
   1345
   1346static void pxa2xx_lcdc_orientation(void *opaque, int angle)
   1347{
   1348    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
   1349
   1350    switch (angle) {
   1351    case 0:
   1352        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
   1353        break;
   1354    case 90:
   1355        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
   1356        break;
   1357    case 180:
   1358        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
   1359        break;
   1360    case 270:
   1361        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
   1362        break;
   1363    }
   1364
   1365    s->orientation = angle;
   1366    s->xres = s->yres = -1;
   1367    pxa2xx_lcdc_resize(s);
   1368}
   1369
   1370static const VMStateDescription vmstate_dma_channel = {
   1371    .name = "dma_channel",
   1372    .version_id = 0,
   1373    .minimum_version_id = 0,
   1374    .fields = (VMStateField[]) {
   1375        VMSTATE_UINT32(branch, struct DMAChannel),
   1376        VMSTATE_UINT8(up, struct DMAChannel),
   1377        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
   1378        VMSTATE_UINT32(descriptor, struct DMAChannel),
   1379        VMSTATE_UINT32(source, struct DMAChannel),
   1380        VMSTATE_UINT32(id, struct DMAChannel),
   1381        VMSTATE_UINT32(command, struct DMAChannel),
   1382        VMSTATE_END_OF_LIST()
   1383    }
   1384};
   1385
   1386static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
   1387{
   1388    PXA2xxLCDState *s = opaque;
   1389
   1390    s->bpp = LCCR3_BPP(s->control[3]);
   1391    s->xres = s->yres = s->pal_for = -1;
   1392
   1393    return 0;
   1394}
   1395
   1396static const VMStateDescription vmstate_pxa2xx_lcdc = {
   1397    .name = "pxa2xx_lcdc",
   1398    .version_id = 0,
   1399    .minimum_version_id = 0,
   1400    .post_load = pxa2xx_lcdc_post_load,
   1401    .fields = (VMStateField[]) {
   1402        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
   1403        VMSTATE_INT32(transp, PXA2xxLCDState),
   1404        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
   1405        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
   1406        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
   1407        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
   1408        VMSTATE_UINT32(ccr, PXA2xxLCDState),
   1409        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
   1410        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
   1411        VMSTATE_UINT32(tcr, PXA2xxLCDState),
   1412        VMSTATE_UINT32(liidr, PXA2xxLCDState),
   1413        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
   1414        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
   1415                             vmstate_dma_channel, struct DMAChannel),
   1416        VMSTATE_END_OF_LIST()
   1417    }
   1418};
   1419
   1420static const GraphicHwOps pxa2xx_ops = {
   1421    .invalidate  = pxa2xx_invalidate_display,
   1422    .gfx_update  = pxa2xx_update_display,
   1423};
   1424
   1425PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
   1426                                 hwaddr base, qemu_irq irq)
   1427{
   1428    PXA2xxLCDState *s;
   1429
   1430    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
   1431    s->invalidated = 1;
   1432    s->irq = irq;
   1433    s->sysmem = sysmem;
   1434
   1435    pxa2xx_lcdc_orientation(s, graphic_rotate);
   1436
   1437    memory_region_init_io(&s->iomem, NULL, &pxa2xx_lcdc_ops, s,
   1438                          "pxa2xx-lcd-controller", 0x00100000);
   1439    memory_region_add_subregion(sysmem, base, &s->iomem);
   1440
   1441    s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
   1442
   1443    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
   1444
   1445    return s;
   1446}
   1447
   1448void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
   1449{
   1450    s->vsync_cb = handler;
   1451}