[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 11/14] ARM: s5pc210: added s5pc210 display controlle
From: |
Evgeny Voevodin |
Subject: |
[Qemu-devel] [PATCH 11/14] ARM: s5pc210: added s5pc210 display controller device (FIMD) |
Date: |
Wed, 07 Dec 2011 13:47:02 +0400 |
From: Mitsyanko Igor <address@hidden>
Signed-off-by: Evgeny Voevodin <address@hidden>
---
Makefile.target | 2 +-
hw/s5pc210.c | 11 +
hw/s5pc210_fimd.c | 1698 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1710 insertions(+), 1 deletions(-)
create mode 100644 hw/s5pc210_fimd.c
diff --git a/Makefile.target b/Makefile.target
index 805993b..84c4a05 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -345,7 +345,7 @@ obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o
pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += s5pc210.o s5pc210_cmu.o s5pc210_uart.o s5pc210_gic.o \
- s5pc210_combiner.o s5pc210_pwm.o s5pc210_mct.o
+ s5pc210_combiner.o s5pc210_pwm.o s5pc210_mct.o s5pc210_fimd.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
obj-arm-y += arm-semi.o
diff --git a/hw/s5pc210.c b/hw/s5pc210.c
index 8678b97..c7cba3e 100644
--- a/hw/s5pc210.c
+++ b/hw/s5pc210.c
@@ -97,6 +97,10 @@
/* MCT */
#define S5PC210_MCT_BASE_ADDR 0x10050000
+/* Display controllers (FIMD) */
+#define S5PC210_FIMD0_BASE_ADDR 0x11C00000
+#define S5PC210_FIMD1_BASE_ADDR 0x12000000
+
#define S5PC210_BASE_BOOT_ADDR S5PC210_DRAM0_BASE_ADDR
/* Secondary CPU startup code is in IROM memory */
@@ -465,6 +469,13 @@ static void s5pc210_init(ram_addr_t ram_size,
}
}
+ /*** Display controller (FIMD) ***/
+ sysbus_create_varargs("s5pc210.fimd", S5PC210_FIMD0_BASE_ADDR,
+ irq_table[s5pc210_get_irq(11, 0)],
+ irq_table[s5pc210_get_irq(11, 1)],
+ irq_table[s5pc210_get_irq(11, 2)],
+ NULL);
+
/*** Load kernel ***/
s5pc210_binfo.ram_size = ram_size;
diff --git a/hw/s5pc210_fimd.c b/hw/s5pc210_fimd.c
new file mode 100644
index 0000000..b3b01f2
--- /dev/null
+++ b/hw/s5pc210_fimd.c
@@ -0,0 +1,1698 @@
+/*
+ * Samsung s5pc210 Display Controller (FIMD)
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ * Based on LCD controller for Samsung S5PC1xx-based board emulation
+ * by Kirill Batuzov <address@hidden>
+ *
+ * Contributed by Mitsyanko Igor <address@hidden>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "qemu-common.h"
+#include "cpu-all.h"
+#include "sysbus.h"
+#include "console.h"
+#include "pixel_ops.h"
+
+/* Debug messages configuration */
+#define S5P_FIMD_DEBUG 0
+#define S5P_FIMD_MODE_TRACE 0
+
+#if S5P_FIMD_DEBUG == 0
+ #define print_debug1(fmt, args...) do { } while (0)
+ #define print_debug2(fmt, args...) do { } while (0)
+ #define print_error(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#elif S5P_FIMD_DEBUG == 1
+ #define print_debug1(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+ #define print_debug2(fmt, args...) do { } while (0)
+ #define print_error(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#else
+ #define print_debug1(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+ #define print_debug2(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
+ #define print_error(fmt, args...) \
+ do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
+#endif
+
+
+#define NUM_OF_WINDOWS 5
+#define FIMD_REGS_SIZE 0x4114
+
+/* Video main control registers */
+#define FIMD_VIDCON0 0x0000
+#define FIMD_VIDCON1 0x0004
+#define FIMD_VIDCON2 0x0008
+#define FIMD_VIDCON3 0x000C
+#define FIMD_VIDCON0_ENVID_F (1 << 0)
+#define FIMD_VIDCON0_ENVID (1 << 1)
+#define FIMD_VIDCON0_ENVID_MASK ((1 << 0) | (1 << 1))
+#define FIMD_VIDCON1_ROMASK 0x07FFE000
+
+/* Video time control registers */
+#define FIMD_VIDTCON2_SIZE_MASK 0x07FF
+#define FIMD_VIDTCON2_HOR_SHIFT 0
+#define FIMD_VIDTCON2_VER_SHIFT 11
+
+/* Window control registers */
+#define FIMD_WINCON0 0x0020
+#define FIMD_WINCON_ROMASK 0x82200000
+#define FIMD_WINCON_ENWIN (1 << 0)
+#define FIMD_WINCON_BLD_PIX (1 << 6)
+#define FIMD_WINCON_ALPHA_SEL (1 << 1)
+#define FIMD_WINCON_ALSEL_SHIFT 1
+#define FIMD_WINCON_SWAP 0x078000
+#define FIMD_WINCON_SWAP_SHIFT 15
+#define FIMD_WINCON_SWAP_WORD 0x1
+#define FIMD_WINCON_SWAP_HWORD 0x2
+#define FIMD_WINCON_SWAP_BYTE 0x4
+#define FIMD_WINCON_SWAP_BITS 0x8
+#define FIMD_WINCON_BPPMODE_SHIFT 2
+#define FIMD_WINCON_BPPMODE 0x0F
+#define FIMD_WINCON_BUFSTATUS_L (1 << 21)
+#define FIMD_WINCON_BUFSTATUS_H (1 << 31)
+#define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31))
+#define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31))
+#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31))
+#define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30))
+#define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30))
+#define FIMD_WINCON_BUF2_SEL ((0 << 20) | (1 << 30))
+#define FIMD_WINCON_BUFMODE (1 << 14)
+
+/* Window position control registers */
+#define FIMD_VIDOSD_COORD_MASK 0x07FF
+#define FIMD_VIDOSD_HOR_SHIFT 11
+#define FIMD_VIDOSD_VER_SHIFT 0
+#define FIMD_VIDOSD_ALPHA_AEN0 0xFFF000
+#define FIMD_VIDOSD_AEN0_SHIFT 12
+#define FIMD_VIDOSD_ALPHA_AEN1 0x000FFF
+
+/* Frame buffer address registers */
+#define FIMD_VIDWADD2_PAGEWIDTH 0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE 0x1FFF
+#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
+
+/* Window color key registers */
+#define FIMD_WKEYCON0_COMPKEY 0x00FFFFFF
+#define FIMD_WKEYCON0_CTL_SHIFT 24
+#define FIMD_WKEYCON0_CTL_DIRCON 0x1
+#define FIMD_WKEYCON0_CTL_KEYEN 0x2
+#define FIMD_WKEYCON0_CTL_KEYBLEN 0x4
+
+/* Window alpha control registers */
+#define FIMD_VIDALPHA_ALPHA_MASK 0x000F0F0F
+
+/* Window color map registers */
+#define FIMD_WINMAP_EN (1 << 24)
+#define FIMD_WINMAP_COLOR_MASK 0x00FFFFFF
+#define FIMD_WINMAP_NOCOLOR (~FIMD_WINMAP_COLOR_MASK)
+
+/* Window palette control registers */
+#define FIMD_WPAL_W0PAL_L 0x07
+#define FIMD_WPAL_W0PAL_L_SH 0
+#define FIMD_WPAL_W1PAL_L 0x07
+#define FIMD_WPAL_W1PAL_L_SH 3
+#define FIMD_WPAL_W2PAL_L 0x01
+#define FIMD_WPAL_W2PAL_L_SH 6
+#define FIMD_WPAL_W2PAL_H 0x06
+#define FIMD_WPAL_W2PAL_H_SH 8
+#define FIMD_WPAL_W3PAL_L 0x01
+#define FIMD_WPAL_W3PAL_L_SH 7
+#define FIMD_WPAL_W3PAL_H 0x06
+#define FIMD_WPAL_W3PAL_H_SH 12
+#define FIMD_WPAL_W4PAL_L 0x01
+#define FIMD_WPAL_W4PAL_L_SH 8
+#define FIMD_WPAL_W4PAL_H 0x06
+#define FIMD_WPAL_W4PAL_H_SH 16
+
+/* Trigger control registers */
+#define FIMD_TRIGCON 0x01A4
+#define FIMD_TRIGCON_ROMASK 0x00000004
+
+/* Video interrupt control registers */
+#define FIMD_VIDINT_INTFIFOPEND (1 << 0)
+#define FIMD_VIDINT_INTFRMPEND (1 << 1)
+#define FIMD_VIDINT_INTI80PEND (1 << 2)
+#define FIMD_VIDINT_INTEN (1 << 0)
+#define FIMD_VIDINT_INTFIFOEN (1 << 1)
+#define FIMD_VIDINT_INTFRMEN (1 << 12)
+#define FIMD_VIDINT_I80IFDONE (1 << 17)
+
+/* Window blend equation control registers */
+#define FIMD_BLENDEQ_COEF_MASK 0xF
+#define FIMD_BLENDEQ_COEF_Q 18
+#define FIMD_BLENDEQ_COEF_P 12
+#define FIMD_BLENDEQ_COEF_B 6
+#define FIMD_BLENDEQ_COEF_A 0
+
+typedef struct {
+ uint8_t r, g, b;
+ uint32_t a;
+} rgba;
+#define RGBA_SIZE 7
+
+typedef struct DrawConfig DrawConfig;
+
+typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
+typedef void draw_line_func(struct DrawConfig *cfg, uint8_t *src,
+ uint8_t *dst, uint8_t *ifb);
+typedef uint32_t coef_func(const struct DrawConfig *cfg, rgba pa, rgba pb);
+
+typedef struct {
+ uint32_t wincon; /* Window control register */
+ uint32_t vidosd[4]; /* Window position control registers A-D */
+ uint32_t buf_start[3]; /* Start address for video frame buffer */
+ uint32_t buf_end[3]; /* End address for video frame buffer */
+ uint32_t buf_size; /* Virtual screen width */
+ uint32_t keycon[2]; /* Window color key registers */
+ uint32_t keyalpha; /* Color key alpha control register */
+ uint32_t winmap; /* Window color map register */
+ uint32_t vidw_alpha[2]; /* Window alpha control registers */
+ uint32_t blendeq; /* Window blending equation control register */
+ uint32_t rtqoscon; /* Window RTQOS Control Registers */
+ uint32_t palette[256]; /* Pallete RAM */
+ uint32_t shadow_buf_start; /* Start address of shadow frame buffer */
+ uint32_t shadow_buf_end; /* End address of shadow frame buffer */
+ uint32_t shadow_buf_size; /* Virtual shadow screen width */
+} S5pc210fimdWindow;
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ DisplayState *console;
+ qemu_irq irq[3];
+
+ uint32_t vidcon[4]; /* Video main control registers 0-3 */
+ uint32_t vidtcon[4]; /* Video time control registers 0-3 */
+ uint32_t shadowcon; /* Window shadow control register */
+ uint32_t winchmap; /* Channel maping control register */
+ uint32_t vidintcon[2]; /* Video interrupt control registers */
+ uint32_t dithmode; /* Dithering control register */
+ uint32_t wpalcon[2]; /* Window pallete control registers */
+ uint32_t trigcon; /* Trigger control register */
+ uint32_t i80ifcon[4]; /* I80 interface control registers */
+ uint32_t colorgaincon; /* Color gain control register */
+ uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
+ uint32_t sifccon[3]; /* I80 System Interface Manual Command Control */
+ uint32_t huecoef_cr[4]; /* Hue control registers */
+ uint32_t huecoef_cb[4]; /* Hue control registers */
+ uint32_t hueoffset; /* Hue offset control register */
+ uint32_t blendcon; /* Blending equation control register */
+ uint32_t dualrgb; /* Undocumented register */
+ uint32_t i80ifcmd[12]; /* LCD I80 Interface Command */
+
+ S5pc210fimdWindow window[5]; /* Window-specific registers */
+ uint8_t *ifb; /* Internal frame buffer */
+ bool invalidate; /* Image needs to be redrawn */
+ bool enabled; /* Display controller is enabled */
+} S5pc210fimdState;
+
+struct DrawConfig {
+ pixel_to_rgb_func *pixel_to_rgb;
+ draw_line_func *draw_line;
+ int (*put_pixel)(const rgba p, uint8_t *pixel);
+ int (*get_pixel)(const uint8_t *src, rgba *p);
+ void (*blend)(struct DrawConfig *cfg, rgba p_old, rgba p_new, rgba *p);
+ coef_func *coef_p, *coef_q, *coef_a, *coef_b;
+ uint8_t is_palletized;
+ uint32_t bg_alpha[2], fg_alpha[2];
+ uint32_t color_key, color_mask, color_ctl;
+ uint8_t fg_alpha_pix, bg_alpha_pix;
+ int width;
+ int bpp;
+ uint32_t *palette;
+ uint8_t swap;
+ uint8_t fg_pixel_blending, bg_pixel_blending;
+ uint8_t fg_alpha_sel, bg_alpha_sel;
+ uint32_t map_color;
+};
+
+static inline int s5pc210_buffer_status(S5pc210fimdWindow *w)
+{
+ switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
+ case FIMD_WINCON_BUF0_STAT: default:
+ return 0;
+ case FIMD_WINCON_BUF1_STAT:
+ return 1;
+ case FIMD_WINCON_BUF2_STAT:
+ return 2;
+ }
+}
+
+/* Perform byte/halfword/word swap of data according to config */
+static inline uint64_t swap_data(const DrawConfig *cfg, uint64_t x)
+{
+ int i;
+ uint64_t res;
+
+ if (cfg->swap & FIMD_WINCON_SWAP_BITS) {
+ res = 0;
+ for (i = 0; i < 64; i++) {
+ if (x & (1ULL << (64 - i))) {
+ res |= (1ULL << i);
+ }
+ }
+ x = res;
+ }
+ if (cfg->swap & FIMD_WINCON_SWAP_BYTE) {
+ x = ((x & 0x00000000000000FFULL) << 56) |
+ ((x & 0x000000000000FF00ULL) << 40) |
+ ((x & 0x0000000000FF0000ULL) << 24) |
+ ((x & 0x00000000FF000000ULL) << 8) |
+ ((x & 0x000000FF00000000ULL) >> 8) |
+ ((x & 0x0000FF0000000000ULL) >> 24) |
+ ((x & 0x00FF000000000000ULL) >> 40) |
+ ((x & 0xFF00000000000000ULL) >> 56);
+ }
+ if (cfg->swap & FIMD_WINCON_SWAP_HWORD) {
+ x = ((x & 0x000000000000FFFFULL) << 48) |
+ ((x & 0x00000000FFFF0000ULL) << 16) |
+ ((x & 0x0000FFFF00000000ULL) >> 16) |
+ ((x & 0xFFFF000000000000ULL) >> 48);
+ }
+ if (cfg->swap & FIMD_WINCON_SWAP_WORD) {
+ x = ((x & 0x00000000FFFFFFFFULL) << 32) |
+ ((x & 0xFFFFFFFF00000000ULL) >> 32);
+ }
+ return x;
+}
+
+/* Palette/pixel to RGB conversion */
+
+#define DEF_PIXEL_TO_RGB(N, R, G, B, A) \
+static void N(uint32_t pixel, rgba *p) \
+{ \
+ p->b = (pixel & ((1 << (B)) - 1)) << (8 - (B)); \
+ pixel >>= (B); \
+ p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)); \
+ pixel >>= (G); \
+ p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)); \
+ pixel >>= (R); \
+ if (1 == (A)) { \
+ p->a = pixel & 1; \
+ } else if (8 == (A)) { \
+ p->a = pixel & 0xFF; \
+ p->a = (p->a << 16) | (p->a << 8) | p->a; \
+ } else { \
+ p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)); \
+ } \
+}
+
+DEF_PIXEL_TO_RGB(pixel_a232_to_rgb, 2, 3, 2, 1)
+DEF_PIXEL_TO_RGB(pixel_a444_to_rgb, 4, 4, 4, 1)
+DEF_PIXEL_TO_RGB(pixel_4444_to_rgb, 4, 4, 4, 4)
+DEF_PIXEL_TO_RGB(pixel_565_to_rgb, 5, 6, 5, 0)
+DEF_PIXEL_TO_RGB(pixel_a555_to_rgb, 5, 5, 5, 1)
+DEF_PIXEL_TO_RGB(pixel_555_to_rgb, 5, 5, 5, 0)
+DEF_PIXEL_TO_RGB(pixel_666_to_rgb, 6, 6, 6, 0)
+DEF_PIXEL_TO_RGB(pixel_a666_to_rgb, 6, 6, 6, 1)
+DEF_PIXEL_TO_RGB(pixel_a665_to_rgb, 6, 6, 5, 1)
+DEF_PIXEL_TO_RGB(pixel_888_to_rgb, 8, 8, 8, 0)
+DEF_PIXEL_TO_RGB(pixel_a888_to_rgb, 8, 8, 8, 1)
+DEF_PIXEL_TO_RGB(pixel_a887_to_rgb, 8, 8, 7, 1)
+DEF_PIXEL_TO_RGB(pixel_8888_to_rgb, 8, 8, 8, 8)
+
+/* Special case for (5+1,5+1,5+1) mode */
+static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
+{
+ uint8_t u = (pixel >> 15) & 1;
+ p->b = (((pixel & 0x1F) << 1) | u) << 2;
+ pixel >>= 5;
+ p->g = (((pixel & 0x3F) << 1) | u) << 2;
+ pixel >>= 6;
+ p->r = (((pixel & 0x1F) << 1) | u) << 2;
+}
+
+/* Draw line with pallete index in frame buffer data */
+#define DEF_DRAW_LINE_PALLETE(N) \
+static void glue(draw_line_pallete_, N)(DrawConfig *cfg, uint8_t *src, \
+ uint8_t *dst, uint8_t *ifb) \
+{ \
+ int width = cfg->width; \
+ uint64_t data; \
+ rgba p, p_old; \
+ int i; \
+ do { \
+ data = ldq_raw((void *)src); \
+ src += 8; \
+ data = swap_data(cfg, data); \
+ for (i = (64 / (N) - 1); i >= 0; i--) { \
+ cfg->pixel_to_rgb(cfg->palette[(data >> ((N) * i)) & \
+ ((1ULL << (N)) - 1)], &p); \
+ if (cfg->blend) { \
+ ifb += cfg->get_pixel(ifb, &p_old); \
+ cfg->blend(cfg, p_old, p, &p); \
+ } \
+ dst += cfg->put_pixel(p, dst); \
+ } \
+ width -= (64 / (N)); \
+ } while (width > 0); \
+}
+
+/* Draw line with direct color value in frame buffer data */
+#define DEF_DRAW_LINE_NOPALLETE(N) \
+static void glue(draw_line_, N)(DrawConfig *cfg, uint8_t *src, \
+ uint8_t *dst, uint8_t *ifb) \
+{ \
+ int width = cfg->width; \
+ uint64_t data; \
+ rgba p, p_old; \
+ int i; \
+ do { \
+ data = ldq_raw((void *)src); \
+ src += 8; \
+ data = swap_data(cfg, data); \
+ for (i = (64 / (N) - 1); i >= 0; i--) { \
+ cfg->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
+ if (cfg->blend) { \
+ ifb += cfg->get_pixel(ifb, &p_old); \
+ cfg->blend(cfg, p_old, p, &p); \
+ } \
+ dst += cfg->put_pixel(p, dst); \
+ } \
+ width -= (64 / (N)); \
+ } while (width > 0); \
+}
+
+DEF_DRAW_LINE_PALLETE(1)
+DEF_DRAW_LINE_PALLETE(2)
+DEF_DRAW_LINE_PALLETE(4)
+DEF_DRAW_LINE_PALLETE(8)
+DEF_DRAW_LINE_NOPALLETE(8) /* 8bpp mode has pallete and non-pallete versions
*/
+DEF_DRAW_LINE_NOPALLETE(16)
+DEF_DRAW_LINE_NOPALLETE(32)
+
+/* Special draw line routine for window color map case */
+static void draw_line_mapcolor(DrawConfig *cfg, uint8_t *src,
+ uint8_t *dst, uint8_t *ifb)
+{
+ rgba p, p_old;
+ int width = cfg->width;
+ uint32_t map_color = cfg->map_color;
+
+ do {
+ pixel_888_to_rgb(map_color, &p);
+ if (cfg->blend) {
+ ifb += cfg->get_pixel(ifb, &p_old);
+ cfg->blend(cfg, p_old, p, &p);
+ }
+ dst += cfg->put_pixel(p, dst);
+ } while (--width);
+}
+
+/* Routine to copy line from internal frame buffer to QEMU display */
+static void draw_line_copy(DrawConfig *cfg, uint8_t *src, uint8_t *dst)
+{
+ rgba p;
+ int width = cfg->width;
+
+ do {
+ src += cfg->get_pixel(src, &p);
+ dst += cfg->put_pixel(p, dst);
+ } while (--width);
+}
+
+/* Parse BPPMODE_F bits and setup known DRAW_CONFIG fields accordingly.
+ BPPMODE_F = WINCON1[5:2] */
+static void s5pc210_parse_win_bppmode(S5pc210fimdWindow *w, DrawConfig *cfg)
+{
+ switch ((w->wincon >> FIMD_WINCON_BPPMODE_SHIFT) & FIMD_WINCON_BPPMODE) {
+ case 0:
+ cfg->draw_line = draw_line_pallete_1;
+ cfg->is_palletized = 1;
+ cfg->bpp = 1;
+ break;
+ case 1:
+ cfg->draw_line = draw_line_pallete_2;
+ cfg->is_palletized = 1;
+ cfg->bpp = 2;
+ break;
+ case 2:
+ cfg->draw_line = draw_line_pallete_4;
+ cfg->is_palletized = 1;
+ cfg->bpp = 4;
+ break;
+ case 3:
+ cfg->draw_line = draw_line_pallete_8;
+ cfg->is_palletized = 1;
+ cfg->bpp = 8;
+ break;
+ case 4:
+ cfg->draw_line = draw_line_8;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_a232_to_rgb;
+ cfg->bpp = 8;
+ break;
+ case 5:
+ cfg->draw_line = draw_line_16;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_565_to_rgb;
+ cfg->bpp = 16;
+ break;
+ case 6:
+ cfg->draw_line = draw_line_16;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_a555_to_rgb;
+ cfg->bpp = 16;
+ break;
+ case 7:
+ cfg->draw_line = draw_line_16;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_1555_to_rgb;
+ cfg->bpp = 16;
+ break;
+ case 8:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_666_to_rgb;
+ cfg->bpp = 32;
+ break;
+ case 9:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_a665_to_rgb;
+ cfg->bpp = 32;
+ break;
+ case 10:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_a666_to_rgb;
+ cfg->bpp = 32;
+ break;
+ case 11:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_888_to_rgb;
+ cfg->bpp = 32;
+ break;
+ case 12:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_a887_to_rgb;
+ cfg->bpp = 32;
+ break;
+ case 13:
+ cfg->draw_line = draw_line_32;
+ cfg->is_palletized = 0;
+ if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+ FIMD_WINCON_ALPHA_SEL)) {
+ cfg->pixel_to_rgb = pixel_8888_to_rgb;
+ cfg->fg_alpha_pix = 1;
+ } else {
+ cfg->pixel_to_rgb = pixel_a888_to_rgb;
+ }
+ cfg->bpp = 32;
+ break;
+ case 14:
+ cfg->draw_line = draw_line_16;
+ cfg->is_palletized = 0;
+ if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
+ FIMD_WINCON_ALPHA_SEL)) {
+ cfg->pixel_to_rgb = pixel_4444_to_rgb;
+ cfg->fg_alpha_pix = 1;
+ } else {
+ cfg->pixel_to_rgb = pixel_a444_to_rgb;
+ }
+ cfg->bpp = 16;
+ break;
+ case 15:
+ cfg->draw_line = draw_line_16;
+ cfg->is_palletized = 0;
+ cfg->pixel_to_rgb = pixel_555_to_rgb;
+ cfg->bpp = 16;
+ break;
+ }
+}
+
+#if S5P_FIMD_MODE_TRACE > 0
+static const char *s5pc210_fimd_get_bppmode(int mode_code)
+{
+ switch (mode_code) {
+ case 0:
+ return "1 bpp";
+ case 1:
+ return "2 bpp";
+ case 2:
+ return "4 bpp";
+ case 3:
+ return "8 bpp (palletized)";
+ case 4:
+ return "8 bpp (non-palletized, A: 1-R:2-G:3-B:2)";
+ case 5:
+ return "16 bpp (non-palletized, R:5-G:6-B:5)";
+ case 6:
+ return "16 bpp (non-palletized, A:1-R:5-G:5-B:5)";
+ case 7:
+ return "16 bpp (non-palletized, I :1-R:5-G:5-B:5)";
+ case 8:
+ return "Unpacked 18 bpp (non-palletized, R:6-G:6-B:6)";
+ case 9:
+ return "Unpacked 18bpp (non-palletized,A:1-R:6-G:6-B:5)";
+ case 10:
+ return "Unpacked 19bpp (non-palletized,A:1-R:6-G:6-B:6)";
+ case 11:
+ return "Unpacked 24 bpp (non-palletized R:8-G:8-B:8)";
+ case 12:
+ return "Unpacked 24 bpp (non-palletized A:1-R:8-G:8-B:7)";
+ case 13:
+ return "Unpacked 25 bpp (non-palletized A:1-R:8-G:8-B:8)";
+ case 14:
+ return "Unpacked 13 bpp (non-palletized A:1-R:4-G:4-B:4)";
+ case 15:
+ return "Unpacked 15 bpp (non-palletized R:5-G:5-B:5)";
+ default:
+ return "Non-existing bpp mode";
+ }
+}
+#endif
+
+static inline void s5pc210_fimd_trace_bppmode(S5pc210fimdWindow *w,
+ int win_num, uint32_t val)
+{
+#if S5P_FIMD_MODE_TRACE > 0
+ if (((w->wincon >> FIMD_WINCON_BPPMODE_SHIFT) & FIMD_WINCON_BPPMODE) ==
+ ((val >> FIMD_WINCON_BPPMODE_SHIFT) & FIMD_WINCON_BPPMODE)) {
+ return;
+ }
+ printf("QEMU FIMD: Window %d BPP mode changed from %s to %s\n", win_num,
+ s5pc210_fimd_get_bppmode((w->wincon >> FIMD_WINCON_BPPMODE_SHIFT) &
+ FIMD_WINCON_BPPMODE),
+ s5pc210_fimd_get_bppmode((val >> FIMD_WINCON_BPPMODE_SHIFT) &
+ FIMD_WINCON_BPPMODE));
+#endif
+}
+
+static inline void s5pc210_fimd_trace_reset(void)
+{
+#if S5P_FIMD_MODE_TRACE > 0
+ fprintf(stderr, "QEMU FIMD: Display controller reset\n");
+#endif
+}
+
+static inline void s5pc210_fimd_enable(S5pc210fimdState *s, bool enabled)
+{
+ s->enabled = enabled ? true : false;
+#if S5P_FIMD_MODE_TRACE > 0
+ fprintf(stderr, "QEMU FIMD: display controller %s\n",
+ (enabled ? "enabled" : "disabled"));
+#endif
+}
+
+/* Returns WxPAL for given window number WINDOW */
+static uint32_t s5pc210_wxpal(S5pc210fimdState *s, int window)
+{
+ switch (window) {
+ case 0:
+ return (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SH) & FIMD_WPAL_W0PAL_L;
+ case 1:
+ return (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SH) & FIMD_WPAL_W1PAL_L;
+ case 2:
+ return ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SH) & FIMD_WPAL_W2PAL_H) |
+ ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SH) & FIMD_WPAL_W2PAL_L);
+ case 3:
+ return ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SH) & FIMD_WPAL_W3PAL_H) |
+ ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SH) & FIMD_WPAL_W3PAL_L);
+ case 4:
+ return ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SH) & FIMD_WPAL_W4PAL_H) |
+ ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SH) & FIMD_WPAL_W4PAL_L);
+ }
+ hw_error("s5pc210.fimd: incorrect window number %d\n", window);
+ return 0;
+}
+
+pixel_to_rgb_func *wxpal_to_rgb[8] = {
+ [0] = pixel_565_to_rgb,
+ [1] = pixel_a555_to_rgb,
+ [2] = pixel_666_to_rgb,
+ [3] = pixel_a665_to_rgb,
+ [4] = pixel_a666_to_rgb,
+ [5] = pixel_888_to_rgb,
+ [6] = pixel_a888_to_rgb,
+ [7] = pixel_8888_to_rgb
+};
+
+/* Put/get pixel to/from internal LCD Controller framebuffer */
+
+static int put_rgba(const rgba p, uint8_t *d)
+{
+ *(uint8_t *)d++ = p.r;
+ *(uint8_t *)d++ = p.g;
+ *(uint8_t *)d++ = p.b;
+ *(uint32_t *)d = p.a;
+ return RGBA_SIZE;
+}
+
+static int get_rgba(const uint8_t *s, rgba *p)
+{
+ p->r = *(uint8_t *)s++;
+ p->g = *(uint8_t *)s++;
+ p->b = *(uint8_t *)s++;
+ p->a = *(uint32_t *)s;
+ return RGBA_SIZE;
+}
+
+/* Write RGB to QEMU's GraphicConsole framebuffer */
+
+static int put_pixel8(const rgba p, uint8_t *d)
+{
+ uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
+ *(uint8_t *)d = pixel;
+ return 1;
+}
+
+static int put_pixel15(const rgba p, uint8_t *d)
+{
+ uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
+ *(uint16_t *)d = pixel;
+ return 2;
+}
+
+static int put_pixel16(const rgba p, uint8_t *d)
+{
+ uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
+ *(uint16_t *)d = pixel;
+ return 2;
+}
+
+static int put_pixel24(const rgba p, uint8_t *d)
+{
+ uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+ *(uint8_t *)d++ = (pixel >> 0) & 0xFF;
+ *(uint8_t *)d++ = (pixel >> 8) & 0xFF;
+ *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
+ return 3;
+}
+
+static int put_pixel32(const rgba p, uint8_t *d)
+{
+ uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
+ *(uint32_t *)d = pixel;
+ return 4;
+}
+
+static inline uint32_t unpack_by_4(uint32_t x)
+{
+ return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
+}
+
+
+/* Coefficient extraction functions */
+
+static uint32_t coef_zero(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return 0;
+}
+
+static uint32_t coef_one(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return 0xFFFFFF;
+}
+
+static uint32_t coef_alphaa(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ if (!cfg->fg_pixel_blending) {
+ pa.a = cfg->fg_alpha_sel;
+ }
+ if (cfg->fg_alpha_pix) {
+ return pa.a;
+ } else {
+ return cfg->fg_alpha[pa.a];
+ }
+}
+
+static uint32_t coef_one_minus_alphaa(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ if (!cfg->fg_pixel_blending) {
+ pa.a = cfg->fg_alpha_sel;
+ }
+ if (cfg->fg_alpha_pix) {
+ return 0xFFFFFF - pa.a;
+ } else {
+ return 0xFFFFFF - cfg->fg_alpha[pa.a];
+ }
+}
+
+static uint32_t coef_alphab(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ if (!cfg->bg_pixel_blending) {
+ pb.a = cfg->bg_alpha_sel;
+ }
+ if (cfg->bg_alpha_pix) {
+ return pb.a;
+ } else {
+ return cfg->bg_alpha[pb.a];
+ }
+}
+
+static uint32_t coef_one_minus_alphab(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ if (!cfg->bg_pixel_blending) {
+ pb.a = cfg->bg_alpha_sel;
+ }
+ if (cfg->bg_alpha_pix) {
+ return 0xFFFFFF - pb.a;
+ } else {
+ return 0xFFFFFF - cfg->bg_alpha[pb.a];
+ }
+}
+
+static uint32_t coef_a(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return (pa.r << 16) | (pa.g << 8) | pa.b;
+}
+
+static uint32_t coef_one_minus_a(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return 0xFFFFFF - ((pa.r << 16) | (pa.g << 8) | pa.b);
+}
+
+static uint32_t coef_b(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return (pb.r << 16) | (pb.g << 8) | pb.b;
+}
+
+static uint32_t coef_one_minus_b(const DrawConfig *cfg,
+ rgba pa, rgba pb)
+{
+ return 0xFFFFFF - ((pb.r << 16) | (pb.g << 8) | pb.b);
+}
+
+
+static coef_func *coef_decode(uint32_t x)
+{
+ switch (x) {
+ case 0:
+ return coef_zero;
+ case 1:
+ return coef_one;
+ case 2:
+ return coef_alphaa;
+ case 3:
+ return coef_one_minus_alphaa;
+ case 4:
+ return coef_alphab;
+ case 5:
+ return coef_one_minus_alphab;
+ case 10:
+ return coef_a;
+ case 11:
+ return coef_one_minus_a;
+ case 12:
+ return coef_b;
+ case 13:
+ return coef_one_minus_b;
+ default:
+ hw_error("s5pc210.fimd: blend equation coef illegal value\n");
+ return 0;
+ }
+}
+
+static void blend_alpha(const DrawConfig *cfg, rgba p_bg, rgba p_fg, rgba *res)
+{
+ uint32_t pl, ql, al, bl;
+ uint32_t p, q, a, b, fg, bg, fga, bga;
+
+ pl = cfg->coef_p(cfg, p_fg, p_bg);
+ ql = cfg->coef_q(cfg, p_fg, p_bg);
+ al = cfg->coef_a(cfg, p_fg, p_bg);
+ bl = cfg->coef_b(cfg, p_fg, p_bg);
+ res->a = 0;
+ /* B */
+ p = pl & 0xFF;
+ pl >>= 8;
+ q = ql & 0xFF;
+ ql >>= 8;
+ a = al & 0xFF;
+ al >>= 8;
+ b = bl & 0xFF;
+ bl >>= 8;
+ fg = p_fg.b;
+ bg = p_bg.b;
+ if (cfg->fg_pixel_blending) {
+ if (cfg->fg_alpha_pix) {
+ fga = p_fg.a & 0xFF;
+ } else {
+ fga = cfg->fg_alpha[p_fg.a] & 0xFF;
+ }
+ } else {
+ fga = cfg->fg_alpha[cfg->fg_alpha_sel] & 0xFF;
+ }
+ if (cfg->bg_pixel_blending) {
+ if (cfg->bg_alpha_pix) {
+ bga = p_bg.a & 0xFF;
+ } else {
+ bga = cfg->bg_alpha[p_bg.a] & 0xFF;
+ }
+ } else {
+ bga = cfg->bg_alpha[cfg->bg_alpha_sel] & 0xFF;
+ }
+ bg = (bg * b + fg * a) / 0xFF;
+ if (bg > 0xFF) {
+ res->b = 0xFF;
+ } else {
+ res->b = bg;
+ }
+ bga = (bga * p + fga * q) / 0xFF;
+ if (bga > 0xFF) {
+ res->a |= 0xFF;
+ } else {
+ res->a |= bga;
+ }
+ /* G */
+ p = pl & 0xFF;
+ pl >>= 8;
+ q = ql & 0xFF;
+ ql >>= 8;
+ a = al & 0xFF;
+ al >>= 8;
+ b = bl & 0xFF;
+ bl >>= 8;
+ fg = p_fg.g;
+ bg = p_bg.g;
+ if (cfg->fg_pixel_blending) {
+ if (cfg->fg_alpha_pix) {
+ fga = (p_fg.a >> 8) & 0xFF;
+ } else {
+ fga = (cfg->fg_alpha[p_fg.a] >> 8) & 0xFF;
+ }
+ } else {
+ fga = (cfg->fg_alpha[cfg->fg_alpha_sel] >> 8) & 0xFF;
+ }
+ if (cfg->bg_pixel_blending) {
+ if (cfg->bg_alpha_pix) {
+ bga = (p_bg.a >> 8) & 0xFF;
+ } else {
+ bga = (cfg->bg_alpha[p_bg.a] >> 8) & 0xFF;
+ }
+ } else {
+ bga = (cfg->bg_alpha[cfg->bg_alpha_sel] >> 8) & 0xFF;
+ }
+ bg = (bg * b + fg * a) / 0xFF;
+ if (bg > 0xFF) {
+ res->g = 0xFF;
+ } else {
+ res->g = bg;
+ }
+ bga = (bga * p + fga * q) / 0xFF;
+ if (bga > 0xFF) {
+ res->a |= 0xFF << 8;
+ } else {
+ res->a |= bga << 8;
+ }
+ /* R */
+ p = pl & 0xFF;
+ pl >>= 8;
+ q = ql & 0xFF;
+ ql >>= 8;
+ a = al & 0xFF;
+ al >>= 8;
+ b = bl & 0xFF;
+ bl >>= 8;
+ fg = p_fg.r;
+ bg = p_bg.r;
+ if (cfg->fg_pixel_blending) {
+ if (cfg->fg_alpha_pix) {
+ fga = (p_fg.a >> 16) & 0xFF;
+ } else {
+ fga = (cfg->fg_alpha[p_fg.a] >> 16) & 0xFF;
+ }
+ } else {
+ fga = (cfg->fg_alpha[cfg->fg_alpha_sel] >> 16) & 0xFF;
+ }
+ if (cfg->bg_pixel_blending) {
+ if (cfg->bg_alpha_pix) {
+ bga = (p_bg.a >> 16) & 0xFF;
+ } else {
+ bga = (cfg->bg_alpha[p_bg.a] >> 16) & 0xFF;
+ }
+ } else {
+ bga = (cfg->bg_alpha[cfg->bg_alpha_sel] >> 16) & 0xFF;
+ }
+ bg = (bg * b + fg * a) / 0xFF;
+ if (bg > 0xFF) {
+ res->r = 0xFF;
+ } else {
+ res->r = bg;
+ }
+ bga = (bga * p + fga * q) / 0xFF;
+ if (bga > 0xFF) {
+ res->a |= 0xFF << 16;
+ } else {
+ res->a |= bga << 16;
+ }
+}
+
+static void blend_colorkey(DrawConfig *cfg, rgba p_bg, rgba p_fg, rgba *p)
+{
+ uint8_t r, g, b;
+
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_KEYEN) {
+ blend_alpha(cfg, p_bg, p_fg, p);
+ return ;
+ }
+ r = ((cfg->color_key & ~cfg->color_mask) >> 16) & 0xFF;
+ g = ((cfg->color_key & ~cfg->color_mask) >> 8) & 0xFF;
+ b = ((cfg->color_key & ~cfg->color_mask) >> 0) & 0xFF;
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_DIRCON) {
+ if ((p_fg.r & ~((cfg->color_mask >> 16) & 0xFF)) == r &&
+ (p_fg.g & ~((cfg->color_mask >> 8) & 0xFF)) == g &&
+ (p_fg.b & ~((cfg->color_mask >> 0) & 0xFF)) == b) {
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_KEYBLEN) {
+ p_fg.a = 1;
+ cfg->fg_pixel_blending = 0;
+ blend_alpha(cfg, p_bg, p_fg, p);
+ } else {
+ *p = p_bg;
+ }
+ } else {
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_KEYBLEN) {
+ p_fg.a = 0;
+ cfg->fg_pixel_blending = 0;
+ blend_alpha(cfg, p_bg, p_fg, p);
+ } else {
+ *p = p_fg;
+ }
+ }
+ } else {
+ if ((p_bg.r & ~((cfg->color_mask >> 16) & 0xFF)) == r &&
+ (p_bg.g & ~((cfg->color_mask >> 8) & 0xFF)) == g &&
+ (p_bg.b & ~((cfg->color_mask >> 0) & 0xFF)) == b) {
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_KEYBLEN) {
+ p_fg.a = 1;
+ cfg->fg_pixel_blending = 0;
+ blend_alpha(cfg, p_bg, p_fg, p);
+ } else {
+ *p = p_fg;
+ }
+ } else {
+ if (cfg->color_ctl & FIMD_WKEYCON0_CTL_KEYBLEN) {
+ p_fg.a = 0;
+ cfg->fg_pixel_blending = 0;
+ blend_alpha(cfg, p_bg, p_fg, p);
+ } else {
+ *p = p_bg;
+ }
+ }
+ }
+}
+
+static inline void putpixel_by_bpp(DrawConfig *cfg, int bpp)
+{
+ switch (bpp) {
+ case 8:
+ cfg->put_pixel = put_pixel8;
+ break;
+ case 15:
+ cfg->put_pixel = put_pixel15;
+ break;
+ case 16:
+ cfg->put_pixel = put_pixel16;
+ break;
+ case 24:
+ cfg->put_pixel = put_pixel24;
+ break;
+ case 32:
+ cfg->put_pixel = put_pixel32;
+ break;
+ default:
+ hw_error("s5pc210.fimd: unsupported BPP (%d)", bpp);
+ break;
+ }
+}
+
+static void s5pc210_fimd_update_irq(S5pc210fimdState *s)
+{
+ if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
+ qemu_irq_lower(s->irq[0]);
+ qemu_irq_lower(s->irq[1]);
+ qemu_irq_lower(s->irq[2]);
+ return;
+ }
+ if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
+ (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
+ qemu_irq_raise(s->irq[0]);
+ } else {
+ qemu_irq_lower(s->irq[0]);
+ }
+ if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
+ (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
+ qemu_irq_raise(s->irq[1]);
+ } else {
+ qemu_irq_lower(s->irq[1]);
+ }
+ if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
+ (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
+ qemu_irq_raise(s->irq[2]);
+ } else {
+ qemu_irq_lower(s->irq[2]);
+ }
+}
+
+static void s5pc210_update_resolution(S5pc210fimdState *s)
+{
+ /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
+ uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
+ FIMD_VIDTCON2_SIZE_MASK) + 1;
+ uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+ FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+ if (s->ifb == NULL || ds_get_width(s->console) != width ||
+ ds_get_height(s->console) != height) {
+ print_debug1("Resolution changed from %ux%u to %ux%u\n",
+ ds_get_width(s->console), ds_get_height(s->console), width, height);
+ qemu_console_resize(s->console, width, height);
+ s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE);
+ memset(s->ifb, 0, width * height * RGBA_SIZE);
+ s->invalidate = true;
+ }
+}
+
+static void s5pc210_fimd_update(void *opaque)
+{
+ S5pc210fimdState *s = (S5pc210fimdState *)opaque;
+ DrawConfig cfg;
+ int i, line, buf_id;
+ target_phys_addr_t fb_start_addr, fb_next_line_addr, inc_size, fb_len, x;
+ int lefttop_x, lefttop_y, rightbottom_x, rightbottom_y;
+ int width, height;
+ int first_line = -1, last_line = -1, fb_line_size;
+ uint8_t is_first_window = 1;
+ uint8_t *host_fb_addr, *host_fb_start_addr;
+ bool is_dirty = false;
+ ram_addr_t pd;
+ const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
+ const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
+ FIMD_VIDTCON2_SIZE_MASK) + 1;
+
+ if (!s || !s->console || !ds_get_bits_per_pixel(s->console)) {
+ return;
+ }
+
+ if (s->enabled == false) {
+ return;
+ }
+
+ memset(&cfg, 0, sizeof(cfg));
+ s5pc210_update_resolution(s);
+
+ for (i = 0; i < NUM_OF_WINDOWS; i++) {
+ if (s->window[i].wincon & FIMD_WINCON_ENWIN) {
+ cfg.fg_alpha_pix = 0;
+ s5pc210_parse_win_bppmode(&s->window[i], &cfg);
+ /* If we have mode with palletized color then we need to parse
+ palette color mode and set pixel-to-rgb conversion function
+ accordingly. */
+ if (cfg.is_palletized) {
+ uint32_t tmp = s5pc210_wxpal(s, i);
+ /* Different windows have different mapping WxPAL to palette
+ pixel format. This transform happens to unify them all. */
+ if (i < 2 && tmp < 7) {
+ tmp = 6 - tmp;
+ }
+ cfg.pixel_to_rgb = wxpal_to_rgb[tmp];
+ if (tmp == 7) {
+ cfg.fg_alpha_pix = 1;
+ }
+ }
+ cfg.put_pixel = put_rgba;
+ cfg.get_pixel = get_rgba;
+ cfg.bg_alpha_pix = 1;
+ cfg.color_mask = s->window[i].keycon[0] & FIMD_WKEYCON0_COMPKEY;
+ cfg.color_key = s->window[i].keycon[1];
+ cfg.color_ctl =
+ (s->window[i].keycon[0] >> FIMD_WKEYCON0_CTL_SHIFT) & 7;
+ if (i == 0) {
+ cfg.fg_alpha[0] = s->window[i].vidw_alpha[0];
+ cfg.fg_alpha[1] = s->window[i].vidw_alpha[1];
+ } else {
+ cfg.fg_alpha[0] =
+ unpack_by_4((s->window[i].vidosd[2] &
+ FIMD_VIDOSD_ALPHA_AEN0) >> FIMD_VIDOSD_AEN0_SHIFT) |
+ (s->window[i].vidw_alpha[0] & FIMD_VIDALPHA_ALPHA_MASK);
+ cfg.fg_alpha[1] =
+ unpack_by_4(s->window[i].vidosd[2] &
+ FIMD_VIDOSD_ALPHA_AEN1) | (s->window[i].vidw_alpha[0]
+ & FIMD_VIDALPHA_ALPHA_MASK);
+ }
+ cfg.bg_pixel_blending = 1;
+ cfg.fg_pixel_blending = s->window[i].wincon & FIMD_WINCON_BLD_PIX;
+ cfg.fg_alpha_sel = (s->window[i].wincon & FIMD_WINCON_ALPHA_SEL) >>
+ FIMD_WINCON_ALSEL_SHIFT;
+ cfg.palette = s->window[i].palette;
+ cfg.swap = (s->window[i].wincon & FIMD_WINCON_SWAP) >>
+ FIMD_WINCON_SWAP_SHIFT;
+ cfg.coef_q = coef_decode((s->window[i].blendeq >>
+ FIMD_BLENDEQ_COEF_Q) & FIMD_BLENDEQ_COEF_MASK);
+ cfg.coef_p = coef_decode((s->window[i].blendeq >>
+ FIMD_BLENDEQ_COEF_P) & FIMD_BLENDEQ_COEF_MASK);
+ cfg.coef_b = coef_decode((s->window[i].blendeq >>
+ FIMD_BLENDEQ_COEF_B) & FIMD_BLENDEQ_COEF_MASK);
+ cfg.coef_a = coef_decode((s->window[i].blendeq >>
+ FIMD_BLENDEQ_COEF_A) & FIMD_BLENDEQ_COEF_MASK);
+ if (is_first_window) {
+ cfg.blend = NULL;
+ } else {
+ cfg.blend = blend_colorkey;
+ }
+ is_first_window = 0;
+ if (s->window[i].winmap & FIMD_WINMAP_EN) {
+ cfg.map_color = s->window[i].winmap & FIMD_WINMAP_COLOR_MASK;
+ cfg.draw_line = draw_line_mapcolor;
+ }
+
+ /* At this point CFG is fully set up except WIDTH. We can proceed
+ with drawing. */
+ lefttop_x = (s->window[i].vidosd[0] >> FIMD_VIDOSD_HOR_SHIFT)
+ & FIMD_VIDOSD_COORD_MASK;
+ lefttop_y = (s->window[i].vidosd[0] >> FIMD_VIDOSD_VER_SHIFT)
+ & FIMD_VIDOSD_COORD_MASK;
+ rightbottom_x = (s->window[i].vidosd[1] >> FIMD_VIDOSD_HOR_SHIFT)
+ & FIMD_VIDOSD_COORD_MASK;
+ rightbottom_y = (s->window[i].vidosd[1] >> FIMD_VIDOSD_VER_SHIFT)
+ & FIMD_VIDOSD_COORD_MASK;
+ height = rightbottom_y - lefttop_y + 1;
+ width = rightbottom_x - lefttop_x + 1;
+ cfg.width = width;
+ buf_id = s5pc210_buffer_status(&s->window[i]);
+
+ fb_line_size = s->window[i].buf_size & FIMD_VIDWADD2_PAGEWIDTH;
+ fb_start_addr = s->window[i].buf_start[buf_id];
+ inc_size = (s->window[i].buf_size & FIMD_VIDWADD2_PAGEWIDTH) +
+ ((s->window[i].buf_size >> FIMD_VIDWADD2_OFFSIZE_SHIFT) &
+ FIMD_VIDWADD2_OFFSIZE);
+ fb_len = inc_size * height;
+
+ cpu_physical_sync_dirty_bitmap(fb_start_addr,
+ fb_start_addr + fb_len);
+ host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_len, 0);
+ if (!host_fb_addr) {
+ return;
+ }
+ if (fb_len != inc_size * height) {
+ cpu_physical_memory_unmap(host_fb_addr, fb_len, 0, 0);
+ return;
+ }
+
+ host_fb_start_addr = host_fb_addr;
+ for (line = 0; line < height; line++) {
+ fb_next_line_addr = fb_start_addr + fb_line_size;
+ for (x = fb_start_addr; x < fb_next_line_addr;
+ x += TARGET_PAGE_SIZE) {
+ pd = (cpu_get_physical_page_desc(x) & TARGET_PAGE_MASK) +
+ (x & ~TARGET_PAGE_MASK);
+ is_dirty = is_dirty ||
+ cpu_physical_memory_get_dirty(pd, VGA_DIRTY_FLAG);
+ }
+
+ if (s->invalidate || is_dirty) {
+ if (first_line == -1) {
+ first_line = line;
+ }
+ last_line = line;
+ cfg.draw_line(&cfg, host_fb_addr,
+ s->ifb + lefttop_x * RGBA_SIZE +
+ (lefttop_y + line) * global_width * RGBA_SIZE,
+ s->ifb + lefttop_x * RGBA_SIZE +
+ (lefttop_y + line) * global_width * RGBA_SIZE);
+ }
+ host_fb_addr += inc_size;
+ is_dirty = false;
+ fb_start_addr += inc_size;
+ }
+ cpu_physical_memory_unmap(host_fb_start_addr, fb_len, 0, 0);
+ fb_start_addr = s->window[i].buf_start[buf_id];
+ pd = (cpu_get_physical_page_desc(fb_start_addr) &
TARGET_PAGE_MASK)+
+ (fb_start_addr & ~TARGET_PAGE_MASK);
+ cpu_physical_memory_reset_dirty(pd, pd + inc_size * height,
+ VGA_DIRTY_FLAG);
+ }
+ }
+ /* Last pass: copy resulting image to QEMU_CONSOLE. */
+ if (first_line >= 0) {
+ uint8_t *d;
+ int bpp;
+
+ cfg.get_pixel = get_rgba;
+ bpp = ds_get_bits_per_pixel(s->console);
+ putpixel_by_bpp(&cfg, bpp);
+ bpp = (bpp + 1) >> 3;
+ d = ds_get_data(s->console);
+ for (line = first_line; line < last_line; line++) {
+ draw_line_copy(&cfg, s->ifb + global_width * line * RGBA_SIZE,
+ d + global_width * line * bpp);
+ }
+ dpy_update(s->console, 0, 0, global_width, global_height);
+ }
+ s->invalidate = false;
+ s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
+ if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
+ s5pc210_fimd_enable(s, false);
+ }
+ s5pc210_fimd_update_irq(s);
+}
+
+static void s5pc210_fimd_invalidate(void *opaque)
+{
+ S5pc210fimdState *s = (S5pc210fimdState *)opaque;
+ s->invalidate = true;
+}
+
+static void s5pc210_fimd_reset(DeviceState *d)
+{
+ S5pc210fimdState *s = container_of(d, S5pc210fimdState, busdev.qdev);
+ int i;
+ unsigned long begin = (unsigned long)s + offsetof(S5pc210fimdState,
vidcon);
+ unsigned long len = ((unsigned long)s + offsetof(S5pc210fimdState, window))
+ - begin;
+ s5pc210_fimd_trace_reset();
+
+ /* Set all display controller registers to 0 */
+ memset((void *)begin, 0, len);
+ for (i = 0; i < NUM_OF_WINDOWS; i++) {
+ memset(&s->window[i], 0, sizeof(S5pc210fimdWindow));
+ s->window[i].blendeq = 0xC2;
+ }
+
+ if (s->ifb != NULL) {
+ g_free(s->ifb);
+ }
+ s->ifb = NULL;
+
+ s->invalidate = true;
+ s5pc210_fimd_enable(s, false);
+ /* Some registers have non-zero initial values */
+ s->winchmap = 0x7D517D51;
+ s->colorgaincon = 0x10040100;
+ s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
+ s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
+ s->hueoffset = 0x01800080;
+}
+
+static void s5pc210_fimd_write(void *opaque, target_phys_addr_t offset,
+ uint64_t val, unsigned size)
+{
+ S5pc210fimdState *s = (S5pc210fimdState *)opaque;
+ int w, i;
+
+ print_debug2("write offset 0x%08x, value=%ld(0x%08lx)\n", offset, val,
val);
+
+ if (offset == FIMD_VIDCON0) {
+ if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
+ s5pc210_fimd_enable(s, true);
+ } else {
+ if ((val & FIMD_VIDCON0_ENVID) == 0) {
+ s5pc210_fimd_enable(s, false);
+ }
+ }
+ s->vidcon[0] = val;
+ } else if (offset == FIMD_VIDCON1) {
+ /* Leave read-only bits as is */
+ val = (val & (~FIMD_VIDCON1_ROMASK)) |
+ (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
+ s->vidcon[1] = val;
+ } else if (offset >= FIMD_VIDCON2 && offset <= FIMD_VIDCON3) {
+ s->vidcon[(offset) >> 2] = val;
+ } else if (offset >= 0x010 && offset <= 0x01C) {
+ s->vidtcon[(offset - 0x010) >> 2] = val;
+ } else if (offset >= 0x020 && offset <= 0x030) {
+ w = (offset - 0x020) >> 2;
+ val = (val & ~FIMD_WINCON_ROMASK) |
+ (s->window[w].wincon & FIMD_WINCON_ROMASK);
+ s5pc210_fimd_trace_bppmode(&s->window[w], w, val);
+ switch (val & FIMD_WINCON_BUFSELECT) {
+ case FIMD_WINCON_BUF0_SEL:
+ val &= ~FIMD_WINCON_BUFSTATUS;
+ break;
+ case FIMD_WINCON_BUF1_SEL:
+ val = (val & ~FIMD_WINCON_BUFSTATUS_H) |
+ FIMD_WINCON_BUFSTATUS_L;
+ break;
+ case FIMD_WINCON_BUF2_SEL:
+ if (val & FIMD_WINCON_BUFMODE) {
+ val = (val & ~FIMD_WINCON_BUFSTATUS_L) |
+ FIMD_WINCON_BUFSTATUS_H;
+ }
+ break;
+ default:
+ break;
+ }
+ s->window[w].wincon = val;
+ } else if (offset == 0x034) {
+ s->shadowcon = val;
+ } else if (offset == 0x03C) {
+ s->winchmap = val;
+ } else if (offset >= 0x040 && offset <= 0x088) {
+ w = (offset - 0x040) >> 4;
+ i = ((offset - 0x040) & 0xF) >> 2;
+ if (i == 3 && w != 1 && w != 2) {
+ print_error("Bad write offset 0x%08x\n", offset);
+ }
+ s->window[w].vidosd[i] = val;
+ } else if (offset >= 0x0A0 && offset <= 0x0C4) {
+ w = (offset - 0x0A0) >> 3;
+ i = ((offset - 0x0A0) >> 2) & 1;
+ s->window[w].buf_start[i] = val;
+ } else if (offset >= 0x0D0 && offset <= 0x0F4) {
+ w = (offset - 0x0D0) >> 3;
+ i = ((offset - 0x0D0) >> 2) & 1;
+ s->window[w].buf_end[i] = val;
+ } else if (offset >= 0x100 && offset <= 0x110) {
+ s->window[(offset - 0x100) >> 2].buf_size = val;
+ } else if (offset == 0x130) {
+ s->vidintcon[0] = val;
+ } else if (offset == 0x134) {
+ s->vidintcon[1] &= ~(val & 7);
+ s5pc210_fimd_update_irq(s);
+ } else if (offset >= 0x140 && offset <= 0x15C) {
+ w = ((offset - 0x140) >> 3) + 1;
+ i = ((offset - 0x140) >> 2) & 1;
+ s->window[w].keycon[i] = val;
+ } else if (offset >= 0x160 && offset <= 0x16C) {
+ w = ((offset - 0x160) >> 2) + 1;
+ s->window[w].keyalpha = val;
+ } else if (offset == 0x170) {
+ s->dithmode = val;
+ } else if (offset >= 0x180 && offset <= 0x190) {
+ if (val & FIMD_WINMAP_EN) {
+ s->invalidate = true;
+ s5pc210_fimd_update(s);
+ }
+ s->window[(offset - 0x180) >> 2].winmap = val;
+ } else if (offset >= 0x19C && offset <= 0x1A0) {
+ s->wpalcon[(offset - 0x19C) >> 2] = val;
+ } else if (offset == 0x1A4) {
+ val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon &
FIMD_TRIGCON_ROMASK);
+ s->trigcon = val;
+ } else if (offset >= 0x1B0 && offset <= 0x1BC) {
+ s->i80ifcon[(offset - 0x1B0) >> 2] = val;
+ } else if (offset == 0x1C0) {
+ s->colorgaincon = val;
+ } else if (offset >= 0x1D0 && offset <= 0x1D4) {
+ s->ldi_cmdcon[(offset - 0x1D0) >> 2] = val;
+ } else if (offset >= 0x1E0 && offset <= 0x1E8) {
+ i = (offset - 0x1E0) >> 2;
+ if (i != 2) {
+ s->sifccon[i] = val;
+ }
+ } else if (offset >= 0x1EC && offset <= 0x1F8) {
+ i = (offset - 0x1EC) >> 2;
+ s->huecoef_cr[i] = val;
+ } else if (offset >= 0x1FC && offset <= 0x208) {
+ i = (offset - 0x1FC) >> 2;
+ s->huecoef_cb[i] = val;
+ } else if (offset == 0x20C) {
+ s->hueoffset = val;
+ } else if (offset >= 0x21C && offset <= 0x240) {
+ w = ((offset - 0x21C) >> 3);
+ i = ((offset - 0x21C) >> 2) & 1;
+ s->window[w].vidw_alpha[i] = val;
+ } else if (offset >= 0x244 && offset <= 0x250) {
+ s->window[(offset - 0x244) >> 2].blendeq = val;
+ } else if (offset == 0x260) {
+ s->blendcon = val;
+ } else if (offset >= 0x264 && offset <= 0x274) {
+ s->window[(offset - 0x264) >> 2].rtqoscon = val;
+ } else if (offset == 0x27C) {
+ s->dualrgb = val;
+ } else if (offset >= 0x280 && offset <= 0x2AC) {
+ s->i80ifcmd[(offset - 0x280) >> 2] = val;
+ } else if (offset >= 0x40A0 && offset <= 0x40C0) {
+ if (offset & 0x0004) {
+ print_error("bad write offset 0x%08x\n", offset);
+ }
+ s->window[(offset - 0x40A0) >> 3].shadow_buf_start = val;
+ } else if (offset >= 0x40D0 && offset <= 0x40F0) {
+ if (offset & 0x0004) {
+ print_error("bad write offset 0x%08x\n", offset);
+ }
+ s->window[(offset - 0x40D0) >> 3].shadow_buf_end = val;
+ } else if (offset >= 0x4100 && offset <= 0x4110) {
+ s->window[(offset - 0x4100) >> 2].shadow_buf_size = val;
+ } else if (offset >= 0x2400 && offset <= 0x37FC) {
+ w = (offset - 0x2400) >> 10;
+ i = ((offset - 0x2400) >> 2) & 0xFF;
+ s->window[w].palette[i] = val;
+ } else if (offset >= 0x0400 && offset <= 0x0BFC) {
+ w = (offset - 0x0400) >> 10;
+ i = ((offset - 0x0400) >> 2) & 0xFF;
+ s->window[w].palette[i] = val;
+ } else {
+ print_error("bad write offset 0x%08x\n", offset);
+ }
+}
+
+static uint64_t s5pc210_fimd_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ S5pc210fimdState *s = (S5pc210fimdState *)opaque;
+ int w, i;
+
+ print_debug2("read offset 0x%08x\n", offset);
+
+ if (offset <= 0x00C) {
+ return s->vidcon[(offset) >> 2];
+ } else if (offset >= 0x010 && offset <= 0x01C) {
+ return s->vidtcon[(offset - 0x010) >> 2];
+ } else if (offset >= 0x020 && offset <= 0x030) {
+ return s->window[(offset - 0x020) >> 2].wincon;
+ } else if (offset == 0x034) {
+ return s->shadowcon;
+ } else if (offset == 0x03C) {
+ return s->winchmap;
+ } else if (offset >= 0x040 && offset <= 0x088) {
+ w = (offset - 0x040) >> 4;
+ i = ((offset - 0x040) & 0xF) >> 2;
+ if (i == 3 && w != 1 && w != 2) {
+ goto return_error;
+ }
+ return s->window[w].vidosd[i];
+ } else if (offset >= 0x0A0 && offset <= 0x0C4) {
+ w = (offset - 0x0A0) >> 3;
+ i = ((offset - 0x0A0) >> 2) & 1;
+ return s->window[w].buf_start[i];
+ } else if (offset >= 0x0D0 && offset <= 0x0F4) {
+ w = (offset - 0x0D0) >> 3;
+ i = ((offset - 0x0D0) >> 2) & 1;
+ return s->window[w].buf_end[i];
+ } else if (offset >= 0x100 && offset <= 0x110) {
+ return s->window[(offset - 0x100) >> 2].buf_size;
+ } else if (offset >= 0x130 && offset <= 0x134) {
+ return s->vidintcon[(offset - 0x130) >> 2];
+ } else if (offset >= 0x140 && offset <= 0x15C) {
+ w = ((offset - 0x140) >> 3) + 1;
+ i = ((offset - 0x140) >> 2) & 1;
+ return s->window[w].keycon[i];
+ } else if (offset >= 0x160 && offset <= 0x16C) {
+ w = ((offset - 0x160) >> 2) + 1;
+ return s->window[w].keyalpha;
+ } else if (offset == 0x170) {
+ return s->dithmode;
+ } else if (offset >= 0x180 && offset <= 0x190) {
+ return s->window[(offset - 0x180) >> 2].winmap;
+ } else if (offset >= 0x19C && offset <= 0x1A0) {
+ return s->wpalcon[(offset - 0x19C) >> 2];
+ } else if (offset == 0x1A4) {
+ return s->trigcon;
+ } else if (offset >= 0x1B0 && offset <= 0x1BC) {
+ return s->i80ifcon[(offset - 0x1B0) >> 2];
+ } else if (offset == 0x1C0) {
+ return s->colorgaincon;
+ } else if (offset >= 0x1D0 && offset <= 0x1D4) {
+ return s->ldi_cmdcon[(offset - 0x1D0) >> 2];
+ } else if (offset >= 0x1E0 && offset <= 0x1E8) {
+ i = (offset - 0x1E0) >> 2;
+ return s->sifccon[i];
+ } else if (offset >= 0x1EC && offset <= 0x1F8) {
+ i = (offset - 0x1EC) >> 2;
+ return s->huecoef_cr[i];
+ } else if (offset >= 0x1FC && offset <= 0x208) {
+ i = (offset - 0x1FC) >> 2;
+ return s->huecoef_cb[i];
+ } else if (offset == 0x20C) {
+ return s->hueoffset;
+ } else if (offset >= 0x21C && offset <= 0x240) {
+ w = ((offset - 0x21C) >> 3);
+ i = ((offset - 0x21C) >> 2) & 1;
+ return s->window[w].vidw_alpha[i];
+ } else if (offset >= 0x244 && offset <= 0x250) {
+ return s->window[(offset - 0x244) >> 2].blendeq;
+ } else if (offset == 0x260) {
+ return s->blendcon;
+ } else if (offset >= 0x264 && offset <= 0x274) {
+ return s->window[(offset - 0x264) >> 2].rtqoscon;
+ } else if (offset == 0x27C) {
+ return s->dualrgb;
+ } else if (offset >= 0x280 && offset <= 0x2AC) {
+ return s->i80ifcmd[(offset - 0x280) >> 2];
+ } else if (offset >= 0x40A0 && offset <= 0x40C0) {
+ if (offset & 0x0004) {
+ goto return_error;
+ }
+ return s->window[(offset - 0x40A0) >> 3].shadow_buf_start;
+ } else if (offset >= 0x40D0 && offset <= 0x40F0) {
+ if (offset & 0x0004) {
+ goto return_error;
+ }
+ return s->window[(offset - 0x40D0) >> 3].shadow_buf_end;
+ } else if (offset >= 0x4100 && offset <= 0x4110) {
+ return s->window[(offset - 0x4100) >> 2].shadow_buf_size;
+ } else if (offset >= 0x2400 && offset <= 0x37FC) {
+ w = (offset - 0x2400) >> 10;
+ i = ((offset - 0x2400) >> 2) & 0xFF;
+ return s->window[w].palette[i];
+ } else if (offset >= 0x0400 && offset <= 0x0BFC) {
+ /* Palete aliases for win 0,1 */
+ w = (offset - 0x0400) >> 10;
+ i = ((offset - 0x0400) >> 2) & 0xFF;
+ return s->window[w].palette[i];
+ }
+return_error:
+ print_error("bad read offset 0x%08x\n", offset);
+ return 0xBAADBAAD;
+}
+
+static const MemoryRegionOps s5pc210_fimd_mmio_ops = {
+ .read = s5pc210_fimd_read,
+ .write = s5pc210_fimd_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int s5pc210_fimd_load(void *opaque, int version_id)
+{
+ S5pc210fimdState *s = (S5pc210fimdState *)opaque;
+
+ if (version_id != 1) {
+ return -EINVAL;
+ }
+
+ /* Redraw the whole screen */
+ s5pc210_update_resolution(s);
+ s5pc210_fimd_invalidate(s);
+ s5pc210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
+ FIMD_VIDCON0_ENVID_MASK);
+ return 0;
+}
+
+static const VMStateDescription s5pc210_fimd_window_vmstate = {
+ .name = "s5pc210.fimd_window",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(wincon, S5pc210fimdWindow),
+ VMSTATE_UINT32_ARRAY(vidosd, S5pc210fimdWindow, 4),
+ VMSTATE_UINT32_ARRAY(buf_start, S5pc210fimdWindow, 3),
+ VMSTATE_UINT32_ARRAY(buf_end, S5pc210fimdWindow, 3),
+ VMSTATE_UINT32(buf_size, S5pc210fimdWindow),
+ VMSTATE_UINT32_ARRAY(keycon, S5pc210fimdWindow, 2),
+ VMSTATE_UINT32(keyalpha, S5pc210fimdWindow),
+ VMSTATE_UINT32(winmap, S5pc210fimdWindow),
+ VMSTATE_UINT32_ARRAY(vidw_alpha, S5pc210fimdWindow, 2),
+ VMSTATE_UINT32(blendeq, S5pc210fimdWindow),
+ VMSTATE_UINT32(rtqoscon, S5pc210fimdWindow),
+ VMSTATE_UINT32_ARRAY(palette, S5pc210fimdWindow, 256),
+ VMSTATE_UINT32(shadow_buf_start, S5pc210fimdWindow),
+ VMSTATE_UINT32(shadow_buf_end, S5pc210fimdWindow),
+ VMSTATE_UINT32(shadow_buf_size, S5pc210fimdWindow),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription s5pc210_fimd_vmstate = {
+ .name = "s5pc210.fimd",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .post_load = s5pc210_fimd_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(vidcon, S5pc210fimdState, 4),
+ VMSTATE_UINT32_ARRAY(vidtcon, S5pc210fimdState, 4),
+ VMSTATE_UINT32(shadowcon, S5pc210fimdState),
+ VMSTATE_UINT32(winchmap, S5pc210fimdState),
+ VMSTATE_UINT32_ARRAY(vidintcon, S5pc210fimdState, 2),
+ VMSTATE_UINT32(dithmode, S5pc210fimdState),
+ VMSTATE_UINT32_ARRAY(wpalcon, S5pc210fimdState, 2),
+ VMSTATE_UINT32(trigcon, S5pc210fimdState),
+ VMSTATE_UINT32_ARRAY(i80ifcon, S5pc210fimdState, 4),
+ VMSTATE_UINT32(colorgaincon, S5pc210fimdState),
+ VMSTATE_UINT32_ARRAY(ldi_cmdcon, S5pc210fimdState, 2),
+ VMSTATE_UINT32_ARRAY(sifccon, S5pc210fimdState, 3),
+ VMSTATE_UINT32_ARRAY(huecoef_cr, S5pc210fimdState, 4),
+ VMSTATE_UINT32_ARRAY(huecoef_cb, S5pc210fimdState, 4),
+ VMSTATE_UINT32(hueoffset, S5pc210fimdState),
+ VMSTATE_UINT32(blendcon, S5pc210fimdState),
+ VMSTATE_UINT32(dualrgb, S5pc210fimdState),
+ VMSTATE_UINT32_ARRAY(i80ifcmd, S5pc210fimdState, 12),
+ VMSTATE_STRUCT_ARRAY(window, S5pc210fimdState, 5, 1,
+ s5pc210_fimd_window_vmstate, S5pc210fimdWindow),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int s5pc210_fimd_init(SysBusDevice *dev)
+{
+ S5pc210fimdState *s = FROM_SYSBUS(S5pc210fimdState, dev);
+
+ s->ifb = NULL;
+
+ sysbus_init_irq(dev, &s->irq[0]);
+ sysbus_init_irq(dev, &s->irq[1]);
+ sysbus_init_irq(dev, &s->irq[2]);
+
+ memory_region_init_io(&s->iomem, &s5pc210_fimd_mmio_ops, s, "s5pc210.fimd",
+ FIMD_REGS_SIZE);
+ sysbus_init_mmio_region(dev, &s->iomem);
+ s->console = graphic_console_init(s5pc210_fimd_update,
+ s5pc210_fimd_invalidate, NULL, NULL, s);
+
+ return 0;
+}
+
+static SysBusDeviceInfo s5pc210_fimd_info = {
+ .init = s5pc210_fimd_init,
+ .qdev.name = "s5pc210.fimd",
+ .qdev.size = sizeof(S5pc210fimdState),
+ .qdev.vmsd = &s5pc210_fimd_vmstate,
+ .qdev.reset = s5pc210_fimd_reset,
+};
+
+static void s5pc210_fimd_register_devices(void)
+{
+ sysbus_register_withprop(&s5pc210_fimd_info);
+}
+
+device_init(s5pc210_fimd_register_devices)
--
1.7.4.1
- Re: [Qemu-devel] [PATCH 09/14] hw/lan9118.c: Basic byte/word/long access support., (continued)
[Qemu-devel] [PATCH 08/14] ARM: s5pc210: Boot secondary CPU., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 12/14] SD card: add query function to check wether SD card currently ready to recieve data Before executing data transfer to card, we must check that previously issued command wasn't a simple query command (for ex. CMD13), which doesn't require data transfer. Currently, we only can aquire information about whether SD card is in sending data state or not. This patch allows us to query wether previous command was data write command and it was successfully accepted by card (meaning that SD card in recieving data state)., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 06/14] hw/arm_gic.c: lower IRQ only on changing of enable bit., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 14/14] s5pc210: Switch to sysbus_init_mmio., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 07/14] ARM: s5pc210: MCT support., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 10/14] hw/s5pc210.c: Add lan9118 support to SMDK board., Evgeny Voevodin, 2011/12/07
[Qemu-devel] [PATCH 11/14] ARM: s5pc210: added s5pc210 display controller device (FIMD),
Evgeny Voevodin <=
[Qemu-devel] [PATCH 13/14] ARM: s5pc210: added SD/MMC host controller (ver. 2.0 compliant) implementation, Evgeny Voevodin, 2011/12/07
Re: [Qemu-devel] [PATCH 00/14] ARM: Samsung S5PC210-based boards support., Peter Maydell, 2011/12/07