diff options
Diffstat (limited to 'board/st/u8500/mcde_display_image.c')
-rw-r--r-- | board/st/u8500/mcde_display_image.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/board/st/u8500/mcde_display_image.c b/board/st/u8500/mcde_display_image.c new file mode 100644 index 000000000..483b09cc1 --- /dev/null +++ b/board/st/u8500/mcde_display_image.c @@ -0,0 +1,299 @@ +/* +* Copyright (C) ST-Ericsson SA 2010 +* +* Author: Torbjorn Svensson <torbjorn.x.svensson@stericsson.com> +* for ST-Ericsson. +* +* License terms: GNU General Public License (GPL), version 2. +*/ + +#include <common.h> +#include <command.h> +#include <linux/err.h> +#include <part.h> +#include <mmc.h> +#include <bmp_layout.h> +#include "mcde.h" +#include "mcde_display.h" + +#define DEBUG_THIS_FILE 0 +#define dbg_printk(format, arg...) \ + if (DEBUG_THIS_FILE) \ + printf("mcde: " format, ##arg) + +/* bmp compression constants */ +#define BI_RGB 0 +#define BI_RLE8 1 /* RLE 8-bit/pixel */ +#define BI_RLE4 2 /* RLE 4-bit/pixel */ +#define BI_BITFIELDS 3 + +extern struct mcde_display_device main_display; + +static uint32_t read_unaligned32(uint32_t *val) +{ + uint32_t ret; + memcpy(&ret, val, sizeof(int32_t)); + return ret; +} + +static void copy_indexed(u16 *bmp_dst, u8 *bmp_start, + int dst_pitch, int src_pitch, + u32 width, u32 height, u8 *palette) +{ + /* + * Copy image from flash area to overlay area and + * convert format from 8-bit indexed to rgb565. + */ + int i; + int j; + int o; + int pad; + u16 val16; + u32 w; + u8 r; + u8 g; + u8 b; + u8 *bmp_src; + + pad = (dst_pitch - 2 * width) / 2; + + /* expanding 8 bit indexes to 16 bit rgb */ + for (i = height - 1, o = 0; i >= 0; i--) { + bmp_src = (u8 *)(bmp_start + i * src_pitch); + for (j = 0; j < width; j++) { + w = bmp_src[j]; /* get index */ + w <<= 2; /* make offset */ + w += (u32)palette; /* make address */ + r = *((u8 *)w++); + g = *((u8 *)w++); + b = *((u8 *)w); + val16 = r >> 3; + val16 |= (g >> 2) << 5; + val16 |= (b >> 3) << 11; + bmp_dst[o++] = val16; + } + o += pad; + } +} + +static void copy_rgb565(u8 *bmp_dst, u8 *bmp_start, + int dst_pitch, int src_pitch, + u32 width, u32 height) +{ + int i; + u8 *bmp_src; + + /* point after source data */ + bmp_src = (u8 *)(bmp_start + (height * src_pitch)); + for (i = 0; i < height; i++) { + bmp_src -= src_pitch; + memcpy(bmp_dst, bmp_src, src_pitch); + bmp_dst += dst_pitch; + } +} + +static void copy_rgb(u16 *bmp_dst, u8 *bmp_start, + int dst_pitch, int src_pitch, + u32 width, u32 height, u32 bitspp) +{ + /* + * Copy image from flash area to overlay area and + * convert format from (a)rgb888(8) to rgb565. + */ + int i; + int j; + int o; + int pad; + u16 val16; + u8 r; + u8 g; + u8 b; + u8 *bmp_src; + u32 src_inc = bitspp / 8; + + pad = (dst_pitch - 2 * width) / 2; + + /* convert to 16 bit */ + for (i = height - 1, o = 0; i >= 0; i--) { + bmp_src = (u8 *)(bmp_start + i * src_pitch); + for (j = 0; j < (width * src_inc); j += src_inc) { + r = bmp_src[j]; + g = bmp_src[j + 1]; + b = bmp_src[j + 2]; + val16 = r >> 3; + val16 |= (g >> 2) << 5; + val16 |= (b >> 3) << 11; + bmp_dst[o++] = val16; + } + o += pad; + } +} + +int mcde_display_image(struct mcde_chnl_state *chnl) +{ + int err = 0; + struct mmc *emmc_dev; + u32 address = (CONFIG_SYS_VIDEO_FB_ADRS + 2 * + CONFIG_SYS_DISPLAY_NATIVE_X_RES * + CONFIG_SYS_DISPLAY_NATIVE_Y_RES); /* after frame buffer */ + u8 *bmp_start; + struct bmp_header *bmp_header; + u32 bmp_offset; + u32 dib_bytesz; + u32 dib_width; + u32 dib_height; + u32 dib_compression; + u16 dib_bitspp; + int src_pitch; + int dst_pitch; + u32 dib_header_size; + u8 *palette; + u32 palette_size; + u8 *bmp_src; + u8 *bmp_dst; + u8 *ovly_mem = (u8 *)CONFIG_SYS_VIDEO_FB_ADRS; /* frame buffer */ + struct mcde_ovly_state *ovly; + u32 xpos = 0; + u32 ypos = 0; + + dbg_printk("%s: Enter\n", __func__); + + emmc_dev = find_mmc_device(CONFIG_EMMC_DEV_NUM); + if (emmc_dev == NULL) { + printf("mcde_display_image: emmc not found.\n"); + return -ENODEV; + } + + if (toc_load_toc_entry(&emmc_dev->block_dev, MCDE_TOC_SPLASH_NAME, 0, + 0, address)) { + printf("mcde_display_image: no splash image found.\n"); + return -ENOENT; + } + + /* get bmp_image */ + bmp_start = (u8 *)address; + dbg_printk("%s: bmp start = 0x%p\n", __func__, (void *)bmp_start); + + /* check BMP magic */ + bmp_header = (struct bmp_header *)bmp_start; + if (bmp_header->signature[0] != 'B' || + bmp_header->signature[1] != 'M') { + printf("%s: unsupported filetype, must be BMP\n", __func__); + return -EILSEQ; + } + + /* get offset to bitmap-data from the BMP header */ + bmp_offset = read_unaligned32(&bmp_header->data_offset); + dbg_printk("bmp filesz = %d\n", + read_unaligned32(&bmp_header->file_size)); + dbg_printk("bmp offset = %d\n", bmp_offset); + + dib_width = read_unaligned32((uint32_t *)&bmp_header->width); + dib_height = read_unaligned32((uint32_t *)&bmp_header->height); + dib_bytesz = read_unaligned32(&bmp_header->image_size); + dib_bitspp = bmp_header->bit_count; + dib_header_size = read_unaligned32(&bmp_header->size); + dbg_printk("dib header_sz = %d\n", dib_header_size); + dbg_printk("dib width = %d\n", dib_width); + dbg_printk("dib height = %d\n", dib_height); + dbg_printk("dib nplanes = %d\n", bmp_header->planes); + dbg_printk("dib bitspp = %d\n", dib_bitspp); + dib_compression = read_unaligned32(&bmp_header->compression); + dbg_printk("dib compress_type = %d\n", dib_compression); + dbg_printk("dib dib_bytesz = %d\n", dib_bytesz); + + /* calculate palette address */ + palette = ((u8 *)&bmp_header->size + dib_header_size); + palette_size = ((bmp_start + bmp_offset) - palette); + dbg_printk("palette size = %d\n", palette_size); + /* if same as image start: no palette */ + if (palette_size == 0) + palette = NULL; + dbg_printk("palette = 0x%08x\n", (u32)palette); + + /* check validity */ + if ((dib_width > main_display.native_x_res) || + (dib_height > main_display.native_y_res)) { + printf("%s: image to large, must be [%d,%d] or smaller\n", + __func__, main_display.native_x_res, + main_display.native_y_res); + err++; + } + if (bmp_header->planes != 1) { + printf("%s: unsupported nplanes, must be 1\n", __func__); + err++; + } + + src_pitch = dib_width * dib_bitspp / 8; + src_pitch = (src_pitch + 3) >> 2; /* pad to 32-bit boundary */ + src_pitch <<= 2; + dbg_printk("src_pitch=%d\n", src_pitch); + + if (dib_compression != BI_RGB && dib_compression != BI_BITFIELDS) + err++; + + if (err != 0) + return -EINVAL; + + /* set new pitch */ + dst_pitch = dib_width * 16 / 8; /* dest is 16 bpp */ + dst_pitch = (dst_pitch + 7) >> 3; /* pad to 64-bit boundary */ + dst_pitch <<= 3; + dbg_printk("dst_pitch=%d\n", dst_pitch); + + /* image is stored upside-down in the file */ + bmp_dst = ovly_mem; + bmp_src = (u8 *)(bmp_start + bmp_offset); + dbg_printk("bmp copy dst=0x%08x, src=0x%08x, len=%d\n", + (uint32_t)bmp_dst, (uint32_t)bmp_src, dib_bytesz); + + switch (dib_bitspp) { + case 8: + copy_indexed((u16 *)bmp_dst, bmp_src, dst_pitch, src_pitch, + dib_width, dib_height, palette); + break; + case 16: + copy_rgb565(bmp_dst, bmp_src, dst_pitch, src_pitch, + dib_width, dib_height); + break; + case 24: + case 32: + copy_rgb((u16 *)bmp_dst, bmp_src, dst_pitch, src_pitch, + dib_width, dib_height, dib_bitspp); + break; + default: + printf("%s: unsupported bitspp=%d\n", __func__, dib_bitspp); + return -EINVAL; + } + dbg_printk("%s: image OK\n", __func__); + + ovly = mcde_ovly_get(chnl); + if (IS_ERR(ovly)) { + err = PTR_ERR(ovly); + printf("%s: Failed to get channel\n", __func__); + return -err; + } + dbg_printk("ovly=%p ovly_mem=%p\n", (void *)ovly, (void *)ovly_mem); + mcde_ovly_set_source_buf(ovly, (u32)ovly_mem); + mcde_ovly_set_source_info(ovly, dst_pitch, + main_display.default_pixel_format); + mcde_ovly_set_source_area(ovly, 0, 0, dib_width, dib_height); + + if (dib_width == main_display.native_x_res) + xpos = 0; + else + xpos = (main_display.native_x_res - dib_width) / 2; + + if (dib_height == main_display.native_y_res) + ypos = 0; + else + ypos = (main_display.native_y_res - dib_height) / 2; + + mcde_ovly_set_dest_pos(ovly, xpos, ypos, 0); + + mcde_ovly_apply(ovly); + mcde_chnl_update(chnl); + + return mcde_turn_on_display(); +} + |