130628cb1SMitsyanko Igor /* 230628cb1SMitsyanko Igor * Samsung exynos4210 Display Controller (FIMD) 330628cb1SMitsyanko Igor * 430628cb1SMitsyanko Igor * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. 530628cb1SMitsyanko Igor * All rights reserved. 630628cb1SMitsyanko Igor * Based on LCD controller for Samsung S5PC1xx-based board emulation 730628cb1SMitsyanko Igor * by Kirill Batuzov <batuzovk@ispras.ru> 830628cb1SMitsyanko Igor * 930628cb1SMitsyanko Igor * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com> 1030628cb1SMitsyanko Igor * 1130628cb1SMitsyanko Igor * This program is free software; you can redistribute it and/or modify it 1230628cb1SMitsyanko Igor * under the terms of the GNU General Public License as published by the 1330628cb1SMitsyanko Igor * Free Software Foundation; either version 2 of the License, or (at your 1430628cb1SMitsyanko Igor * option) any later version. 1530628cb1SMitsyanko Igor * 1630628cb1SMitsyanko Igor * This program is distributed in the hope that it will be useful, 1730628cb1SMitsyanko Igor * but WITHOUT ANY WARRANTY; without even the implied warranty of 1830628cb1SMitsyanko Igor * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1930628cb1SMitsyanko Igor * See the GNU General Public License for more details. 2030628cb1SMitsyanko Igor * 2130628cb1SMitsyanko Igor * You should have received a copy of the GNU General Public License along 2230628cb1SMitsyanko Igor * with this program; if not, see <http://www.gnu.org/licenses/>. 2330628cb1SMitsyanko Igor */ 2430628cb1SMitsyanko Igor 258ef94f0bSPeter Maydell #include "qemu/osdep.h" 2630628cb1SMitsyanko Igor #include "qemu-common.h" 2783c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2828ecbaeeSPaolo Bonzini #include "ui/console.h" 2928ecbaeeSPaolo Bonzini #include "ui/pixel_ops.h" 301de7afc9SPaolo Bonzini #include "qemu/bswap.h" 3130628cb1SMitsyanko Igor 3230628cb1SMitsyanko Igor /* Debug messages configuration */ 3330628cb1SMitsyanko Igor #define EXYNOS4210_FIMD_DEBUG 0 3430628cb1SMitsyanko Igor #define EXYNOS4210_FIMD_MODE_TRACE 0 3530628cb1SMitsyanko Igor 3630628cb1SMitsyanko Igor #if EXYNOS4210_FIMD_DEBUG == 0 3730628cb1SMitsyanko Igor #define DPRINT_L1(fmt, args...) do { } while (0) 3830628cb1SMitsyanko Igor #define DPRINT_L2(fmt, args...) do { } while (0) 3930628cb1SMitsyanko Igor #define DPRINT_ERROR(fmt, args...) do { } while (0) 4030628cb1SMitsyanko Igor #elif EXYNOS4210_FIMD_DEBUG == 1 4130628cb1SMitsyanko Igor #define DPRINT_L1(fmt, args...) \ 4230628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) 4330628cb1SMitsyanko Igor #define DPRINT_L2(fmt, args...) do { } while (0) 4430628cb1SMitsyanko Igor #define DPRINT_ERROR(fmt, args...) \ 4530628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0) 4630628cb1SMitsyanko Igor #else 4730628cb1SMitsyanko Igor #define DPRINT_L1(fmt, args...) \ 4830628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) 4930628cb1SMitsyanko Igor #define DPRINT_L2(fmt, args...) \ 5030628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) 5130628cb1SMitsyanko Igor #define DPRINT_ERROR(fmt, args...) \ 5230628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0) 5330628cb1SMitsyanko Igor #endif 5430628cb1SMitsyanko Igor 5530628cb1SMitsyanko Igor #if EXYNOS4210_FIMD_MODE_TRACE == 0 5630628cb1SMitsyanko Igor #define DPRINT_TRACE(fmt, args...) do { } while (0) 5730628cb1SMitsyanko Igor #else 5830628cb1SMitsyanko Igor #define DPRINT_TRACE(fmt, args...) \ 5930628cb1SMitsyanko Igor do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0) 6030628cb1SMitsyanko Igor #endif 6130628cb1SMitsyanko Igor 6230628cb1SMitsyanko Igor #define NUM_OF_WINDOWS 5 6330628cb1SMitsyanko Igor #define FIMD_REGS_SIZE 0x4114 6430628cb1SMitsyanko Igor 6530628cb1SMitsyanko Igor /* Video main control registers */ 6630628cb1SMitsyanko Igor #define FIMD_VIDCON0 0x0000 6730628cb1SMitsyanko Igor #define FIMD_VIDCON1 0x0004 6830628cb1SMitsyanko Igor #define FIMD_VIDCON2 0x0008 6930628cb1SMitsyanko Igor #define FIMD_VIDCON3 0x000C 7030628cb1SMitsyanko Igor #define FIMD_VIDCON0_ENVID_F (1 << 0) 7130628cb1SMitsyanko Igor #define FIMD_VIDCON0_ENVID (1 << 1) 7230628cb1SMitsyanko Igor #define FIMD_VIDCON0_ENVID_MASK ((1 << 0) | (1 << 1)) 7330628cb1SMitsyanko Igor #define FIMD_VIDCON1_ROMASK 0x07FFE000 7430628cb1SMitsyanko Igor 7530628cb1SMitsyanko Igor /* Video time control registers */ 7630628cb1SMitsyanko Igor #define FIMD_VIDTCON_START 0x10 7730628cb1SMitsyanko Igor #define FIMD_VIDTCON_END 0x1C 7830628cb1SMitsyanko Igor #define FIMD_VIDTCON2_SIZE_MASK 0x07FF 7930628cb1SMitsyanko Igor #define FIMD_VIDTCON2_HOR_SHIFT 0 8030628cb1SMitsyanko Igor #define FIMD_VIDTCON2_VER_SHIFT 11 8130628cb1SMitsyanko Igor 8230628cb1SMitsyanko Igor /* Window control registers */ 8330628cb1SMitsyanko Igor #define FIMD_WINCON_START 0x0020 8430628cb1SMitsyanko Igor #define FIMD_WINCON_END 0x0030 8530628cb1SMitsyanko Igor #define FIMD_WINCON_ROMASK 0x82200000 8630628cb1SMitsyanko Igor #define FIMD_WINCON_ENWIN (1 << 0) 8730628cb1SMitsyanko Igor #define FIMD_WINCON_BLD_PIX (1 << 6) 8830628cb1SMitsyanko Igor #define FIMD_WINCON_ALPHA_MUL (1 << 7) 8930628cb1SMitsyanko Igor #define FIMD_WINCON_ALPHA_SEL (1 << 1) 9030628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP 0x078000 9130628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP_SHIFT 15 9230628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP_WORD 0x1 9330628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP_HWORD 0x2 9430628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP_BYTE 0x4 9530628cb1SMitsyanko Igor #define FIMD_WINCON_SWAP_BITS 0x8 9630628cb1SMitsyanko Igor #define FIMD_WINCON_BUFSTAT_L (1 << 21) 9730628cb1SMitsyanko Igor #define FIMD_WINCON_BUFSTAT_H (1 << 31) 9830628cb1SMitsyanko Igor #define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31)) 9930628cb1SMitsyanko Igor #define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31)) 10030628cb1SMitsyanko Igor #define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31)) 10130628cb1SMitsyanko Igor #define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31)) 10230628cb1SMitsyanko Igor #define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30)) 10330628cb1SMitsyanko Igor #define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30)) 10430628cb1SMitsyanko Igor #define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30)) 10530628cb1SMitsyanko Igor #define FIMD_WINCON_BUF2_SEL ((0 << 20) | (1 << 30)) 10630628cb1SMitsyanko Igor #define FIMD_WINCON_BUFMODE (1 << 14) 10730628cb1SMitsyanko Igor #define IS_PALETTIZED_MODE(w) (w->wincon & 0xC) 10830628cb1SMitsyanko Igor #define PAL_MODE_WITH_ALPHA(x) ((x) == 7) 10930628cb1SMitsyanko Igor #define WIN_BPP_MODE(w) ((w->wincon >> 2) & 0xF) 11030628cb1SMitsyanko Igor #define WIN_BPP_MODE_WITH_ALPHA(w) \ 11130628cb1SMitsyanko Igor (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE) 11230628cb1SMitsyanko Igor 11330628cb1SMitsyanko Igor /* Shadow control register */ 11430628cb1SMitsyanko Igor #define FIMD_SHADOWCON 0x0034 11530628cb1SMitsyanko Igor #define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w)))) 11630628cb1SMitsyanko Igor /* Channel mapping control register */ 11730628cb1SMitsyanko Igor #define FIMD_WINCHMAP 0x003C 11830628cb1SMitsyanko Igor 11930628cb1SMitsyanko Igor /* Window position control registers */ 12030628cb1SMitsyanko Igor #define FIMD_VIDOSD_START 0x0040 12130628cb1SMitsyanko Igor #define FIMD_VIDOSD_END 0x0088 12230628cb1SMitsyanko Igor #define FIMD_VIDOSD_COORD_MASK 0x07FF 12330628cb1SMitsyanko Igor #define FIMD_VIDOSD_HOR_SHIFT 11 12430628cb1SMitsyanko Igor #define FIMD_VIDOSD_VER_SHIFT 0 12530628cb1SMitsyanko Igor #define FIMD_VIDOSD_ALPHA_AEN0 0xFFF000 12630628cb1SMitsyanko Igor #define FIMD_VIDOSD_AEN0_SHIFT 12 12730628cb1SMitsyanko Igor #define FIMD_VIDOSD_ALPHA_AEN1 0x000FFF 12830628cb1SMitsyanko Igor 12930628cb1SMitsyanko Igor /* Frame buffer address registers */ 13030628cb1SMitsyanko Igor #define FIMD_VIDWADD0_START 0x00A0 13130628cb1SMitsyanko Igor #define FIMD_VIDWADD0_END 0x00C4 13230628cb1SMitsyanko Igor #define FIMD_VIDWADD0_END 0x00C4 13330628cb1SMitsyanko Igor #define FIMD_VIDWADD1_START 0x00D0 13430628cb1SMitsyanko Igor #define FIMD_VIDWADD1_END 0x00F4 13530628cb1SMitsyanko Igor #define FIMD_VIDWADD2_START 0x0100 13630628cb1SMitsyanko Igor #define FIMD_VIDWADD2_END 0x0110 13730628cb1SMitsyanko Igor #define FIMD_VIDWADD2_PAGEWIDTH 0x1FFF 13830628cb1SMitsyanko Igor #define FIMD_VIDWADD2_OFFSIZE 0x1FFF 13930628cb1SMitsyanko Igor #define FIMD_VIDWADD2_OFFSIZE_SHIFT 13 14030628cb1SMitsyanko Igor #define FIMD_VIDW0ADD0_B2 0x20A0 14130628cb1SMitsyanko Igor #define FIMD_VIDW4ADD0_B2 0x20C0 14230628cb1SMitsyanko Igor 14330628cb1SMitsyanko Igor /* Video interrupt control registers */ 14430628cb1SMitsyanko Igor #define FIMD_VIDINTCON0 0x130 14530628cb1SMitsyanko Igor #define FIMD_VIDINTCON1 0x134 14630628cb1SMitsyanko Igor 14730628cb1SMitsyanko Igor /* Window color key registers */ 14830628cb1SMitsyanko Igor #define FIMD_WKEYCON_START 0x140 14930628cb1SMitsyanko Igor #define FIMD_WKEYCON_END 0x15C 15030628cb1SMitsyanko Igor #define FIMD_WKEYCON0_COMPKEY 0x00FFFFFF 15130628cb1SMitsyanko Igor #define FIMD_WKEYCON0_CTL_SHIFT 24 15230628cb1SMitsyanko Igor #define FIMD_WKEYCON0_DIRCON (1 << 24) 15330628cb1SMitsyanko Igor #define FIMD_WKEYCON0_KEYEN (1 << 25) 15430628cb1SMitsyanko Igor #define FIMD_WKEYCON0_KEYBLEN (1 << 26) 15530628cb1SMitsyanko Igor /* Window color key alpha control register */ 15630628cb1SMitsyanko Igor #define FIMD_WKEYALPHA_START 0x160 15730628cb1SMitsyanko Igor #define FIMD_WKEYALPHA_END 0x16C 15830628cb1SMitsyanko Igor 15930628cb1SMitsyanko Igor /* Dithering control register */ 16030628cb1SMitsyanko Igor #define FIMD_DITHMODE 0x170 16130628cb1SMitsyanko Igor 16230628cb1SMitsyanko Igor /* Window alpha control registers */ 16330628cb1SMitsyanko Igor #define FIMD_VIDALPHA_ALPHA_LOWER 0x000F0F0F 16430628cb1SMitsyanko Igor #define FIMD_VIDALPHA_ALPHA_UPPER 0x00F0F0F0 16530628cb1SMitsyanko Igor #define FIMD_VIDWALPHA_START 0x21C 16630628cb1SMitsyanko Igor #define FIMD_VIDWALPHA_END 0x240 16730628cb1SMitsyanko Igor 16830628cb1SMitsyanko Igor /* Window color map registers */ 16930628cb1SMitsyanko Igor #define FIMD_WINMAP_START 0x180 17030628cb1SMitsyanko Igor #define FIMD_WINMAP_END 0x190 17130628cb1SMitsyanko Igor #define FIMD_WINMAP_EN (1 << 24) 17230628cb1SMitsyanko Igor #define FIMD_WINMAP_COLOR_MASK 0x00FFFFFF 17330628cb1SMitsyanko Igor 17430628cb1SMitsyanko Igor /* Window palette control registers */ 17530628cb1SMitsyanko Igor #define FIMD_WPALCON_HIGH 0x019C 17630628cb1SMitsyanko Igor #define FIMD_WPALCON_LOW 0x01A0 17730628cb1SMitsyanko Igor #define FIMD_WPALCON_UPDATEEN (1 << 9) 17830628cb1SMitsyanko Igor #define FIMD_WPAL_W0PAL_L 0x07 17930628cb1SMitsyanko Igor #define FIMD_WPAL_W0PAL_L_SHT 0 18030628cb1SMitsyanko Igor #define FIMD_WPAL_W1PAL_L 0x07 18130628cb1SMitsyanko Igor #define FIMD_WPAL_W1PAL_L_SHT 3 18230628cb1SMitsyanko Igor #define FIMD_WPAL_W2PAL_L 0x01 18330628cb1SMitsyanko Igor #define FIMD_WPAL_W2PAL_L_SHT 6 18430628cb1SMitsyanko Igor #define FIMD_WPAL_W2PAL_H 0x06 18530628cb1SMitsyanko Igor #define FIMD_WPAL_W2PAL_H_SHT 8 18630628cb1SMitsyanko Igor #define FIMD_WPAL_W3PAL_L 0x01 18730628cb1SMitsyanko Igor #define FIMD_WPAL_W3PAL_L_SHT 7 18830628cb1SMitsyanko Igor #define FIMD_WPAL_W3PAL_H 0x06 18930628cb1SMitsyanko Igor #define FIMD_WPAL_W3PAL_H_SHT 12 19030628cb1SMitsyanko Igor #define FIMD_WPAL_W4PAL_L 0x01 19130628cb1SMitsyanko Igor #define FIMD_WPAL_W4PAL_L_SHT 8 19230628cb1SMitsyanko Igor #define FIMD_WPAL_W4PAL_H 0x06 19330628cb1SMitsyanko Igor #define FIMD_WPAL_W4PAL_H_SHT 16 19430628cb1SMitsyanko Igor 19530628cb1SMitsyanko Igor /* Trigger control registers */ 19630628cb1SMitsyanko Igor #define FIMD_TRIGCON 0x01A4 19730628cb1SMitsyanko Igor #define FIMD_TRIGCON_ROMASK 0x00000004 19830628cb1SMitsyanko Igor 19930628cb1SMitsyanko Igor /* LCD I80 Interface Control */ 20030628cb1SMitsyanko Igor #define FIMD_I80IFCON_START 0x01B0 20130628cb1SMitsyanko Igor #define FIMD_I80IFCON_END 0x01BC 20230628cb1SMitsyanko Igor /* Color gain control register */ 20330628cb1SMitsyanko Igor #define FIMD_COLORGAINCON 0x01C0 20430628cb1SMitsyanko Igor /* LCD i80 Interface Command Control */ 20530628cb1SMitsyanko Igor #define FIMD_LDI_CMDCON0 0x01D0 20630628cb1SMitsyanko Igor #define FIMD_LDI_CMDCON1 0x01D4 20730628cb1SMitsyanko Igor /* I80 System Interface Manual Command Control */ 20830628cb1SMitsyanko Igor #define FIMD_SIFCCON0 0x01E0 20930628cb1SMitsyanko Igor #define FIMD_SIFCCON2 0x01E8 21030628cb1SMitsyanko Igor 21130628cb1SMitsyanko Igor /* Hue Control Registers */ 21230628cb1SMitsyanko Igor #define FIMD_HUECOEFCR_START 0x01EC 21330628cb1SMitsyanko Igor #define FIMD_HUECOEFCR_END 0x01F4 21430628cb1SMitsyanko Igor #define FIMD_HUECOEFCB_START 0x01FC 21530628cb1SMitsyanko Igor #define FIMD_HUECOEFCB_END 0x0208 21630628cb1SMitsyanko Igor #define FIMD_HUEOFFSET 0x020C 21730628cb1SMitsyanko Igor 21830628cb1SMitsyanko Igor /* Video interrupt control registers */ 21930628cb1SMitsyanko Igor #define FIMD_VIDINT_INTFIFOPEND (1 << 0) 22030628cb1SMitsyanko Igor #define FIMD_VIDINT_INTFRMPEND (1 << 1) 22130628cb1SMitsyanko Igor #define FIMD_VIDINT_INTI80PEND (1 << 2) 22230628cb1SMitsyanko Igor #define FIMD_VIDINT_INTEN (1 << 0) 22330628cb1SMitsyanko Igor #define FIMD_VIDINT_INTFIFOEN (1 << 1) 22430628cb1SMitsyanko Igor #define FIMD_VIDINT_INTFRMEN (1 << 12) 22530628cb1SMitsyanko Igor #define FIMD_VIDINT_I80IFDONE (1 << 17) 22630628cb1SMitsyanko Igor 22730628cb1SMitsyanko Igor /* Window blend equation control registers */ 22830628cb1SMitsyanko Igor #define FIMD_BLENDEQ_START 0x0244 22930628cb1SMitsyanko Igor #define FIMD_BLENDEQ_END 0x0250 23030628cb1SMitsyanko Igor #define FIMD_BLENDCON 0x0260 23130628cb1SMitsyanko Igor #define FIMD_ALPHA_8BIT (1 << 0) 23230628cb1SMitsyanko Igor #define FIMD_BLENDEQ_COEF_MASK 0xF 23330628cb1SMitsyanko Igor 23430628cb1SMitsyanko Igor /* Window RTQOS Control Registers */ 23530628cb1SMitsyanko Igor #define FIMD_WRTQOSCON_START 0x0264 23630628cb1SMitsyanko Igor #define FIMD_WRTQOSCON_END 0x0274 23730628cb1SMitsyanko Igor 23830628cb1SMitsyanko Igor /* LCD I80 Interface Command */ 23930628cb1SMitsyanko Igor #define FIMD_I80IFCMD_START 0x0280 24030628cb1SMitsyanko Igor #define FIMD_I80IFCMD_END 0x02AC 24130628cb1SMitsyanko Igor 24230628cb1SMitsyanko Igor /* Shadow windows control registers */ 24330628cb1SMitsyanko Igor #define FIMD_SHD_ADD0_START 0x40A0 24430628cb1SMitsyanko Igor #define FIMD_SHD_ADD0_END 0x40C0 24530628cb1SMitsyanko Igor #define FIMD_SHD_ADD1_START 0x40D0 24630628cb1SMitsyanko Igor #define FIMD_SHD_ADD1_END 0x40F0 24730628cb1SMitsyanko Igor #define FIMD_SHD_ADD2_START 0x4100 24830628cb1SMitsyanko Igor #define FIMD_SHD_ADD2_END 0x4110 24930628cb1SMitsyanko Igor 25030628cb1SMitsyanko Igor /* Palette memory */ 25130628cb1SMitsyanko Igor #define FIMD_PAL_MEM_START 0x2400 25230628cb1SMitsyanko Igor #define FIMD_PAL_MEM_END 0x37FC 25330628cb1SMitsyanko Igor /* Palette memory aliases for windows 0 and 1 */ 25430628cb1SMitsyanko Igor #define FIMD_PALMEM_AL_START 0x0400 25530628cb1SMitsyanko Igor #define FIMD_PALMEM_AL_END 0x0BFC 25630628cb1SMitsyanko Igor 25730628cb1SMitsyanko Igor typedef struct { 25830628cb1SMitsyanko Igor uint8_t r, g, b; 25930628cb1SMitsyanko Igor /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */ 26030628cb1SMitsyanko Igor uint32_t a; 26130628cb1SMitsyanko Igor } rgba; 26230628cb1SMitsyanko Igor #define RGBA_SIZE 7 26330628cb1SMitsyanko Igor 26430628cb1SMitsyanko Igor typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p); 26530628cb1SMitsyanko Igor typedef struct Exynos4210fimdWindow Exynos4210fimdWindow; 26630628cb1SMitsyanko Igor 26730628cb1SMitsyanko Igor struct Exynos4210fimdWindow { 26830628cb1SMitsyanko Igor uint32_t wincon; /* Window control register */ 26930628cb1SMitsyanko Igor uint32_t buf_start[3]; /* Start address for video frame buffer */ 27030628cb1SMitsyanko Igor uint32_t buf_end[3]; /* End address for video frame buffer */ 27130628cb1SMitsyanko Igor uint32_t keycon[2]; /* Window color key registers */ 27230628cb1SMitsyanko Igor uint32_t keyalpha; /* Color key alpha control register */ 27330628cb1SMitsyanko Igor uint32_t winmap; /* Window color map register */ 27430628cb1SMitsyanko Igor uint32_t blendeq; /* Window blending equation control register */ 27530628cb1SMitsyanko Igor uint32_t rtqoscon; /* Window RTQOS Control Registers */ 27630628cb1SMitsyanko Igor uint32_t palette[256]; /* Palette RAM */ 27730628cb1SMitsyanko Igor uint32_t shadow_buf_start; /* Start address of shadow frame buffer */ 27830628cb1SMitsyanko Igor uint32_t shadow_buf_end; /* End address of shadow frame buffer */ 27930628cb1SMitsyanko Igor uint32_t shadow_buf_size; /* Virtual shadow screen width */ 28030628cb1SMitsyanko Igor 28130628cb1SMitsyanko Igor pixel_to_rgb_func *pixel_to_rgb; 28230628cb1SMitsyanko Igor void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst, 28330628cb1SMitsyanko Igor bool blend); 28430628cb1SMitsyanko Igor uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a); 28530628cb1SMitsyanko Igor uint16_t lefttop_x, lefttop_y; /* VIDOSD0 register */ 28630628cb1SMitsyanko Igor uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */ 28730628cb1SMitsyanko Igor uint32_t osdsize; /* VIDOSD2&3 register */ 28830628cb1SMitsyanko Igor uint32_t alpha_val[2]; /* VIDOSD2&3, VIDWALPHA registers */ 28930628cb1SMitsyanko Igor uint16_t virtpage_width; /* VIDWADD2 register */ 29030628cb1SMitsyanko Igor uint16_t virtpage_offsize; /* VIDWADD2 register */ 29130628cb1SMitsyanko Igor MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */ 29230628cb1SMitsyanko Igor uint8_t *host_fb_addr; /* Host pointer to window's framebuffer */ 293a8170e5eSAvi Kivity hwaddr fb_len; /* Framebuffer length */ 29430628cb1SMitsyanko Igor }; 29530628cb1SMitsyanko Igor 296f27321aaSAndreas Färber #define TYPE_EXYNOS4210_FIMD "exynos4210.fimd" 297f27321aaSAndreas Färber #define EXYNOS4210_FIMD(obj) \ 298f27321aaSAndreas Färber OBJECT_CHECK(Exynos4210fimdState, (obj), TYPE_EXYNOS4210_FIMD) 299f27321aaSAndreas Färber 30030628cb1SMitsyanko Igor typedef struct { 301f27321aaSAndreas Färber SysBusDevice parent_obj; 302f27321aaSAndreas Färber 30330628cb1SMitsyanko Igor MemoryRegion iomem; 304c78f7137SGerd Hoffmann QemuConsole *console; 30530628cb1SMitsyanko Igor qemu_irq irq[3]; 30630628cb1SMitsyanko Igor 30730628cb1SMitsyanko Igor uint32_t vidcon[4]; /* Video main control registers 0-3 */ 30830628cb1SMitsyanko Igor uint32_t vidtcon[4]; /* Video time control registers 0-3 */ 30930628cb1SMitsyanko Igor uint32_t shadowcon; /* Window shadow control register */ 31030628cb1SMitsyanko Igor uint32_t winchmap; /* Channel mapping control register */ 31130628cb1SMitsyanko Igor uint32_t vidintcon[2]; /* Video interrupt control registers */ 31230628cb1SMitsyanko Igor uint32_t dithmode; /* Dithering control register */ 31330628cb1SMitsyanko Igor uint32_t wpalcon[2]; /* Window palette control registers */ 31430628cb1SMitsyanko Igor uint32_t trigcon; /* Trigger control register */ 31530628cb1SMitsyanko Igor uint32_t i80ifcon[4]; /* I80 interface control registers */ 31630628cb1SMitsyanko Igor uint32_t colorgaincon; /* Color gain control register */ 31730628cb1SMitsyanko Igor uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */ 31830628cb1SMitsyanko Igor uint32_t sifccon[3]; /* I80 System Interface Manual Command Control */ 31930628cb1SMitsyanko Igor uint32_t huecoef_cr[4]; /* Hue control registers */ 32030628cb1SMitsyanko Igor uint32_t huecoef_cb[4]; /* Hue control registers */ 32130628cb1SMitsyanko Igor uint32_t hueoffset; /* Hue offset control register */ 32230628cb1SMitsyanko Igor uint32_t blendcon; /* Blending control register */ 32330628cb1SMitsyanko Igor uint32_t i80ifcmd[12]; /* LCD I80 Interface Command */ 32430628cb1SMitsyanko Igor 32530628cb1SMitsyanko Igor Exynos4210fimdWindow window[5]; /* Window-specific registers */ 32630628cb1SMitsyanko Igor uint8_t *ifb; /* Internal frame buffer */ 32730628cb1SMitsyanko Igor bool invalidate; /* Image needs to be redrawn */ 32830628cb1SMitsyanko Igor bool enabled; /* Display controller is enabled */ 32930628cb1SMitsyanko Igor } Exynos4210fimdState; 33030628cb1SMitsyanko Igor 33130628cb1SMitsyanko Igor /* Perform byte/halfword/word swap of data according to WINCON */ 33230628cb1SMitsyanko Igor static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data) 33330628cb1SMitsyanko Igor { 33430628cb1SMitsyanko Igor int i; 33530628cb1SMitsyanko Igor uint64_t res; 33630628cb1SMitsyanko Igor uint64_t x = *data; 33730628cb1SMitsyanko Igor 33830628cb1SMitsyanko Igor if (swap_ctl & FIMD_WINCON_SWAP_BITS) { 33930628cb1SMitsyanko Igor res = 0; 34030628cb1SMitsyanko Igor for (i = 0; i < 64; i++) { 341644ead5bSPeter Maydell if (x & (1ULL << (63 - i))) { 34230628cb1SMitsyanko Igor res |= (1ULL << i); 34330628cb1SMitsyanko Igor } 34430628cb1SMitsyanko Igor } 34530628cb1SMitsyanko Igor x = res; 34630628cb1SMitsyanko Igor } 34730628cb1SMitsyanko Igor 34830628cb1SMitsyanko Igor if (swap_ctl & FIMD_WINCON_SWAP_BYTE) { 34930628cb1SMitsyanko Igor x = bswap64(x); 35030628cb1SMitsyanko Igor } 35130628cb1SMitsyanko Igor 35230628cb1SMitsyanko Igor if (swap_ctl & FIMD_WINCON_SWAP_HWORD) { 35330628cb1SMitsyanko Igor x = ((x & 0x000000000000FFFFULL) << 48) | 35430628cb1SMitsyanko Igor ((x & 0x00000000FFFF0000ULL) << 16) | 35530628cb1SMitsyanko Igor ((x & 0x0000FFFF00000000ULL) >> 16) | 35630628cb1SMitsyanko Igor ((x & 0xFFFF000000000000ULL) >> 48); 35730628cb1SMitsyanko Igor } 35830628cb1SMitsyanko Igor 35930628cb1SMitsyanko Igor if (swap_ctl & FIMD_WINCON_SWAP_WORD) { 36030628cb1SMitsyanko Igor x = ((x & 0x00000000FFFFFFFFULL) << 32) | 36130628cb1SMitsyanko Igor ((x & 0xFFFFFFFF00000000ULL) >> 32); 36230628cb1SMitsyanko Igor } 36330628cb1SMitsyanko Igor 36430628cb1SMitsyanko Igor *data = x; 36530628cb1SMitsyanko Igor } 36630628cb1SMitsyanko Igor 36730628cb1SMitsyanko Igor /* Conversion routines of Pixel data from frame buffer area to internal RGBA 36830628cb1SMitsyanko Igor * pixel representation. 36930628cb1SMitsyanko Igor * Every color component internally represented as 8-bit value. If original 37030628cb1SMitsyanko Igor * data has less than 8 bit for component, data is extended to 8 bit. For 37130628cb1SMitsyanko Igor * example, if blue component has only two possible values 0 and 1 it will be 37230628cb1SMitsyanko Igor * extended to 0 and 0xFF */ 37330628cb1SMitsyanko Igor 37430628cb1SMitsyanko Igor /* One bit for alpha representation */ 37530628cb1SMitsyanko Igor #define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \ 37630628cb1SMitsyanko Igor static void N(uint32_t pixel, rgba *p) \ 37730628cb1SMitsyanko Igor { \ 37830628cb1SMitsyanko Igor p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \ 37930628cb1SMitsyanko Igor ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \ 38030628cb1SMitsyanko Igor pixel >>= (B); \ 38130628cb1SMitsyanko Igor p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \ 38230628cb1SMitsyanko Igor ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \ 38330628cb1SMitsyanko Igor pixel >>= (G); \ 38430628cb1SMitsyanko Igor p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \ 38530628cb1SMitsyanko Igor ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \ 38630628cb1SMitsyanko Igor pixel >>= (R); \ 38730628cb1SMitsyanko Igor p->a = (pixel & 0x1); \ 38830628cb1SMitsyanko Igor } 38930628cb1SMitsyanko Igor 39030628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4) 39130628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5) 39230628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6) 39330628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5) 39430628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8) 39530628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7) 39630628cb1SMitsyanko Igor 39730628cb1SMitsyanko Igor /* Alpha component is always zero */ 39830628cb1SMitsyanko Igor #define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \ 39930628cb1SMitsyanko Igor static void N(uint32_t pixel, rgba *p) \ 40030628cb1SMitsyanko Igor { \ 40130628cb1SMitsyanko Igor p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \ 40230628cb1SMitsyanko Igor ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \ 40330628cb1SMitsyanko Igor pixel >>= (B); \ 40430628cb1SMitsyanko Igor p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \ 40530628cb1SMitsyanko Igor ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \ 40630628cb1SMitsyanko Igor pixel >>= (G); \ 40730628cb1SMitsyanko Igor p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \ 40830628cb1SMitsyanko Igor ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \ 40930628cb1SMitsyanko Igor p->a = 0x0; \ 41030628cb1SMitsyanko Igor } 41130628cb1SMitsyanko Igor 41230628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb, 5, 6, 5) 41330628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb, 5, 5, 5) 41430628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb, 6, 6, 6) 41530628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb, 8, 8, 8) 41630628cb1SMitsyanko Igor 41730628cb1SMitsyanko Igor /* Alpha component has some meaningful value */ 41830628cb1SMitsyanko Igor #define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \ 41930628cb1SMitsyanko Igor static void N(uint32_t pixel, rgba *p) \ 42030628cb1SMitsyanko Igor { \ 42130628cb1SMitsyanko Igor p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \ 42230628cb1SMitsyanko Igor ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \ 42330628cb1SMitsyanko Igor pixel >>= (B); \ 42430628cb1SMitsyanko Igor p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \ 42530628cb1SMitsyanko Igor ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \ 42630628cb1SMitsyanko Igor pixel >>= (G); \ 42730628cb1SMitsyanko Igor p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \ 42830628cb1SMitsyanko Igor ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \ 42930628cb1SMitsyanko Igor pixel >>= (R); \ 43030628cb1SMitsyanko Igor p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \ 43130628cb1SMitsyanko Igor ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \ 43230628cb1SMitsyanko Igor p->a = p->a | (p->a << 8) | (p->a << 16); \ 43330628cb1SMitsyanko Igor } 43430628cb1SMitsyanko Igor 43530628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4) 43630628cb1SMitsyanko Igor DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8) 43730628cb1SMitsyanko Igor 43830628cb1SMitsyanko Igor /* Lookup table to extent 2-bit color component to 8 bit */ 43930628cb1SMitsyanko Igor static const uint8_t pixel_lutable_2b[4] = { 44030628cb1SMitsyanko Igor 0x0, 0x55, 0xAA, 0xFF 44130628cb1SMitsyanko Igor }; 44230628cb1SMitsyanko Igor /* Lookup table to extent 3-bit color component to 8 bit */ 44330628cb1SMitsyanko Igor static const uint8_t pixel_lutable_3b[8] = { 44430628cb1SMitsyanko Igor 0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF 44530628cb1SMitsyanko Igor }; 44630628cb1SMitsyanko Igor /* Special case for a232 bpp mode */ 44730628cb1SMitsyanko Igor static void pixel_a232_to_rgb(uint32_t pixel, rgba *p) 44830628cb1SMitsyanko Igor { 44930628cb1SMitsyanko Igor p->b = pixel_lutable_2b[(pixel & 0x3)]; 45030628cb1SMitsyanko Igor pixel >>= 2; 45130628cb1SMitsyanko Igor p->g = pixel_lutable_3b[(pixel & 0x7)]; 45230628cb1SMitsyanko Igor pixel >>= 3; 45330628cb1SMitsyanko Igor p->r = pixel_lutable_2b[(pixel & 0x3)]; 45430628cb1SMitsyanko Igor pixel >>= 2; 45530628cb1SMitsyanko Igor p->a = (pixel & 0x1); 45630628cb1SMitsyanko Igor } 45730628cb1SMitsyanko Igor 45830628cb1SMitsyanko Igor /* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB 45930628cb1SMitsyanko Igor * for all three color components */ 46030628cb1SMitsyanko Igor static void pixel_1555_to_rgb(uint32_t pixel, rgba *p) 46130628cb1SMitsyanko Igor { 46230628cb1SMitsyanko Igor uint8_t comm = (pixel >> 15) & 1; 46330628cb1SMitsyanko Igor p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3); 46430628cb1SMitsyanko Igor pixel >>= 5; 46530628cb1SMitsyanko Igor p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3); 46630628cb1SMitsyanko Igor pixel >>= 5; 46730628cb1SMitsyanko Igor p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3); 46830628cb1SMitsyanko Igor p->a = 0x0; 46930628cb1SMitsyanko Igor } 47030628cb1SMitsyanko Igor 47130628cb1SMitsyanko Igor /* Put/get pixel to/from internal LCD Controller framebuffer */ 47230628cb1SMitsyanko Igor 47330628cb1SMitsyanko Igor static int put_pixel_ifb(const rgba p, uint8_t *d) 47430628cb1SMitsyanko Igor { 47530628cb1SMitsyanko Igor *(uint8_t *)d++ = p.r; 47630628cb1SMitsyanko Igor *(uint8_t *)d++ = p.g; 47730628cb1SMitsyanko Igor *(uint8_t *)d++ = p.b; 47830628cb1SMitsyanko Igor *(uint32_t *)d = p.a; 47930628cb1SMitsyanko Igor return RGBA_SIZE; 48030628cb1SMitsyanko Igor } 48130628cb1SMitsyanko Igor 48230628cb1SMitsyanko Igor static int get_pixel_ifb(const uint8_t *s, rgba *p) 48330628cb1SMitsyanko Igor { 48430628cb1SMitsyanko Igor p->r = *(uint8_t *)s++; 48530628cb1SMitsyanko Igor p->g = *(uint8_t *)s++; 48630628cb1SMitsyanko Igor p->b = *(uint8_t *)s++; 48730628cb1SMitsyanko Igor p->a = (*(uint32_t *)s) & 0x00FFFFFF; 48830628cb1SMitsyanko Igor return RGBA_SIZE; 48930628cb1SMitsyanko Igor } 49030628cb1SMitsyanko Igor 49130628cb1SMitsyanko Igor static pixel_to_rgb_func *palette_data_format[8] = { 49230628cb1SMitsyanko Igor [0] = pixel_565_to_rgb, 49330628cb1SMitsyanko Igor [1] = pixel_a555_to_rgb, 49430628cb1SMitsyanko Igor [2] = pixel_666_to_rgb, 49530628cb1SMitsyanko Igor [3] = pixel_a665_to_rgb, 49630628cb1SMitsyanko Igor [4] = pixel_a666_to_rgb, 49730628cb1SMitsyanko Igor [5] = pixel_888_to_rgb, 49830628cb1SMitsyanko Igor [6] = pixel_a888_to_rgb, 49930628cb1SMitsyanko Igor [7] = pixel_8888_to_rgb 50030628cb1SMitsyanko Igor }; 50130628cb1SMitsyanko Igor 50230628cb1SMitsyanko Igor /* Returns Index in palette data formats table for given window number WINDOW */ 50330628cb1SMitsyanko Igor static uint32_t 50430628cb1SMitsyanko Igor exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window) 50530628cb1SMitsyanko Igor { 50630628cb1SMitsyanko Igor uint32_t ret; 50730628cb1SMitsyanko Igor 50830628cb1SMitsyanko Igor switch (window) { 50930628cb1SMitsyanko Igor case 0: 51030628cb1SMitsyanko Igor ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L; 51130628cb1SMitsyanko Igor if (ret != 7) { 51230628cb1SMitsyanko Igor ret = 6 - ret; 51330628cb1SMitsyanko Igor } 51430628cb1SMitsyanko Igor break; 51530628cb1SMitsyanko Igor case 1: 51630628cb1SMitsyanko Igor ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L; 51730628cb1SMitsyanko Igor if (ret != 7) { 51830628cb1SMitsyanko Igor ret = 6 - ret; 51930628cb1SMitsyanko Igor } 52030628cb1SMitsyanko Igor break; 52130628cb1SMitsyanko Igor case 2: 52230628cb1SMitsyanko Igor ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) | 52330628cb1SMitsyanko Igor ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L); 52430628cb1SMitsyanko Igor break; 52530628cb1SMitsyanko Igor case 3: 52630628cb1SMitsyanko Igor ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) | 52730628cb1SMitsyanko Igor ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L); 52830628cb1SMitsyanko Igor break; 52930628cb1SMitsyanko Igor case 4: 53030628cb1SMitsyanko Igor ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) | 53130628cb1SMitsyanko Igor ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L); 53230628cb1SMitsyanko Igor break; 53330628cb1SMitsyanko Igor default: 53430628cb1SMitsyanko Igor hw_error("exynos4210.fimd: incorrect window number %d\n", window); 53530628cb1SMitsyanko Igor ret = 0; 53630628cb1SMitsyanko Igor break; 53730628cb1SMitsyanko Igor } 53830628cb1SMitsyanko Igor return ret; 53930628cb1SMitsyanko Igor } 54030628cb1SMitsyanko Igor 54130628cb1SMitsyanko Igor #define FIMD_1_MINUS_COLOR(x) \ 54230628cb1SMitsyanko Igor ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \ 54330628cb1SMitsyanko Igor (0xFF0000 - ((x) & 0xFF0000))) 54430628cb1SMitsyanko Igor #define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0)) 54530628cb1SMitsyanko Igor #define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F)) 54630628cb1SMitsyanko Igor 54730628cb1SMitsyanko Igor /* Multiply three lower bytes of two 32-bit words with each other. 54830628cb1SMitsyanko Igor * Each byte with values 0-255 is considered as a number with possible values 54930628cb1SMitsyanko Igor * in a range [0 - 1] */ 55030628cb1SMitsyanko Igor static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b) 55130628cb1SMitsyanko Igor { 55230628cb1SMitsyanko Igor uint32_t tmp; 55330628cb1SMitsyanko Igor uint32_t ret; 55430628cb1SMitsyanko Igor 55530628cb1SMitsyanko Igor ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp; 55630628cb1SMitsyanko Igor ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 55730628cb1SMitsyanko Igor 0xFF00 : tmp << 8; 55830628cb1SMitsyanko Igor ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ? 55930628cb1SMitsyanko Igor 0xFF0000 : tmp << 16; 56030628cb1SMitsyanko Igor return ret; 56130628cb1SMitsyanko Igor } 56230628cb1SMitsyanko Igor 56330628cb1SMitsyanko Igor /* For each corresponding bytes of two 32-bit words: (a*b + c*d) 56430628cb1SMitsyanko Igor * Byte values 0-255 are mapped to a range [0 .. 1] */ 56530628cb1SMitsyanko Igor static inline uint32_t 56630628cb1SMitsyanko Igor fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d) 56730628cb1SMitsyanko Igor { 56830628cb1SMitsyanko Igor uint32_t tmp; 56930628cb1SMitsyanko Igor uint32_t ret; 57030628cb1SMitsyanko Igor 57130628cb1SMitsyanko Igor ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF)) 57230628cb1SMitsyanko Igor > 0xFF) ? 0xFF : tmp; 57330628cb1SMitsyanko Igor ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) * 57430628cb1SMitsyanko Igor ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8; 57530628cb1SMitsyanko Igor ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) + 57630628cb1SMitsyanko Igor ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ? 57730628cb1SMitsyanko Igor 0xFF0000 : tmp << 16; 57830628cb1SMitsyanko Igor return ret; 57930628cb1SMitsyanko Igor } 58030628cb1SMitsyanko Igor 58130628cb1SMitsyanko Igor /* These routines cover all possible sources of window's transparent factor 58230628cb1SMitsyanko Igor * used in blending equation. Choice of routine is affected by WPALCON 58330628cb1SMitsyanko Igor * registers, BLENDCON register and window's WINCON register */ 58430628cb1SMitsyanko Igor 58530628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a) 58630628cb1SMitsyanko Igor { 58730628cb1SMitsyanko Igor return pix_a; 58830628cb1SMitsyanko Igor } 58930628cb1SMitsyanko Igor 59030628cb1SMitsyanko Igor static uint32_t 59130628cb1SMitsyanko Igor fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a) 59230628cb1SMitsyanko Igor { 59330628cb1SMitsyanko Igor return EXTEND_LOWER_HALFBYTE(pix_a); 59430628cb1SMitsyanko Igor } 59530628cb1SMitsyanko Igor 59630628cb1SMitsyanko Igor static uint32_t 59730628cb1SMitsyanko Igor fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a) 59830628cb1SMitsyanko Igor { 59930628cb1SMitsyanko Igor return EXTEND_UPPER_HALFBYTE(pix_a); 60030628cb1SMitsyanko Igor } 60130628cb1SMitsyanko Igor 60230628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a) 60330628cb1SMitsyanko Igor { 60430628cb1SMitsyanko Igor return fimd_mult_each_byte(pix_a, w->alpha_val[0]); 60530628cb1SMitsyanko Igor } 60630628cb1SMitsyanko Igor 60730628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a) 60830628cb1SMitsyanko Igor { 60930628cb1SMitsyanko Igor return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a), 61030628cb1SMitsyanko Igor EXTEND_UPPER_HALFBYTE(w->alpha_val[0])); 61130628cb1SMitsyanko Igor } 61230628cb1SMitsyanko Igor 61330628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a) 61430628cb1SMitsyanko Igor { 61530628cb1SMitsyanko Igor return w->alpha_val[pix_a]; 61630628cb1SMitsyanko Igor } 61730628cb1SMitsyanko Igor 61830628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a) 61930628cb1SMitsyanko Igor { 62030628cb1SMitsyanko Igor return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]); 62130628cb1SMitsyanko Igor } 62230628cb1SMitsyanko Igor 62330628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a) 62430628cb1SMitsyanko Igor { 62530628cb1SMitsyanko Igor return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0]; 62630628cb1SMitsyanko Igor } 62730628cb1SMitsyanko Igor 62830628cb1SMitsyanko Igor static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a) 62930628cb1SMitsyanko Igor { 63030628cb1SMitsyanko Igor return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon & 63130628cb1SMitsyanko Igor FIMD_WINCON_ALPHA_SEL) ? 1 : 0]); 63230628cb1SMitsyanko Igor } 63330628cb1SMitsyanko Igor 63430628cb1SMitsyanko Igor /* Updates currently active alpha value get function for specified window */ 63530628cb1SMitsyanko Igor static void fimd_update_get_alpha(Exynos4210fimdState *s, int win) 63630628cb1SMitsyanko Igor { 63730628cb1SMitsyanko Igor Exynos4210fimdWindow *w = &s->window[win]; 63830628cb1SMitsyanko Igor const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT; 63930628cb1SMitsyanko Igor 64030628cb1SMitsyanko Igor if (w->wincon & FIMD_WINCON_BLD_PIX) { 64130628cb1SMitsyanko Igor if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) { 64230628cb1SMitsyanko Igor /* In this case, alpha component contains meaningful value */ 64330628cb1SMitsyanko Igor if (w->wincon & FIMD_WINCON_ALPHA_MUL) { 64430628cb1SMitsyanko Igor w->get_alpha = alpha_is_8bit ? 64530628cb1SMitsyanko Igor fimd_get_alpha_mult : fimd_get_alpha_mult_ext; 64630628cb1SMitsyanko Igor } else { 64730628cb1SMitsyanko Igor w->get_alpha = alpha_is_8bit ? 64830628cb1SMitsyanko Igor fimd_get_alpha_pix : fimd_get_alpha_pix_extlow; 64930628cb1SMitsyanko Igor } 65030628cb1SMitsyanko Igor } else { 65130628cb1SMitsyanko Igor if (IS_PALETTIZED_MODE(w) && 65230628cb1SMitsyanko Igor PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) { 65330628cb1SMitsyanko Igor /* Alpha component has 8-bit numeric value */ 65430628cb1SMitsyanko Igor w->get_alpha = alpha_is_8bit ? 65530628cb1SMitsyanko Igor fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh; 65630628cb1SMitsyanko Igor } else { 65730628cb1SMitsyanko Igor /* Alpha has only two possible values (AEN) */ 65830628cb1SMitsyanko Igor w->get_alpha = alpha_is_8bit ? 65930628cb1SMitsyanko Igor fimd_get_alpha_aen : fimd_get_alpha_aen_ext; 66030628cb1SMitsyanko Igor } 66130628cb1SMitsyanko Igor } 66230628cb1SMitsyanko Igor } else { 66330628cb1SMitsyanko Igor w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel : 66430628cb1SMitsyanko Igor fimd_get_alpha_sel_ext; 66530628cb1SMitsyanko Igor } 66630628cb1SMitsyanko Igor } 66730628cb1SMitsyanko Igor 66830628cb1SMitsyanko Igor /* Blends current window's (w) pixel (foreground pixel *ret) with background 66930628cb1SMitsyanko Igor * window (w_blend) pixel p_bg according to formula: 67030628cb1SMitsyanko Igor * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR 67130628cb1SMitsyanko Igor * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA 67230628cb1SMitsyanko Igor */ 67330628cb1SMitsyanko Igor static void 67430628cb1SMitsyanko Igor exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret) 67530628cb1SMitsyanko Igor { 67630628cb1SMitsyanko Igor rgba p_fg = *ret; 67730628cb1SMitsyanko Igor uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) | 67830628cb1SMitsyanko Igor (p_bg.b & 0xFF); 67930628cb1SMitsyanko Igor uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) | 68030628cb1SMitsyanko Igor (p_fg.b & 0xFF); 68130628cb1SMitsyanko Igor uint32_t alpha_fg = p_fg.a; 68230628cb1SMitsyanko Igor int i; 68330628cb1SMitsyanko Igor /* It is possible that blending equation parameters a and b do not 68430628cb1SMitsyanko Igor * depend on window BLENEQ register. Account for this with first_coef */ 68530628cb1SMitsyanko Igor enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4}; 68630628cb1SMitsyanko Igor uint32_t first_coef = A_COEF; 68730628cb1SMitsyanko Igor uint32_t blend_param[COEF_NUM]; 68830628cb1SMitsyanko Igor 68930628cb1SMitsyanko Igor if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) { 69030628cb1SMitsyanko Igor uint32_t colorkey = (w->keycon[1] & 69130628cb1SMitsyanko Igor ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY; 69230628cb1SMitsyanko Igor 69330628cb1SMitsyanko Igor if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) && 69430628cb1SMitsyanko Igor (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) { 69530628cb1SMitsyanko Igor /* Foreground pixel is displayed */ 69630628cb1SMitsyanko Igor if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) { 69730628cb1SMitsyanko Igor alpha_fg = w->keyalpha; 69830628cb1SMitsyanko Igor blend_param[A_COEF] = alpha_fg; 69930628cb1SMitsyanko Igor blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg); 70030628cb1SMitsyanko Igor } else { 70130628cb1SMitsyanko Igor alpha_fg = 0; 70230628cb1SMitsyanko Igor blend_param[A_COEF] = 0xFFFFFF; 70330628cb1SMitsyanko Igor blend_param[B_COEF] = 0x0; 70430628cb1SMitsyanko Igor } 70530628cb1SMitsyanko Igor first_coef = P_COEF; 70630628cb1SMitsyanko Igor } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 && 70730628cb1SMitsyanko Igor (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) { 70830628cb1SMitsyanko Igor /* Background pixel is displayed */ 70930628cb1SMitsyanko Igor if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) { 71030628cb1SMitsyanko Igor alpha_fg = w->keyalpha; 71130628cb1SMitsyanko Igor blend_param[A_COEF] = alpha_fg; 71230628cb1SMitsyanko Igor blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg); 71330628cb1SMitsyanko Igor } else { 71430628cb1SMitsyanko Igor alpha_fg = 0; 71530628cb1SMitsyanko Igor blend_param[A_COEF] = 0x0; 71630628cb1SMitsyanko Igor blend_param[B_COEF] = 0xFFFFFF; 71730628cb1SMitsyanko Igor } 71830628cb1SMitsyanko Igor first_coef = P_COEF; 71930628cb1SMitsyanko Igor } 72030628cb1SMitsyanko Igor } 72130628cb1SMitsyanko Igor 72230628cb1SMitsyanko Igor for (i = first_coef; i < COEF_NUM; i++) { 72330628cb1SMitsyanko Igor switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) { 72430628cb1SMitsyanko Igor case 0: 72530628cb1SMitsyanko Igor blend_param[i] = 0; 72630628cb1SMitsyanko Igor break; 72730628cb1SMitsyanko Igor case 1: 72830628cb1SMitsyanko Igor blend_param[i] = 0xFFFFFF; 72930628cb1SMitsyanko Igor break; 73030628cb1SMitsyanko Igor case 2: 73130628cb1SMitsyanko Igor blend_param[i] = alpha_fg; 73230628cb1SMitsyanko Igor break; 73330628cb1SMitsyanko Igor case 3: 73430628cb1SMitsyanko Igor blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg); 73530628cb1SMitsyanko Igor break; 73630628cb1SMitsyanko Igor case 4: 73730628cb1SMitsyanko Igor blend_param[i] = p_bg.a; 73830628cb1SMitsyanko Igor break; 73930628cb1SMitsyanko Igor case 5: 74030628cb1SMitsyanko Igor blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a); 74130628cb1SMitsyanko Igor break; 74230628cb1SMitsyanko Igor case 6: 74330628cb1SMitsyanko Igor blend_param[i] = w->alpha_val[0]; 74430628cb1SMitsyanko Igor break; 74530628cb1SMitsyanko Igor case 10: 74630628cb1SMitsyanko Igor blend_param[i] = fg_color; 74730628cb1SMitsyanko Igor break; 74830628cb1SMitsyanko Igor case 11: 74930628cb1SMitsyanko Igor blend_param[i] = FIMD_1_MINUS_COLOR(fg_color); 75030628cb1SMitsyanko Igor break; 75130628cb1SMitsyanko Igor case 12: 75230628cb1SMitsyanko Igor blend_param[i] = bg_color; 75330628cb1SMitsyanko Igor break; 75430628cb1SMitsyanko Igor case 13: 75530628cb1SMitsyanko Igor blend_param[i] = FIMD_1_MINUS_COLOR(bg_color); 75630628cb1SMitsyanko Igor break; 75730628cb1SMitsyanko Igor default: 75830628cb1SMitsyanko Igor hw_error("exynos4210.fimd: blend equation coef illegal value\n"); 75930628cb1SMitsyanko Igor break; 76030628cb1SMitsyanko Igor } 76130628cb1SMitsyanko Igor } 76230628cb1SMitsyanko Igor 76330628cb1SMitsyanko Igor fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF], 76430628cb1SMitsyanko Igor fg_color, blend_param[A_COEF]); 76530628cb1SMitsyanko Igor ret->b = fg_color & 0xFF; 76630628cb1SMitsyanko Igor fg_color >>= 8; 76730628cb1SMitsyanko Igor ret->g = fg_color & 0xFF; 76830628cb1SMitsyanko Igor fg_color >>= 8; 76930628cb1SMitsyanko Igor ret->r = fg_color & 0xFF; 77030628cb1SMitsyanko Igor ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF], 77130628cb1SMitsyanko Igor p_bg.a, blend_param[Q_COEF]); 77230628cb1SMitsyanko Igor } 77330628cb1SMitsyanko Igor 77430628cb1SMitsyanko Igor /* These routines read data from video frame buffer in system RAM, convert 77530628cb1SMitsyanko Igor * this data to display controller internal representation, if necessary, 77630628cb1SMitsyanko Igor * perform pixel blending with data, currently presented in internal buffer. 77730628cb1SMitsyanko Igor * Result is stored in display controller internal frame buffer. */ 77830628cb1SMitsyanko Igor 77930628cb1SMitsyanko Igor /* Draw line with index in palette table in RAM frame buffer data */ 78030628cb1SMitsyanko Igor #define DEF_DRAW_LINE_PALETTE(N) \ 78130628cb1SMitsyanko Igor static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \ 78230628cb1SMitsyanko Igor uint8_t *dst, bool blend) \ 78330628cb1SMitsyanko Igor { \ 78430628cb1SMitsyanko Igor int width = w->rightbot_x - w->lefttop_x + 1; \ 78530628cb1SMitsyanko Igor uint8_t *ifb = dst; \ 78630628cb1SMitsyanko Igor uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \ 78730628cb1SMitsyanko Igor uint64_t data; \ 78830628cb1SMitsyanko Igor rgba p, p_old; \ 78930628cb1SMitsyanko Igor int i; \ 79030628cb1SMitsyanko Igor do { \ 791fc97bb5bSPaolo Bonzini memcpy(&data, src, sizeof(data)); \ 79230628cb1SMitsyanko Igor src += 8; \ 79330628cb1SMitsyanko Igor fimd_swap_data(swap, &data); \ 79430628cb1SMitsyanko Igor for (i = (64 / (N) - 1); i >= 0; i--) { \ 79530628cb1SMitsyanko Igor w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \ 79630628cb1SMitsyanko Igor ((1ULL << (N)) - 1)], &p); \ 79730628cb1SMitsyanko Igor p.a = w->get_alpha(w, p.a); \ 79830628cb1SMitsyanko Igor if (blend) { \ 79930628cb1SMitsyanko Igor ifb += get_pixel_ifb(ifb, &p_old); \ 80030628cb1SMitsyanko Igor exynos4210_fimd_blend_pixel(w, p_old, &p); \ 80130628cb1SMitsyanko Igor } \ 80230628cb1SMitsyanko Igor dst += put_pixel_ifb(p, dst); \ 80330628cb1SMitsyanko Igor } \ 80430628cb1SMitsyanko Igor width -= (64 / (N)); \ 80530628cb1SMitsyanko Igor } while (width > 0); \ 80630628cb1SMitsyanko Igor } 80730628cb1SMitsyanko Igor 80830628cb1SMitsyanko Igor /* Draw line with direct color value in RAM frame buffer data */ 80930628cb1SMitsyanko Igor #define DEF_DRAW_LINE_NOPALETTE(N) \ 81030628cb1SMitsyanko Igor static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \ 81130628cb1SMitsyanko Igor uint8_t *dst, bool blend) \ 81230628cb1SMitsyanko Igor { \ 81330628cb1SMitsyanko Igor int width = w->rightbot_x - w->lefttop_x + 1; \ 81430628cb1SMitsyanko Igor uint8_t *ifb = dst; \ 81530628cb1SMitsyanko Igor uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \ 81630628cb1SMitsyanko Igor uint64_t data; \ 81730628cb1SMitsyanko Igor rgba p, p_old; \ 81830628cb1SMitsyanko Igor int i; \ 81930628cb1SMitsyanko Igor do { \ 820fc97bb5bSPaolo Bonzini memcpy(&data, src, sizeof(data)); \ 82130628cb1SMitsyanko Igor src += 8; \ 82230628cb1SMitsyanko Igor fimd_swap_data(swap, &data); \ 82330628cb1SMitsyanko Igor for (i = (64 / (N) - 1); i >= 0; i--) { \ 82430628cb1SMitsyanko Igor w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \ 82530628cb1SMitsyanko Igor p.a = w->get_alpha(w, p.a); \ 82630628cb1SMitsyanko Igor if (blend) { \ 82730628cb1SMitsyanko Igor ifb += get_pixel_ifb(ifb, &p_old); \ 82830628cb1SMitsyanko Igor exynos4210_fimd_blend_pixel(w, p_old, &p); \ 82930628cb1SMitsyanko Igor } \ 83030628cb1SMitsyanko Igor dst += put_pixel_ifb(p, dst); \ 83130628cb1SMitsyanko Igor } \ 83230628cb1SMitsyanko Igor width -= (64 / (N)); \ 83330628cb1SMitsyanko Igor } while (width > 0); \ 83430628cb1SMitsyanko Igor } 83530628cb1SMitsyanko Igor 83630628cb1SMitsyanko Igor DEF_DRAW_LINE_PALETTE(1) 83730628cb1SMitsyanko Igor DEF_DRAW_LINE_PALETTE(2) 83830628cb1SMitsyanko Igor DEF_DRAW_LINE_PALETTE(4) 83930628cb1SMitsyanko Igor DEF_DRAW_LINE_PALETTE(8) 84030628cb1SMitsyanko Igor DEF_DRAW_LINE_NOPALETTE(8) /* 8bpp mode has palette and non-palette versions */ 84130628cb1SMitsyanko Igor DEF_DRAW_LINE_NOPALETTE(16) 84230628cb1SMitsyanko Igor DEF_DRAW_LINE_NOPALETTE(32) 84330628cb1SMitsyanko Igor 84430628cb1SMitsyanko Igor /* Special draw line routine for window color map case */ 84530628cb1SMitsyanko Igor static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src, 84630628cb1SMitsyanko Igor uint8_t *dst, bool blend) 84730628cb1SMitsyanko Igor { 84830628cb1SMitsyanko Igor rgba p, p_old; 84930628cb1SMitsyanko Igor uint8_t *ifb = dst; 85030628cb1SMitsyanko Igor int width = w->rightbot_x - w->lefttop_x + 1; 85130628cb1SMitsyanko Igor uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK; 85230628cb1SMitsyanko Igor 85330628cb1SMitsyanko Igor do { 85430628cb1SMitsyanko Igor pixel_888_to_rgb(map_color, &p); 85530628cb1SMitsyanko Igor p.a = w->get_alpha(w, p.a); 85630628cb1SMitsyanko Igor if (blend) { 85730628cb1SMitsyanko Igor ifb += get_pixel_ifb(ifb, &p_old); 85830628cb1SMitsyanko Igor exynos4210_fimd_blend_pixel(w, p_old, &p); 85930628cb1SMitsyanko Igor } 86030628cb1SMitsyanko Igor dst += put_pixel_ifb(p, dst); 86130628cb1SMitsyanko Igor } while (--width); 86230628cb1SMitsyanko Igor } 86330628cb1SMitsyanko Igor 86430628cb1SMitsyanko Igor /* Write RGB to QEMU's GraphicConsole framebuffer */ 86530628cb1SMitsyanko Igor 86630628cb1SMitsyanko Igor static int put_to_qemufb_pixel8(const rgba p, uint8_t *d) 86730628cb1SMitsyanko Igor { 86830628cb1SMitsyanko Igor uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b); 86930628cb1SMitsyanko Igor *(uint8_t *)d = pixel; 87030628cb1SMitsyanko Igor return 1; 87130628cb1SMitsyanko Igor } 87230628cb1SMitsyanko Igor 87330628cb1SMitsyanko Igor static int put_to_qemufb_pixel15(const rgba p, uint8_t *d) 87430628cb1SMitsyanko Igor { 87530628cb1SMitsyanko Igor uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b); 87630628cb1SMitsyanko Igor *(uint16_t *)d = pixel; 87730628cb1SMitsyanko Igor return 2; 87830628cb1SMitsyanko Igor } 87930628cb1SMitsyanko Igor 88030628cb1SMitsyanko Igor static int put_to_qemufb_pixel16(const rgba p, uint8_t *d) 88130628cb1SMitsyanko Igor { 88230628cb1SMitsyanko Igor uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b); 88330628cb1SMitsyanko Igor *(uint16_t *)d = pixel; 88430628cb1SMitsyanko Igor return 2; 88530628cb1SMitsyanko Igor } 88630628cb1SMitsyanko Igor 88730628cb1SMitsyanko Igor static int put_to_qemufb_pixel24(const rgba p, uint8_t *d) 88830628cb1SMitsyanko Igor { 88930628cb1SMitsyanko Igor uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b); 89030628cb1SMitsyanko Igor *(uint8_t *)d++ = (pixel >> 0) & 0xFF; 89130628cb1SMitsyanko Igor *(uint8_t *)d++ = (pixel >> 8) & 0xFF; 89230628cb1SMitsyanko Igor *(uint8_t *)d++ = (pixel >> 16) & 0xFF; 89330628cb1SMitsyanko Igor return 3; 89430628cb1SMitsyanko Igor } 89530628cb1SMitsyanko Igor 89630628cb1SMitsyanko Igor static int put_to_qemufb_pixel32(const rgba p, uint8_t *d) 89730628cb1SMitsyanko Igor { 89830628cb1SMitsyanko Igor uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b); 89930628cb1SMitsyanko Igor *(uint32_t *)d = pixel; 90030628cb1SMitsyanko Igor return 4; 90130628cb1SMitsyanko Igor } 90230628cb1SMitsyanko Igor 90330628cb1SMitsyanko Igor /* Routine to copy pixel from internal buffer to QEMU buffer */ 90430628cb1SMitsyanko Igor static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel); 90530628cb1SMitsyanko Igor static inline void fimd_update_putpix_qemu(int bpp) 90630628cb1SMitsyanko Igor { 90730628cb1SMitsyanko Igor switch (bpp) { 90830628cb1SMitsyanko Igor case 8: 90930628cb1SMitsyanko Igor put_pixel_toqemu = put_to_qemufb_pixel8; 91030628cb1SMitsyanko Igor break; 91130628cb1SMitsyanko Igor case 15: 91230628cb1SMitsyanko Igor put_pixel_toqemu = put_to_qemufb_pixel15; 91330628cb1SMitsyanko Igor break; 91430628cb1SMitsyanko Igor case 16: 91530628cb1SMitsyanko Igor put_pixel_toqemu = put_to_qemufb_pixel16; 91630628cb1SMitsyanko Igor break; 91730628cb1SMitsyanko Igor case 24: 91830628cb1SMitsyanko Igor put_pixel_toqemu = put_to_qemufb_pixel24; 91930628cb1SMitsyanko Igor break; 92030628cb1SMitsyanko Igor case 32: 92130628cb1SMitsyanko Igor put_pixel_toqemu = put_to_qemufb_pixel32; 92230628cb1SMitsyanko Igor break; 92330628cb1SMitsyanko Igor default: 92430628cb1SMitsyanko Igor hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp); 92530628cb1SMitsyanko Igor break; 92630628cb1SMitsyanko Igor } 92730628cb1SMitsyanko Igor } 92830628cb1SMitsyanko Igor 92930628cb1SMitsyanko Igor /* Routine to copy a line from internal frame buffer to QEMU display */ 93030628cb1SMitsyanko Igor static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst) 93130628cb1SMitsyanko Igor { 93230628cb1SMitsyanko Igor rgba p; 93330628cb1SMitsyanko Igor 93430628cb1SMitsyanko Igor do { 93530628cb1SMitsyanko Igor src += get_pixel_ifb(src, &p); 93630628cb1SMitsyanko Igor dst += put_pixel_toqemu(p, dst); 93730628cb1SMitsyanko Igor } while (--width); 93830628cb1SMitsyanko Igor } 93930628cb1SMitsyanko Igor 94030628cb1SMitsyanko Igor /* Parse BPPMODE_F = WINCON1[5:2] bits */ 94130628cb1SMitsyanko Igor static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win) 94230628cb1SMitsyanko Igor { 94330628cb1SMitsyanko Igor Exynos4210fimdWindow *w = &s->window[win]; 94430628cb1SMitsyanko Igor 94530628cb1SMitsyanko Igor if (w->winmap & FIMD_WINMAP_EN) { 94630628cb1SMitsyanko Igor w->draw_line = draw_line_mapcolor; 94730628cb1SMitsyanko Igor return; 94830628cb1SMitsyanko Igor } 94930628cb1SMitsyanko Igor 95030628cb1SMitsyanko Igor switch (WIN_BPP_MODE(w)) { 95130628cb1SMitsyanko Igor case 0: 95230628cb1SMitsyanko Igor w->draw_line = draw_line_palette_1; 95330628cb1SMitsyanko Igor w->pixel_to_rgb = 95430628cb1SMitsyanko Igor palette_data_format[exynos4210_fimd_palette_format(s, win)]; 95530628cb1SMitsyanko Igor break; 95630628cb1SMitsyanko Igor case 1: 95730628cb1SMitsyanko Igor w->draw_line = draw_line_palette_2; 95830628cb1SMitsyanko Igor w->pixel_to_rgb = 95930628cb1SMitsyanko Igor palette_data_format[exynos4210_fimd_palette_format(s, win)]; 96030628cb1SMitsyanko Igor break; 96130628cb1SMitsyanko Igor case 2: 96230628cb1SMitsyanko Igor w->draw_line = draw_line_palette_4; 96330628cb1SMitsyanko Igor w->pixel_to_rgb = 96430628cb1SMitsyanko Igor palette_data_format[exynos4210_fimd_palette_format(s, win)]; 96530628cb1SMitsyanko Igor break; 96630628cb1SMitsyanko Igor case 3: 96730628cb1SMitsyanko Igor w->draw_line = draw_line_palette_8; 96830628cb1SMitsyanko Igor w->pixel_to_rgb = 96930628cb1SMitsyanko Igor palette_data_format[exynos4210_fimd_palette_format(s, win)]; 97030628cb1SMitsyanko Igor break; 97130628cb1SMitsyanko Igor case 4: 97230628cb1SMitsyanko Igor w->draw_line = draw_line_8; 97330628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a232_to_rgb; 97430628cb1SMitsyanko Igor break; 97530628cb1SMitsyanko Igor case 5: 97630628cb1SMitsyanko Igor w->draw_line = draw_line_16; 97730628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_565_to_rgb; 97830628cb1SMitsyanko Igor break; 97930628cb1SMitsyanko Igor case 6: 98030628cb1SMitsyanko Igor w->draw_line = draw_line_16; 98130628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a555_to_rgb; 98230628cb1SMitsyanko Igor break; 98330628cb1SMitsyanko Igor case 7: 98430628cb1SMitsyanko Igor w->draw_line = draw_line_16; 98530628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_1555_to_rgb; 98630628cb1SMitsyanko Igor break; 98730628cb1SMitsyanko Igor case 8: 98830628cb1SMitsyanko Igor w->draw_line = draw_line_32; 98930628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_666_to_rgb; 99030628cb1SMitsyanko Igor break; 99130628cb1SMitsyanko Igor case 9: 99230628cb1SMitsyanko Igor w->draw_line = draw_line_32; 99330628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a665_to_rgb; 99430628cb1SMitsyanko Igor break; 99530628cb1SMitsyanko Igor case 10: 99630628cb1SMitsyanko Igor w->draw_line = draw_line_32; 99730628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a666_to_rgb; 99830628cb1SMitsyanko Igor break; 99930628cb1SMitsyanko Igor case 11: 100030628cb1SMitsyanko Igor w->draw_line = draw_line_32; 100130628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_888_to_rgb; 100230628cb1SMitsyanko Igor break; 100330628cb1SMitsyanko Igor case 12: 100430628cb1SMitsyanko Igor w->draw_line = draw_line_32; 100530628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a887_to_rgb; 100630628cb1SMitsyanko Igor break; 100730628cb1SMitsyanko Igor case 13: 100830628cb1SMitsyanko Igor w->draw_line = draw_line_32; 100930628cb1SMitsyanko Igor if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon & 101030628cb1SMitsyanko Igor FIMD_WINCON_ALPHA_SEL)) { 101130628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_8888_to_rgb; 101230628cb1SMitsyanko Igor } else { 101330628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a888_to_rgb; 101430628cb1SMitsyanko Igor } 101530628cb1SMitsyanko Igor break; 101630628cb1SMitsyanko Igor case 14: 101730628cb1SMitsyanko Igor w->draw_line = draw_line_16; 101830628cb1SMitsyanko Igor if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon & 101930628cb1SMitsyanko Igor FIMD_WINCON_ALPHA_SEL)) { 102030628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_4444_to_rgb; 102130628cb1SMitsyanko Igor } else { 102230628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_a444_to_rgb; 102330628cb1SMitsyanko Igor } 102430628cb1SMitsyanko Igor break; 102530628cb1SMitsyanko Igor case 15: 102630628cb1SMitsyanko Igor w->draw_line = draw_line_16; 102730628cb1SMitsyanko Igor w->pixel_to_rgb = pixel_555_to_rgb; 102830628cb1SMitsyanko Igor break; 102930628cb1SMitsyanko Igor } 103030628cb1SMitsyanko Igor } 103130628cb1SMitsyanko Igor 103230628cb1SMitsyanko Igor #if EXYNOS4210_FIMD_MODE_TRACE > 0 103330628cb1SMitsyanko Igor static const char *exynos4210_fimd_get_bppmode(int mode_code) 103430628cb1SMitsyanko Igor { 103530628cb1SMitsyanko Igor switch (mode_code) { 103630628cb1SMitsyanko Igor case 0: 103730628cb1SMitsyanko Igor return "1 bpp"; 103830628cb1SMitsyanko Igor case 1: 103930628cb1SMitsyanko Igor return "2 bpp"; 104030628cb1SMitsyanko Igor case 2: 104130628cb1SMitsyanko Igor return "4 bpp"; 104230628cb1SMitsyanko Igor case 3: 104330628cb1SMitsyanko Igor return "8 bpp (palettized)"; 104430628cb1SMitsyanko Igor case 4: 104530628cb1SMitsyanko Igor return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)"; 104630628cb1SMitsyanko Igor case 5: 104730628cb1SMitsyanko Igor return "16 bpp (non-palettized, R:5-G:6-B:5)"; 104830628cb1SMitsyanko Igor case 6: 104930628cb1SMitsyanko Igor return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)"; 105030628cb1SMitsyanko Igor case 7: 105130628cb1SMitsyanko Igor return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)"; 105230628cb1SMitsyanko Igor case 8: 105330628cb1SMitsyanko Igor return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)"; 105430628cb1SMitsyanko Igor case 9: 105530628cb1SMitsyanko Igor return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)"; 105630628cb1SMitsyanko Igor case 10: 105730628cb1SMitsyanko Igor return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)"; 105830628cb1SMitsyanko Igor case 11: 105930628cb1SMitsyanko Igor return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)"; 106030628cb1SMitsyanko Igor case 12: 106130628cb1SMitsyanko Igor return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)"; 106230628cb1SMitsyanko Igor case 13: 106330628cb1SMitsyanko Igor return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)"; 106430628cb1SMitsyanko Igor case 14: 106530628cb1SMitsyanko Igor return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)"; 106630628cb1SMitsyanko Igor case 15: 106730628cb1SMitsyanko Igor return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)"; 106830628cb1SMitsyanko Igor default: 106930628cb1SMitsyanko Igor return "Non-existing bpp mode"; 107030628cb1SMitsyanko Igor } 107130628cb1SMitsyanko Igor } 107230628cb1SMitsyanko Igor 107330628cb1SMitsyanko Igor static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s, 107430628cb1SMitsyanko Igor int win_num, uint32_t val) 107530628cb1SMitsyanko Igor { 107630628cb1SMitsyanko Igor Exynos4210fimdWindow *w = &s->window[win_num]; 107730628cb1SMitsyanko Igor 107830628cb1SMitsyanko Igor if (w->winmap & FIMD_WINMAP_EN) { 107930628cb1SMitsyanko Igor printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n", 108030628cb1SMitsyanko Igor win_num, w->winmap & 0xFFFFFF); 108130628cb1SMitsyanko Igor return; 108230628cb1SMitsyanko Igor } 108330628cb1SMitsyanko Igor 108430628cb1SMitsyanko Igor if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) { 108530628cb1SMitsyanko Igor return; 108630628cb1SMitsyanko Igor } 108730628cb1SMitsyanko Igor printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num, 108830628cb1SMitsyanko Igor exynos4210_fimd_get_bppmode((val >> 2) & 0xF)); 108930628cb1SMitsyanko Igor } 109030628cb1SMitsyanko Igor #else 109130628cb1SMitsyanko Igor static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s, 109230628cb1SMitsyanko Igor int win_num, uint32_t val) 109330628cb1SMitsyanko Igor { 109430628cb1SMitsyanko Igor 109530628cb1SMitsyanko Igor } 109630628cb1SMitsyanko Igor #endif 109730628cb1SMitsyanko Igor 109830628cb1SMitsyanko Igor static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w) 109930628cb1SMitsyanko Igor { 110030628cb1SMitsyanko Igor switch (w->wincon & FIMD_WINCON_BUFSTATUS) { 110130628cb1SMitsyanko Igor case FIMD_WINCON_BUF0_STAT: 110230628cb1SMitsyanko Igor return 0; 110330628cb1SMitsyanko Igor case FIMD_WINCON_BUF1_STAT: 110430628cb1SMitsyanko Igor return 1; 110530628cb1SMitsyanko Igor case FIMD_WINCON_BUF2_STAT: 110630628cb1SMitsyanko Igor return 2; 110730628cb1SMitsyanko Igor default: 110830628cb1SMitsyanko Igor DPRINT_ERROR("Non-existent buffer index\n"); 110930628cb1SMitsyanko Igor return 0; 111030628cb1SMitsyanko Igor } 111130628cb1SMitsyanko Igor } 111230628cb1SMitsyanko Igor 111374259ae5SPaolo Bonzini static void exynos4210_fimd_invalidate(void *opaque) 111474259ae5SPaolo Bonzini { 111574259ae5SPaolo Bonzini Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; 111674259ae5SPaolo Bonzini s->invalidate = true; 111774259ae5SPaolo Bonzini } 111874259ae5SPaolo Bonzini 111930628cb1SMitsyanko Igor /* Updates specified window's MemorySection based on values of WINCON, 112030628cb1SMitsyanko Igor * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */ 112130628cb1SMitsyanko Igor static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) 112230628cb1SMitsyanko Igor { 1123f27321aaSAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 112430628cb1SMitsyanko Igor Exynos4210fimdWindow *w = &s->window[win]; 1125a8170e5eSAvi Kivity hwaddr fb_start_addr, fb_mapped_len; 112630628cb1SMitsyanko Igor 112730628cb1SMitsyanko Igor if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) || 112830628cb1SMitsyanko Igor FIMD_WINDOW_PROTECTED(s->shadowcon, win)) { 112930628cb1SMitsyanko Igor return; 113030628cb1SMitsyanko Igor } 113130628cb1SMitsyanko Igor 113230628cb1SMitsyanko Igor if (w->host_fb_addr) { 113330628cb1SMitsyanko Igor cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0); 113430628cb1SMitsyanko Igor w->host_fb_addr = NULL; 113530628cb1SMitsyanko Igor w->fb_len = 0; 113630628cb1SMitsyanko Igor } 113730628cb1SMitsyanko Igor 113830628cb1SMitsyanko Igor fb_start_addr = w->buf_start[fimd_get_buffer_id(w)]; 113930628cb1SMitsyanko Igor /* Total number of bytes of virtual screen used by current window */ 114030628cb1SMitsyanko Igor w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) * 114130628cb1SMitsyanko Igor (w->rightbot_y - w->lefttop_y + 1); 1142dfde4e6eSPaolo Bonzini 1143dfde4e6eSPaolo Bonzini /* TODO: add .exit and unref the region there. Not needed yet since sysbus 1144dfde4e6eSPaolo Bonzini * does not support hot-unplug. 1145dfde4e6eSPaolo Bonzini */ 114674259ae5SPaolo Bonzini if (w->mem_section.mr) { 114774259ae5SPaolo Bonzini memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA); 1148dfde4e6eSPaolo Bonzini memory_region_unref(w->mem_section.mr); 114974259ae5SPaolo Bonzini } 115074259ae5SPaolo Bonzini 1151f27321aaSAndreas Färber w->mem_section = memory_region_find(sysbus_address_space(sbd), 115230628cb1SMitsyanko Igor fb_start_addr, w->fb_len); 115330628cb1SMitsyanko Igor assert(w->mem_section.mr); 115430628cb1SMitsyanko Igor assert(w->mem_section.offset_within_address_space == fb_start_addr); 115530628cb1SMitsyanko Igor DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n", 115630628cb1SMitsyanko Igor win, fb_start_addr, w->fb_len); 115730628cb1SMitsyanko Igor 1158052e87b0SPaolo Bonzini if (int128_get64(w->mem_section.size) != w->fb_len || 115930628cb1SMitsyanko Igor !memory_region_is_ram(w->mem_section.mr)) { 116030628cb1SMitsyanko Igor DPRINT_ERROR("Failed to find window %u framebuffer region\n", win); 116130628cb1SMitsyanko Igor goto error_return; 116230628cb1SMitsyanko Igor } 116330628cb1SMitsyanko Igor 116430628cb1SMitsyanko Igor w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0); 116530628cb1SMitsyanko Igor if (!w->host_fb_addr) { 116630628cb1SMitsyanko Igor DPRINT_ERROR("Failed to map window %u framebuffer\n", win); 116730628cb1SMitsyanko Igor goto error_return; 116830628cb1SMitsyanko Igor } 116930628cb1SMitsyanko Igor 117030628cb1SMitsyanko Igor if (fb_mapped_len != w->fb_len) { 117130628cb1SMitsyanko Igor DPRINT_ERROR("Window %u mapped framebuffer length is less then " 117230628cb1SMitsyanko Igor "expected\n", win); 117330628cb1SMitsyanko Igor cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0); 117430628cb1SMitsyanko Igor goto error_return; 117530628cb1SMitsyanko Igor } 117674259ae5SPaolo Bonzini memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA); 117774259ae5SPaolo Bonzini exynos4210_fimd_invalidate(s); 117830628cb1SMitsyanko Igor return; 117930628cb1SMitsyanko Igor 118030628cb1SMitsyanko Igor error_return: 1181dfde4e6eSPaolo Bonzini memory_region_unref(w->mem_section.mr); 118230628cb1SMitsyanko Igor w->mem_section.mr = NULL; 1183052e87b0SPaolo Bonzini w->mem_section.size = int128_zero(); 118430628cb1SMitsyanko Igor w->host_fb_addr = NULL; 118530628cb1SMitsyanko Igor w->fb_len = 0; 118630628cb1SMitsyanko Igor } 118730628cb1SMitsyanko Igor 118830628cb1SMitsyanko Igor static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled) 118930628cb1SMitsyanko Igor { 119030628cb1SMitsyanko Igor if (enabled && !s->enabled) { 119130628cb1SMitsyanko Igor unsigned w; 119230628cb1SMitsyanko Igor s->enabled = true; 119330628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 119430628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 119530628cb1SMitsyanko Igor } 119630628cb1SMitsyanko Igor } 119730628cb1SMitsyanko Igor s->enabled = enabled; 119830628cb1SMitsyanko Igor DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled"); 119930628cb1SMitsyanko Igor } 120030628cb1SMitsyanko Igor 120130628cb1SMitsyanko Igor static inline uint32_t unpack_upper_4(uint32_t x) 120230628cb1SMitsyanko Igor { 120330628cb1SMitsyanko Igor return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4); 120430628cb1SMitsyanko Igor } 120530628cb1SMitsyanko Igor 120630628cb1SMitsyanko Igor static inline uint32_t pack_upper_4(uint32_t x) 120730628cb1SMitsyanko Igor { 120830628cb1SMitsyanko Igor return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) | 120930628cb1SMitsyanko Igor ((x & 0xF0) >> 4)) & 0xFFF; 121030628cb1SMitsyanko Igor } 121130628cb1SMitsyanko Igor 121230628cb1SMitsyanko Igor static void exynos4210_fimd_update_irq(Exynos4210fimdState *s) 121330628cb1SMitsyanko Igor { 121430628cb1SMitsyanko Igor if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) { 121530628cb1SMitsyanko Igor qemu_irq_lower(s->irq[0]); 121630628cb1SMitsyanko Igor qemu_irq_lower(s->irq[1]); 121730628cb1SMitsyanko Igor qemu_irq_lower(s->irq[2]); 121830628cb1SMitsyanko Igor return; 121930628cb1SMitsyanko Igor } 122030628cb1SMitsyanko Igor if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) && 122130628cb1SMitsyanko Igor (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) { 122230628cb1SMitsyanko Igor qemu_irq_raise(s->irq[0]); 122330628cb1SMitsyanko Igor } else { 122430628cb1SMitsyanko Igor qemu_irq_lower(s->irq[0]); 122530628cb1SMitsyanko Igor } 122630628cb1SMitsyanko Igor if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) && 122730628cb1SMitsyanko Igor (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) { 122830628cb1SMitsyanko Igor qemu_irq_raise(s->irq[1]); 122930628cb1SMitsyanko Igor } else { 123030628cb1SMitsyanko Igor qemu_irq_lower(s->irq[1]); 123130628cb1SMitsyanko Igor } 123230628cb1SMitsyanko Igor if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) && 123330628cb1SMitsyanko Igor (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) { 123430628cb1SMitsyanko Igor qemu_irq_raise(s->irq[2]); 123530628cb1SMitsyanko Igor } else { 123630628cb1SMitsyanko Igor qemu_irq_lower(s->irq[2]); 123730628cb1SMitsyanko Igor } 123830628cb1SMitsyanko Igor } 123930628cb1SMitsyanko Igor 124030628cb1SMitsyanko Igor static void exynos4210_update_resolution(Exynos4210fimdState *s) 124130628cb1SMitsyanko Igor { 1242c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(s->console); 1243c78f7137SGerd Hoffmann 124430628cb1SMitsyanko Igor /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */ 124530628cb1SMitsyanko Igor uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) & 124630628cb1SMitsyanko Igor FIMD_VIDTCON2_SIZE_MASK) + 1; 124730628cb1SMitsyanko Igor uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & 124830628cb1SMitsyanko Igor FIMD_VIDTCON2_SIZE_MASK) + 1; 124930628cb1SMitsyanko Igor 1250c78f7137SGerd Hoffmann if (s->ifb == NULL || surface_width(surface) != width || 1251c78f7137SGerd Hoffmann surface_height(surface) != height) { 125230628cb1SMitsyanko Igor DPRINT_L1("Resolution changed from %ux%u to %ux%u\n", 1253c78f7137SGerd Hoffmann surface_width(surface), surface_height(surface), width, height); 125430628cb1SMitsyanko Igor qemu_console_resize(s->console, width, height); 125530628cb1SMitsyanko Igor s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1); 125630628cb1SMitsyanko Igor memset(s->ifb, 0, width * height * RGBA_SIZE + 1); 125730628cb1SMitsyanko Igor exynos4210_fimd_invalidate(s); 125830628cb1SMitsyanko Igor } 125930628cb1SMitsyanko Igor } 126030628cb1SMitsyanko Igor 126130628cb1SMitsyanko Igor static void exynos4210_fimd_update(void *opaque) 126230628cb1SMitsyanko Igor { 126330628cb1SMitsyanko Igor Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; 1264522fccbeSIgor Mitsyanko DisplaySurface *surface; 126530628cb1SMitsyanko Igor Exynos4210fimdWindow *w; 1266*553bcce5SGerd Hoffmann DirtyBitmapSnapshot *snap; 126730628cb1SMitsyanko Igor int i, line; 1268a8170e5eSAvi Kivity hwaddr fb_line_addr, inc_size; 126930628cb1SMitsyanko Igor int scrn_height; 127030628cb1SMitsyanko Igor int first_line = -1, last_line = -1, scrn_width; 127130628cb1SMitsyanko Igor bool blend = false; 127230628cb1SMitsyanko Igor uint8_t *host_fb_addr; 127330628cb1SMitsyanko Igor bool is_dirty = false; 127430628cb1SMitsyanko Igor const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1; 127530628cb1SMitsyanko Igor const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & 127630628cb1SMitsyanko Igor FIMD_VIDTCON2_SIZE_MASK) + 1; 127730628cb1SMitsyanko Igor 1278522fccbeSIgor Mitsyanko if (!s || !s->console || !s->enabled || 1279522fccbeSIgor Mitsyanko surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) { 128030628cb1SMitsyanko Igor return; 128130628cb1SMitsyanko Igor } 128230628cb1SMitsyanko Igor exynos4210_update_resolution(s); 1283522fccbeSIgor Mitsyanko surface = qemu_console_surface(s->console); 128430628cb1SMitsyanko Igor 128530628cb1SMitsyanko Igor for (i = 0; i < NUM_OF_WINDOWS; i++) { 128630628cb1SMitsyanko Igor w = &s->window[i]; 128730628cb1SMitsyanko Igor if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) { 128830628cb1SMitsyanko Igor scrn_height = w->rightbot_y - w->lefttop_y + 1; 128930628cb1SMitsyanko Igor scrn_width = w->virtpage_width; 129030628cb1SMitsyanko Igor /* Total width of virtual screen page in bytes */ 129130628cb1SMitsyanko Igor inc_size = scrn_width + w->virtpage_offsize; 129230628cb1SMitsyanko Igor memory_region_sync_dirty_bitmap(w->mem_section.mr); 129330628cb1SMitsyanko Igor host_fb_addr = w->host_fb_addr; 129430628cb1SMitsyanko Igor fb_line_addr = w->mem_section.offset_within_region; 1295*553bcce5SGerd Hoffmann snap = memory_region_snapshot_and_clear_dirty(w->mem_section.mr, 1296*553bcce5SGerd Hoffmann fb_line_addr, inc_size * scrn_height, DIRTY_MEMORY_VGA); 129730628cb1SMitsyanko Igor 129830628cb1SMitsyanko Igor for (line = 0; line < scrn_height; line++) { 1299*553bcce5SGerd Hoffmann is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr, 1300*553bcce5SGerd Hoffmann snap, fb_line_addr, scrn_width); 130130628cb1SMitsyanko Igor 130230628cb1SMitsyanko Igor if (s->invalidate || is_dirty) { 130330628cb1SMitsyanko Igor if (first_line == -1) { 130430628cb1SMitsyanko Igor first_line = line; 130530628cb1SMitsyanko Igor } 130630628cb1SMitsyanko Igor last_line = line; 130730628cb1SMitsyanko Igor w->draw_line(w, host_fb_addr, s->ifb + 130830628cb1SMitsyanko Igor w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) * 130930628cb1SMitsyanko Igor global_width * RGBA_SIZE, blend); 131030628cb1SMitsyanko Igor } 131130628cb1SMitsyanko Igor host_fb_addr += inc_size; 131230628cb1SMitsyanko Igor fb_line_addr += inc_size; 131330628cb1SMitsyanko Igor is_dirty = false; 131430628cb1SMitsyanko Igor } 1315*553bcce5SGerd Hoffmann g_free(snap); 131630628cb1SMitsyanko Igor blend = true; 131730628cb1SMitsyanko Igor } 131830628cb1SMitsyanko Igor } 131930628cb1SMitsyanko Igor 132030628cb1SMitsyanko Igor /* Copy resulting image to QEMU_CONSOLE. */ 132130628cb1SMitsyanko Igor if (first_line >= 0) { 132230628cb1SMitsyanko Igor uint8_t *d; 132330628cb1SMitsyanko Igor int bpp; 132430628cb1SMitsyanko Igor 1325c78f7137SGerd Hoffmann bpp = surface_bits_per_pixel(surface); 132630628cb1SMitsyanko Igor fimd_update_putpix_qemu(bpp); 132730628cb1SMitsyanko Igor bpp = (bpp + 1) >> 3; 1328c78f7137SGerd Hoffmann d = surface_data(surface); 132930628cb1SMitsyanko Igor for (line = first_line; line <= last_line; line++) { 133030628cb1SMitsyanko Igor fimd_copy_line_toqemu(global_width, s->ifb + global_width * line * 133130628cb1SMitsyanko Igor RGBA_SIZE, d + global_width * line * bpp); 133230628cb1SMitsyanko Igor } 1333a93a4a22SGerd Hoffmann dpy_gfx_update(s->console, 0, 0, global_width, global_height); 133430628cb1SMitsyanko Igor } 133530628cb1SMitsyanko Igor s->invalidate = false; 133630628cb1SMitsyanko Igor s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND; 133730628cb1SMitsyanko Igor if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) { 133830628cb1SMitsyanko Igor exynos4210_fimd_enable(s, false); 133930628cb1SMitsyanko Igor } 134030628cb1SMitsyanko Igor exynos4210_fimd_update_irq(s); 134130628cb1SMitsyanko Igor } 134230628cb1SMitsyanko Igor 134330628cb1SMitsyanko Igor static void exynos4210_fimd_reset(DeviceState *d) 134430628cb1SMitsyanko Igor { 1345f27321aaSAndreas Färber Exynos4210fimdState *s = EXYNOS4210_FIMD(d); 134630628cb1SMitsyanko Igor unsigned w; 134730628cb1SMitsyanko Igor 134830628cb1SMitsyanko Igor DPRINT_TRACE("Display controller reset\n"); 134930628cb1SMitsyanko Igor /* Set all display controller registers to 0 */ 135030628cb1SMitsyanko Igor memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon); 135130628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 135230628cb1SMitsyanko Igor memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow)); 135330628cb1SMitsyanko Igor s->window[w].blendeq = 0xC2; 135430628cb1SMitsyanko Igor exynos4210_fimd_update_win_bppmode(s, w); 135530628cb1SMitsyanko Igor exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF); 135630628cb1SMitsyanko Igor fimd_update_get_alpha(s, w); 135730628cb1SMitsyanko Igor } 135830628cb1SMitsyanko Igor 135930628cb1SMitsyanko Igor g_free(s->ifb); 136030628cb1SMitsyanko Igor s->ifb = NULL; 136130628cb1SMitsyanko Igor 136230628cb1SMitsyanko Igor exynos4210_fimd_invalidate(s); 136330628cb1SMitsyanko Igor exynos4210_fimd_enable(s, false); 136430628cb1SMitsyanko Igor /* Some registers have non-zero initial values */ 136530628cb1SMitsyanko Igor s->winchmap = 0x7D517D51; 136630628cb1SMitsyanko Igor s->colorgaincon = 0x10040100; 136730628cb1SMitsyanko Igor s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100; 136830628cb1SMitsyanko Igor s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100; 136930628cb1SMitsyanko Igor s->hueoffset = 0x01800080; 137030628cb1SMitsyanko Igor } 137130628cb1SMitsyanko Igor 1372a8170e5eSAvi Kivity static void exynos4210_fimd_write(void *opaque, hwaddr offset, 137330628cb1SMitsyanko Igor uint64_t val, unsigned size) 137430628cb1SMitsyanko Igor { 137530628cb1SMitsyanko Igor Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; 137630628cb1SMitsyanko Igor unsigned w, i; 137730628cb1SMitsyanko Igor uint32_t old_value; 137830628cb1SMitsyanko Igor 137930628cb1SMitsyanko Igor DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset, 138030628cb1SMitsyanko Igor (long long unsigned int)val, (long long unsigned int)val); 138130628cb1SMitsyanko Igor 138230628cb1SMitsyanko Igor switch (offset) { 138330628cb1SMitsyanko Igor case FIMD_VIDCON0: 138430628cb1SMitsyanko Igor if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) { 138530628cb1SMitsyanko Igor exynos4210_fimd_enable(s, true); 138630628cb1SMitsyanko Igor } else { 138730628cb1SMitsyanko Igor if ((val & FIMD_VIDCON0_ENVID) == 0) { 138830628cb1SMitsyanko Igor exynos4210_fimd_enable(s, false); 138930628cb1SMitsyanko Igor } 139030628cb1SMitsyanko Igor } 139130628cb1SMitsyanko Igor s->vidcon[0] = val; 139230628cb1SMitsyanko Igor break; 139330628cb1SMitsyanko Igor case FIMD_VIDCON1: 139430628cb1SMitsyanko Igor /* Leave read-only bits as is */ 139530628cb1SMitsyanko Igor val = (val & (~FIMD_VIDCON1_ROMASK)) | 139630628cb1SMitsyanko Igor (s->vidcon[1] & FIMD_VIDCON1_ROMASK); 139730628cb1SMitsyanko Igor s->vidcon[1] = val; 139830628cb1SMitsyanko Igor break; 139930628cb1SMitsyanko Igor case FIMD_VIDCON2 ... FIMD_VIDCON3: 140030628cb1SMitsyanko Igor s->vidcon[(offset) >> 2] = val; 140130628cb1SMitsyanko Igor break; 140230628cb1SMitsyanko Igor case FIMD_VIDTCON_START ... FIMD_VIDTCON_END: 140330628cb1SMitsyanko Igor s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val; 140430628cb1SMitsyanko Igor break; 140530628cb1SMitsyanko Igor case FIMD_WINCON_START ... FIMD_WINCON_END: 140630628cb1SMitsyanko Igor w = (offset - FIMD_WINCON_START) >> 2; 140730628cb1SMitsyanko Igor /* Window's current buffer ID */ 140830628cb1SMitsyanko Igor i = fimd_get_buffer_id(&s->window[w]); 140930628cb1SMitsyanko Igor old_value = s->window[w].wincon; 141030628cb1SMitsyanko Igor val = (val & ~FIMD_WINCON_ROMASK) | 141130628cb1SMitsyanko Igor (s->window[w].wincon & FIMD_WINCON_ROMASK); 141230628cb1SMitsyanko Igor if (w == 0) { 141330628cb1SMitsyanko Igor /* Window 0 wincon ALPHA_MUL bit must always be 0 */ 141430628cb1SMitsyanko Igor val &= ~FIMD_WINCON_ALPHA_MUL; 141530628cb1SMitsyanko Igor } 141630628cb1SMitsyanko Igor exynos4210_fimd_trace_bppmode(s, w, val); 141730628cb1SMitsyanko Igor switch (val & FIMD_WINCON_BUFSELECT) { 141830628cb1SMitsyanko Igor case FIMD_WINCON_BUF0_SEL: 141930628cb1SMitsyanko Igor val &= ~FIMD_WINCON_BUFSTATUS; 142030628cb1SMitsyanko Igor break; 142130628cb1SMitsyanko Igor case FIMD_WINCON_BUF1_SEL: 142230628cb1SMitsyanko Igor val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L; 142330628cb1SMitsyanko Igor break; 142430628cb1SMitsyanko Igor case FIMD_WINCON_BUF2_SEL: 142530628cb1SMitsyanko Igor if (val & FIMD_WINCON_BUFMODE) { 142630628cb1SMitsyanko Igor val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H; 142730628cb1SMitsyanko Igor } 142830628cb1SMitsyanko Igor break; 142930628cb1SMitsyanko Igor default: 143030628cb1SMitsyanko Igor break; 143130628cb1SMitsyanko Igor } 143230628cb1SMitsyanko Igor s->window[w].wincon = val; 143330628cb1SMitsyanko Igor exynos4210_fimd_update_win_bppmode(s, w); 143430628cb1SMitsyanko Igor fimd_update_get_alpha(s, w); 143530628cb1SMitsyanko Igor if ((i != fimd_get_buffer_id(&s->window[w])) || 143630628cb1SMitsyanko Igor (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon & 143730628cb1SMitsyanko Igor FIMD_WINCON_ENWIN))) { 143830628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 143930628cb1SMitsyanko Igor } 144030628cb1SMitsyanko Igor break; 144130628cb1SMitsyanko Igor case FIMD_SHADOWCON: 144230628cb1SMitsyanko Igor old_value = s->shadowcon; 144330628cb1SMitsyanko Igor s->shadowcon = val; 144430628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 144530628cb1SMitsyanko Igor if (FIMD_WINDOW_PROTECTED(old_value, w) && 144630628cb1SMitsyanko Igor !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) { 144730628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 144830628cb1SMitsyanko Igor } 144930628cb1SMitsyanko Igor } 145030628cb1SMitsyanko Igor break; 145130628cb1SMitsyanko Igor case FIMD_WINCHMAP: 145230628cb1SMitsyanko Igor s->winchmap = val; 145330628cb1SMitsyanko Igor break; 145430628cb1SMitsyanko Igor case FIMD_VIDOSD_START ... FIMD_VIDOSD_END: 145530628cb1SMitsyanko Igor w = (offset - FIMD_VIDOSD_START) >> 4; 145630628cb1SMitsyanko Igor i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2; 145730628cb1SMitsyanko Igor switch (i) { 145830628cb1SMitsyanko Igor case 0: 145930628cb1SMitsyanko Igor old_value = s->window[w].lefttop_y; 146030628cb1SMitsyanko Igor s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) & 146130628cb1SMitsyanko Igor FIMD_VIDOSD_COORD_MASK; 146230628cb1SMitsyanko Igor s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) & 146330628cb1SMitsyanko Igor FIMD_VIDOSD_COORD_MASK; 146430628cb1SMitsyanko Igor if (s->window[w].lefttop_y != old_value) { 146530628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 146630628cb1SMitsyanko Igor } 146730628cb1SMitsyanko Igor break; 146830628cb1SMitsyanko Igor case 1: 146930628cb1SMitsyanko Igor old_value = s->window[w].rightbot_y; 147030628cb1SMitsyanko Igor s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) & 147130628cb1SMitsyanko Igor FIMD_VIDOSD_COORD_MASK; 147230628cb1SMitsyanko Igor s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) & 147330628cb1SMitsyanko Igor FIMD_VIDOSD_COORD_MASK; 147430628cb1SMitsyanko Igor if (s->window[w].rightbot_y != old_value) { 147530628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 147630628cb1SMitsyanko Igor } 147730628cb1SMitsyanko Igor break; 147830628cb1SMitsyanko Igor case 2: 147930628cb1SMitsyanko Igor if (w == 0) { 148030628cb1SMitsyanko Igor s->window[w].osdsize = val; 148130628cb1SMitsyanko Igor } else { 148230628cb1SMitsyanko Igor s->window[w].alpha_val[0] = 148330628cb1SMitsyanko Igor unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >> 148430628cb1SMitsyanko Igor FIMD_VIDOSD_AEN0_SHIFT) | 148530628cb1SMitsyanko Igor (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER); 148630628cb1SMitsyanko Igor s->window[w].alpha_val[1] = 148730628cb1SMitsyanko Igor unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) | 148830628cb1SMitsyanko Igor (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER); 148930628cb1SMitsyanko Igor } 149030628cb1SMitsyanko Igor break; 149130628cb1SMitsyanko Igor case 3: 149230628cb1SMitsyanko Igor if (w != 1 && w != 2) { 149330628cb1SMitsyanko Igor DPRINT_ERROR("Bad write offset 0x%08x\n", offset); 149430628cb1SMitsyanko Igor return; 149530628cb1SMitsyanko Igor } 149630628cb1SMitsyanko Igor s->window[w].osdsize = val; 149730628cb1SMitsyanko Igor break; 149830628cb1SMitsyanko Igor } 149930628cb1SMitsyanko Igor break; 150030628cb1SMitsyanko Igor case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END: 150130628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD0_START) >> 3; 150230628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1; 150330628cb1SMitsyanko Igor if (i == fimd_get_buffer_id(&s->window[w]) && 150430628cb1SMitsyanko Igor s->window[w].buf_start[i] != val) { 150530628cb1SMitsyanko Igor s->window[w].buf_start[i] = val; 150630628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 150730628cb1SMitsyanko Igor break; 150830628cb1SMitsyanko Igor } 150930628cb1SMitsyanko Igor s->window[w].buf_start[i] = val; 151030628cb1SMitsyanko Igor break; 151130628cb1SMitsyanko Igor case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END: 151230628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD1_START) >> 3; 151330628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1; 151430628cb1SMitsyanko Igor s->window[w].buf_end[i] = val; 151530628cb1SMitsyanko Igor break; 151630628cb1SMitsyanko Igor case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END: 151730628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD2_START) >> 2; 151830628cb1SMitsyanko Igor if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) || 151930628cb1SMitsyanko Igor (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) != 152030628cb1SMitsyanko Igor s->window[w].virtpage_offsize)) { 152130628cb1SMitsyanko Igor s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH; 152230628cb1SMitsyanko Igor s->window[w].virtpage_offsize = 152330628cb1SMitsyanko Igor (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE; 152430628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 152530628cb1SMitsyanko Igor } 152630628cb1SMitsyanko Igor break; 152730628cb1SMitsyanko Igor case FIMD_VIDINTCON0: 152830628cb1SMitsyanko Igor s->vidintcon[0] = val; 152930628cb1SMitsyanko Igor break; 153030628cb1SMitsyanko Igor case FIMD_VIDINTCON1: 153130628cb1SMitsyanko Igor s->vidintcon[1] &= ~(val & 7); 153230628cb1SMitsyanko Igor exynos4210_fimd_update_irq(s); 153330628cb1SMitsyanko Igor break; 153430628cb1SMitsyanko Igor case FIMD_WKEYCON_START ... FIMD_WKEYCON_END: 153530628cb1SMitsyanko Igor w = ((offset - FIMD_WKEYCON_START) >> 3) + 1; 153630628cb1SMitsyanko Igor i = ((offset - FIMD_WKEYCON_START) >> 2) & 1; 153730628cb1SMitsyanko Igor s->window[w].keycon[i] = val; 153830628cb1SMitsyanko Igor break; 153930628cb1SMitsyanko Igor case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END: 154030628cb1SMitsyanko Igor w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1; 154130628cb1SMitsyanko Igor s->window[w].keyalpha = val; 154230628cb1SMitsyanko Igor break; 154330628cb1SMitsyanko Igor case FIMD_DITHMODE: 154430628cb1SMitsyanko Igor s->dithmode = val; 154530628cb1SMitsyanko Igor break; 154630628cb1SMitsyanko Igor case FIMD_WINMAP_START ... FIMD_WINMAP_END: 154730628cb1SMitsyanko Igor w = (offset - FIMD_WINMAP_START) >> 2; 154830628cb1SMitsyanko Igor old_value = s->window[w].winmap; 154930628cb1SMitsyanko Igor s->window[w].winmap = val; 155030628cb1SMitsyanko Igor if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) { 155130628cb1SMitsyanko Igor exynos4210_fimd_invalidate(s); 155230628cb1SMitsyanko Igor exynos4210_fimd_update_win_bppmode(s, w); 155330628cb1SMitsyanko Igor exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF); 155430628cb1SMitsyanko Igor exynos4210_fimd_update(s); 155530628cb1SMitsyanko Igor } 155630628cb1SMitsyanko Igor break; 155730628cb1SMitsyanko Igor case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW: 155830628cb1SMitsyanko Igor i = (offset - FIMD_WPALCON_HIGH) >> 2; 155930628cb1SMitsyanko Igor s->wpalcon[i] = val; 156030628cb1SMitsyanko Igor if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) { 156130628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 156230628cb1SMitsyanko Igor exynos4210_fimd_update_win_bppmode(s, w); 156330628cb1SMitsyanko Igor fimd_update_get_alpha(s, w); 156430628cb1SMitsyanko Igor } 156530628cb1SMitsyanko Igor } 156630628cb1SMitsyanko Igor break; 156730628cb1SMitsyanko Igor case FIMD_TRIGCON: 156830628cb1SMitsyanko Igor val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK); 156930628cb1SMitsyanko Igor s->trigcon = val; 157030628cb1SMitsyanko Igor break; 157130628cb1SMitsyanko Igor case FIMD_I80IFCON_START ... FIMD_I80IFCON_END: 157230628cb1SMitsyanko Igor s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val; 157330628cb1SMitsyanko Igor break; 157430628cb1SMitsyanko Igor case FIMD_COLORGAINCON: 157530628cb1SMitsyanko Igor s->colorgaincon = val; 157630628cb1SMitsyanko Igor break; 157730628cb1SMitsyanko Igor case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1: 157830628cb1SMitsyanko Igor s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val; 157930628cb1SMitsyanko Igor break; 158030628cb1SMitsyanko Igor case FIMD_SIFCCON0 ... FIMD_SIFCCON2: 158130628cb1SMitsyanko Igor i = (offset - FIMD_SIFCCON0) >> 2; 158230628cb1SMitsyanko Igor if (i != 2) { 158330628cb1SMitsyanko Igor s->sifccon[i] = val; 158430628cb1SMitsyanko Igor } 158530628cb1SMitsyanko Igor break; 158630628cb1SMitsyanko Igor case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END: 158730628cb1SMitsyanko Igor i = (offset - FIMD_HUECOEFCR_START) >> 2; 158830628cb1SMitsyanko Igor s->huecoef_cr[i] = val; 158930628cb1SMitsyanko Igor break; 159030628cb1SMitsyanko Igor case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END: 159130628cb1SMitsyanko Igor i = (offset - FIMD_HUECOEFCB_START) >> 2; 159230628cb1SMitsyanko Igor s->huecoef_cb[i] = val; 159330628cb1SMitsyanko Igor break; 159430628cb1SMitsyanko Igor case FIMD_HUEOFFSET: 159530628cb1SMitsyanko Igor s->hueoffset = val; 159630628cb1SMitsyanko Igor break; 159730628cb1SMitsyanko Igor case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END: 159830628cb1SMitsyanko Igor w = ((offset - FIMD_VIDWALPHA_START) >> 3); 159930628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1; 160030628cb1SMitsyanko Igor if (w == 0) { 160130628cb1SMitsyanko Igor s->window[w].alpha_val[i] = val; 160230628cb1SMitsyanko Igor } else { 160330628cb1SMitsyanko Igor s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) | 160430628cb1SMitsyanko Igor (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER); 160530628cb1SMitsyanko Igor } 160630628cb1SMitsyanko Igor break; 160730628cb1SMitsyanko Igor case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END: 160830628cb1SMitsyanko Igor s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val; 160930628cb1SMitsyanko Igor break; 161030628cb1SMitsyanko Igor case FIMD_BLENDCON: 161130628cb1SMitsyanko Igor old_value = s->blendcon; 161230628cb1SMitsyanko Igor s->blendcon = val; 161330628cb1SMitsyanko Igor if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) { 161430628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 161530628cb1SMitsyanko Igor fimd_update_get_alpha(s, w); 161630628cb1SMitsyanko Igor } 161730628cb1SMitsyanko Igor } 161830628cb1SMitsyanko Igor break; 161930628cb1SMitsyanko Igor case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END: 162030628cb1SMitsyanko Igor s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val; 162130628cb1SMitsyanko Igor break; 162230628cb1SMitsyanko Igor case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END: 162330628cb1SMitsyanko Igor s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val; 162430628cb1SMitsyanko Igor break; 162530628cb1SMitsyanko Igor case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2: 162630628cb1SMitsyanko Igor if (offset & 0x0004) { 162730628cb1SMitsyanko Igor DPRINT_ERROR("bad write offset 0x%08x\n", offset); 162830628cb1SMitsyanko Igor break; 162930628cb1SMitsyanko Igor } 163030628cb1SMitsyanko Igor w = (offset - FIMD_VIDW0ADD0_B2) >> 3; 163130628cb1SMitsyanko Igor if (fimd_get_buffer_id(&s->window[w]) == 2 && 163230628cb1SMitsyanko Igor s->window[w].buf_start[2] != val) { 163330628cb1SMitsyanko Igor s->window[w].buf_start[2] = val; 163430628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 163530628cb1SMitsyanko Igor break; 163630628cb1SMitsyanko Igor } 163730628cb1SMitsyanko Igor s->window[w].buf_start[2] = val; 163830628cb1SMitsyanko Igor break; 163930628cb1SMitsyanko Igor case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END: 164030628cb1SMitsyanko Igor if (offset & 0x0004) { 164130628cb1SMitsyanko Igor DPRINT_ERROR("bad write offset 0x%08x\n", offset); 164230628cb1SMitsyanko Igor break; 164330628cb1SMitsyanko Igor } 164430628cb1SMitsyanko Igor s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val; 164530628cb1SMitsyanko Igor break; 164630628cb1SMitsyanko Igor case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END: 164730628cb1SMitsyanko Igor if (offset & 0x0004) { 164830628cb1SMitsyanko Igor DPRINT_ERROR("bad write offset 0x%08x\n", offset); 164930628cb1SMitsyanko Igor break; 165030628cb1SMitsyanko Igor } 165130628cb1SMitsyanko Igor s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val; 165230628cb1SMitsyanko Igor break; 165330628cb1SMitsyanko Igor case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END: 165430628cb1SMitsyanko Igor s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val; 165530628cb1SMitsyanko Igor break; 165630628cb1SMitsyanko Igor case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END: 165730628cb1SMitsyanko Igor w = (offset - FIMD_PAL_MEM_START) >> 10; 165830628cb1SMitsyanko Igor i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF; 165930628cb1SMitsyanko Igor s->window[w].palette[i] = val; 166030628cb1SMitsyanko Igor break; 166130628cb1SMitsyanko Igor case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END: 166230628cb1SMitsyanko Igor /* Palette memory aliases for windows 0 and 1 */ 166330628cb1SMitsyanko Igor w = (offset - FIMD_PALMEM_AL_START) >> 10; 166430628cb1SMitsyanko Igor i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF; 166530628cb1SMitsyanko Igor s->window[w].palette[i] = val; 166630628cb1SMitsyanko Igor break; 166730628cb1SMitsyanko Igor default: 166830628cb1SMitsyanko Igor DPRINT_ERROR("bad write offset 0x%08x\n", offset); 166930628cb1SMitsyanko Igor break; 167030628cb1SMitsyanko Igor } 167130628cb1SMitsyanko Igor } 167230628cb1SMitsyanko Igor 1673a8170e5eSAvi Kivity static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset, 167430628cb1SMitsyanko Igor unsigned size) 167530628cb1SMitsyanko Igor { 167630628cb1SMitsyanko Igor Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; 167730628cb1SMitsyanko Igor int w, i; 167830628cb1SMitsyanko Igor uint32_t ret = 0; 167930628cb1SMitsyanko Igor 168030628cb1SMitsyanko Igor DPRINT_L2("read offset 0x%08x\n", offset); 168130628cb1SMitsyanko Igor 168230628cb1SMitsyanko Igor switch (offset) { 168330628cb1SMitsyanko Igor case FIMD_VIDCON0 ... FIMD_VIDCON3: 168430628cb1SMitsyanko Igor return s->vidcon[(offset - FIMD_VIDCON0) >> 2]; 168530628cb1SMitsyanko Igor case FIMD_VIDTCON_START ... FIMD_VIDTCON_END: 168630628cb1SMitsyanko Igor return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2]; 168730628cb1SMitsyanko Igor case FIMD_WINCON_START ... FIMD_WINCON_END: 168830628cb1SMitsyanko Igor return s->window[(offset - FIMD_WINCON_START) >> 2].wincon; 168930628cb1SMitsyanko Igor case FIMD_SHADOWCON: 169030628cb1SMitsyanko Igor return s->shadowcon; 169130628cb1SMitsyanko Igor case FIMD_WINCHMAP: 169230628cb1SMitsyanko Igor return s->winchmap; 169330628cb1SMitsyanko Igor case FIMD_VIDOSD_START ... FIMD_VIDOSD_END: 169430628cb1SMitsyanko Igor w = (offset - FIMD_VIDOSD_START) >> 4; 169530628cb1SMitsyanko Igor i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2; 169630628cb1SMitsyanko Igor switch (i) { 169730628cb1SMitsyanko Igor case 0: 169830628cb1SMitsyanko Igor ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) << 169930628cb1SMitsyanko Igor FIMD_VIDOSD_HOR_SHIFT) | 170030628cb1SMitsyanko Igor (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK); 170130628cb1SMitsyanko Igor break; 170230628cb1SMitsyanko Igor case 1: 170330628cb1SMitsyanko Igor ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) << 170430628cb1SMitsyanko Igor FIMD_VIDOSD_HOR_SHIFT) | 170530628cb1SMitsyanko Igor (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK); 170630628cb1SMitsyanko Igor break; 170730628cb1SMitsyanko Igor case 2: 170830628cb1SMitsyanko Igor if (w == 0) { 170930628cb1SMitsyanko Igor ret = s->window[w].osdsize; 171030628cb1SMitsyanko Igor } else { 171130628cb1SMitsyanko Igor ret = (pack_upper_4(s->window[w].alpha_val[0]) << 171230628cb1SMitsyanko Igor FIMD_VIDOSD_AEN0_SHIFT) | 171330628cb1SMitsyanko Igor pack_upper_4(s->window[w].alpha_val[1]); 171430628cb1SMitsyanko Igor } 171530628cb1SMitsyanko Igor break; 171630628cb1SMitsyanko Igor case 3: 171730628cb1SMitsyanko Igor if (w != 1 && w != 2) { 171830628cb1SMitsyanko Igor DPRINT_ERROR("bad read offset 0x%08x\n", offset); 171930628cb1SMitsyanko Igor return 0xBAADBAAD; 172030628cb1SMitsyanko Igor } 172130628cb1SMitsyanko Igor ret = s->window[w].osdsize; 172230628cb1SMitsyanko Igor break; 172330628cb1SMitsyanko Igor } 172430628cb1SMitsyanko Igor return ret; 172530628cb1SMitsyanko Igor case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END: 172630628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD0_START) >> 3; 172730628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1; 172830628cb1SMitsyanko Igor return s->window[w].buf_start[i]; 172930628cb1SMitsyanko Igor case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END: 173030628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD1_START) >> 3; 173130628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1; 173230628cb1SMitsyanko Igor return s->window[w].buf_end[i]; 173330628cb1SMitsyanko Igor case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END: 173430628cb1SMitsyanko Igor w = (offset - FIMD_VIDWADD2_START) >> 2; 173530628cb1SMitsyanko Igor return s->window[w].virtpage_width | (s->window[w].virtpage_offsize << 173630628cb1SMitsyanko Igor FIMD_VIDWADD2_OFFSIZE_SHIFT); 173730628cb1SMitsyanko Igor case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1: 173830628cb1SMitsyanko Igor return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2]; 173930628cb1SMitsyanko Igor case FIMD_WKEYCON_START ... FIMD_WKEYCON_END: 174030628cb1SMitsyanko Igor w = ((offset - FIMD_WKEYCON_START) >> 3) + 1; 174130628cb1SMitsyanko Igor i = ((offset - FIMD_WKEYCON_START) >> 2) & 1; 174230628cb1SMitsyanko Igor return s->window[w].keycon[i]; 174330628cb1SMitsyanko Igor case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END: 174430628cb1SMitsyanko Igor w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1; 174530628cb1SMitsyanko Igor return s->window[w].keyalpha; 174630628cb1SMitsyanko Igor case FIMD_DITHMODE: 174730628cb1SMitsyanko Igor return s->dithmode; 174830628cb1SMitsyanko Igor case FIMD_WINMAP_START ... FIMD_WINMAP_END: 174930628cb1SMitsyanko Igor return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap; 175030628cb1SMitsyanko Igor case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW: 175130628cb1SMitsyanko Igor return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2]; 175230628cb1SMitsyanko Igor case FIMD_TRIGCON: 175330628cb1SMitsyanko Igor return s->trigcon; 175430628cb1SMitsyanko Igor case FIMD_I80IFCON_START ... FIMD_I80IFCON_END: 175530628cb1SMitsyanko Igor return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2]; 175630628cb1SMitsyanko Igor case FIMD_COLORGAINCON: 175730628cb1SMitsyanko Igor return s->colorgaincon; 175830628cb1SMitsyanko Igor case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1: 175930628cb1SMitsyanko Igor return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2]; 176030628cb1SMitsyanko Igor case FIMD_SIFCCON0 ... FIMD_SIFCCON2: 176130628cb1SMitsyanko Igor i = (offset - FIMD_SIFCCON0) >> 2; 176230628cb1SMitsyanko Igor return s->sifccon[i]; 176330628cb1SMitsyanko Igor case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END: 176430628cb1SMitsyanko Igor i = (offset - FIMD_HUECOEFCR_START) >> 2; 176530628cb1SMitsyanko Igor return s->huecoef_cr[i]; 176630628cb1SMitsyanko Igor case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END: 176730628cb1SMitsyanko Igor i = (offset - FIMD_HUECOEFCB_START) >> 2; 176830628cb1SMitsyanko Igor return s->huecoef_cb[i]; 176930628cb1SMitsyanko Igor case FIMD_HUEOFFSET: 177030628cb1SMitsyanko Igor return s->hueoffset; 177130628cb1SMitsyanko Igor case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END: 177230628cb1SMitsyanko Igor w = ((offset - FIMD_VIDWALPHA_START) >> 3); 177330628cb1SMitsyanko Igor i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1; 177430628cb1SMitsyanko Igor return s->window[w].alpha_val[i] & 177530628cb1SMitsyanko Igor (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER); 177630628cb1SMitsyanko Igor case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END: 177730628cb1SMitsyanko Igor return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq; 177830628cb1SMitsyanko Igor case FIMD_BLENDCON: 177930628cb1SMitsyanko Igor return s->blendcon; 178030628cb1SMitsyanko Igor case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END: 178130628cb1SMitsyanko Igor return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon; 178230628cb1SMitsyanko Igor case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END: 178330628cb1SMitsyanko Igor return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2]; 178430628cb1SMitsyanko Igor case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2: 178530628cb1SMitsyanko Igor if (offset & 0x0004) { 178630628cb1SMitsyanko Igor break; 178730628cb1SMitsyanko Igor } 178830628cb1SMitsyanko Igor return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2]; 178930628cb1SMitsyanko Igor case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END: 179030628cb1SMitsyanko Igor if (offset & 0x0004) { 179130628cb1SMitsyanko Igor break; 179230628cb1SMitsyanko Igor } 179330628cb1SMitsyanko Igor return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start; 179430628cb1SMitsyanko Igor case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END: 179530628cb1SMitsyanko Igor if (offset & 0x0004) { 179630628cb1SMitsyanko Igor break; 179730628cb1SMitsyanko Igor } 179830628cb1SMitsyanko Igor return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end; 179930628cb1SMitsyanko Igor case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END: 180030628cb1SMitsyanko Igor return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size; 180130628cb1SMitsyanko Igor case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END: 180230628cb1SMitsyanko Igor w = (offset - FIMD_PAL_MEM_START) >> 10; 180330628cb1SMitsyanko Igor i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF; 180430628cb1SMitsyanko Igor return s->window[w].palette[i]; 180530628cb1SMitsyanko Igor case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END: 180630628cb1SMitsyanko Igor /* Palette aliases for win 0,1 */ 180730628cb1SMitsyanko Igor w = (offset - FIMD_PALMEM_AL_START) >> 10; 180830628cb1SMitsyanko Igor i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF; 180930628cb1SMitsyanko Igor return s->window[w].palette[i]; 181030628cb1SMitsyanko Igor } 181130628cb1SMitsyanko Igor 181230628cb1SMitsyanko Igor DPRINT_ERROR("bad read offset 0x%08x\n", offset); 181330628cb1SMitsyanko Igor return 0xBAADBAAD; 181430628cb1SMitsyanko Igor } 181530628cb1SMitsyanko Igor 181630628cb1SMitsyanko Igor static const MemoryRegionOps exynos4210_fimd_mmio_ops = { 181730628cb1SMitsyanko Igor .read = exynos4210_fimd_read, 181830628cb1SMitsyanko Igor .write = exynos4210_fimd_write, 181930628cb1SMitsyanko Igor .valid = { 182030628cb1SMitsyanko Igor .min_access_size = 4, 182130628cb1SMitsyanko Igor .max_access_size = 4, 182230628cb1SMitsyanko Igor .unaligned = false 182330628cb1SMitsyanko Igor }, 182430628cb1SMitsyanko Igor .endianness = DEVICE_NATIVE_ENDIAN, 182530628cb1SMitsyanko Igor }; 182630628cb1SMitsyanko Igor 182730628cb1SMitsyanko Igor static int exynos4210_fimd_load(void *opaque, int version_id) 182830628cb1SMitsyanko Igor { 182930628cb1SMitsyanko Igor Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; 183030628cb1SMitsyanko Igor int w; 183130628cb1SMitsyanko Igor 183230628cb1SMitsyanko Igor if (version_id != 1) { 183330628cb1SMitsyanko Igor return -EINVAL; 183430628cb1SMitsyanko Igor } 183530628cb1SMitsyanko Igor 183630628cb1SMitsyanko Igor for (w = 0; w < NUM_OF_WINDOWS; w++) { 183730628cb1SMitsyanko Igor exynos4210_fimd_update_win_bppmode(s, w); 183830628cb1SMitsyanko Igor fimd_update_get_alpha(s, w); 183930628cb1SMitsyanko Igor fimd_update_memory_section(s, w); 184030628cb1SMitsyanko Igor } 184130628cb1SMitsyanko Igor 184230628cb1SMitsyanko Igor /* Redraw the whole screen */ 184330628cb1SMitsyanko Igor exynos4210_update_resolution(s); 184430628cb1SMitsyanko Igor exynos4210_fimd_invalidate(s); 184530628cb1SMitsyanko Igor exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) == 184630628cb1SMitsyanko Igor FIMD_VIDCON0_ENVID_MASK); 184730628cb1SMitsyanko Igor return 0; 184830628cb1SMitsyanko Igor } 184930628cb1SMitsyanko Igor 185030628cb1SMitsyanko Igor static const VMStateDescription exynos4210_fimd_window_vmstate = { 185130628cb1SMitsyanko Igor .name = "exynos4210.fimd_window", 185230628cb1SMitsyanko Igor .version_id = 1, 185330628cb1SMitsyanko Igor .minimum_version_id = 1, 185430628cb1SMitsyanko Igor .fields = (VMStateField[]) { 185530628cb1SMitsyanko Igor VMSTATE_UINT32(wincon, Exynos4210fimdWindow), 185630628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3), 185730628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3), 185830628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2), 185930628cb1SMitsyanko Igor VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow), 186030628cb1SMitsyanko Igor VMSTATE_UINT32(winmap, Exynos4210fimdWindow), 186130628cb1SMitsyanko Igor VMSTATE_UINT32(blendeq, Exynos4210fimdWindow), 186230628cb1SMitsyanko Igor VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow), 186330628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256), 186430628cb1SMitsyanko Igor VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow), 186530628cb1SMitsyanko Igor VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow), 186630628cb1SMitsyanko Igor VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow), 186730628cb1SMitsyanko Igor VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow), 186830628cb1SMitsyanko Igor VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow), 186930628cb1SMitsyanko Igor VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow), 187030628cb1SMitsyanko Igor VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow), 187130628cb1SMitsyanko Igor VMSTATE_UINT32(osdsize, Exynos4210fimdWindow), 187230628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2), 187330628cb1SMitsyanko Igor VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow), 187430628cb1SMitsyanko Igor VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow), 187530628cb1SMitsyanko Igor VMSTATE_END_OF_LIST() 187630628cb1SMitsyanko Igor } 187730628cb1SMitsyanko Igor }; 187830628cb1SMitsyanko Igor 187930628cb1SMitsyanko Igor static const VMStateDescription exynos4210_fimd_vmstate = { 188030628cb1SMitsyanko Igor .name = "exynos4210.fimd", 188130628cb1SMitsyanko Igor .version_id = 1, 188230628cb1SMitsyanko Igor .minimum_version_id = 1, 188330628cb1SMitsyanko Igor .post_load = exynos4210_fimd_load, 188430628cb1SMitsyanko Igor .fields = (VMStateField[]) { 188530628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4), 188630628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4), 188730628cb1SMitsyanko Igor VMSTATE_UINT32(shadowcon, Exynos4210fimdState), 188830628cb1SMitsyanko Igor VMSTATE_UINT32(winchmap, Exynos4210fimdState), 188930628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2), 189030628cb1SMitsyanko Igor VMSTATE_UINT32(dithmode, Exynos4210fimdState), 189130628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2), 189230628cb1SMitsyanko Igor VMSTATE_UINT32(trigcon, Exynos4210fimdState), 189330628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4), 189430628cb1SMitsyanko Igor VMSTATE_UINT32(colorgaincon, Exynos4210fimdState), 189530628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2), 189630628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3), 189730628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4), 189830628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4), 189930628cb1SMitsyanko Igor VMSTATE_UINT32(hueoffset, Exynos4210fimdState), 190030628cb1SMitsyanko Igor VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12), 190130628cb1SMitsyanko Igor VMSTATE_UINT32(blendcon, Exynos4210fimdState), 190230628cb1SMitsyanko Igor VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1, 190330628cb1SMitsyanko Igor exynos4210_fimd_window_vmstate, Exynos4210fimdWindow), 190430628cb1SMitsyanko Igor VMSTATE_END_OF_LIST() 190530628cb1SMitsyanko Igor } 190630628cb1SMitsyanko Igor }; 190730628cb1SMitsyanko Igor 1908380cd056SGerd Hoffmann static const GraphicHwOps exynos4210_fimd_ops = { 1909380cd056SGerd Hoffmann .invalidate = exynos4210_fimd_invalidate, 1910380cd056SGerd Hoffmann .gfx_update = exynos4210_fimd_update, 1911380cd056SGerd Hoffmann }; 1912380cd056SGerd Hoffmann 19133c09d6caSxiaoqiang zhao static void exynos4210_fimd_init(Object *obj) 191430628cb1SMitsyanko Igor { 19153c09d6caSxiaoqiang zhao Exynos4210fimdState *s = EXYNOS4210_FIMD(obj); 19163c09d6caSxiaoqiang zhao SysBusDevice *dev = SYS_BUS_DEVICE(obj); 191730628cb1SMitsyanko Igor 191830628cb1SMitsyanko Igor s->ifb = NULL; 191930628cb1SMitsyanko Igor 192030628cb1SMitsyanko Igor sysbus_init_irq(dev, &s->irq[0]); 192130628cb1SMitsyanko Igor sysbus_init_irq(dev, &s->irq[1]); 192230628cb1SMitsyanko Igor sysbus_init_irq(dev, &s->irq[2]); 192330628cb1SMitsyanko Igor 19243c09d6caSxiaoqiang zhao memory_region_init_io(&s->iomem, obj, &exynos4210_fimd_mmio_ops, s, 192530628cb1SMitsyanko Igor "exynos4210.fimd", FIMD_REGS_SIZE); 192630628cb1SMitsyanko Igor sysbus_init_mmio(dev, &s->iomem); 19273c09d6caSxiaoqiang zhao } 192830628cb1SMitsyanko Igor 19293c09d6caSxiaoqiang zhao static void exynos4210_fimd_realize(DeviceState *dev, Error **errp) 19303c09d6caSxiaoqiang zhao { 19313c09d6caSxiaoqiang zhao Exynos4210fimdState *s = EXYNOS4210_FIMD(dev); 19323c09d6caSxiaoqiang zhao 19333c09d6caSxiaoqiang zhao s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s); 193430628cb1SMitsyanko Igor } 193530628cb1SMitsyanko Igor 193630628cb1SMitsyanko Igor static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) 193730628cb1SMitsyanko Igor { 193830628cb1SMitsyanko Igor DeviceClass *dc = DEVICE_CLASS(klass); 193930628cb1SMitsyanko Igor 194030628cb1SMitsyanko Igor dc->vmsd = &exynos4210_fimd_vmstate; 194130628cb1SMitsyanko Igor dc->reset = exynos4210_fimd_reset; 19423c09d6caSxiaoqiang zhao dc->realize = exynos4210_fimd_realize; 194330628cb1SMitsyanko Igor } 194430628cb1SMitsyanko Igor 19458c43a6f0SAndreas Färber static const TypeInfo exynos4210_fimd_info = { 1946f27321aaSAndreas Färber .name = TYPE_EXYNOS4210_FIMD, 194730628cb1SMitsyanko Igor .parent = TYPE_SYS_BUS_DEVICE, 194830628cb1SMitsyanko Igor .instance_size = sizeof(Exynos4210fimdState), 19493c09d6caSxiaoqiang zhao .instance_init = exynos4210_fimd_init, 195030628cb1SMitsyanko Igor .class_init = exynos4210_fimd_class_init, 195130628cb1SMitsyanko Igor }; 195230628cb1SMitsyanko Igor 195330628cb1SMitsyanko Igor static void exynos4210_fimd_register_types(void) 195430628cb1SMitsyanko Igor { 195530628cb1SMitsyanko Igor type_register_static(&exynos4210_fimd_info); 195630628cb1SMitsyanko Igor } 195730628cb1SMitsyanko Igor 195830628cb1SMitsyanko Igor type_init(exynos4210_fimd_register_types) 1959