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