Merge "app: aboot: support RLE24 compressed logo image"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index a55c020..90b2b67 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -2779,146 +2779,155 @@
fastboot_okay("");
}
-struct fbimage* splash_screen_flash();
+static uint8_t logo_header[LOGO_IMG_HEADER_SIZE];
-int splash_screen_check_header(struct fbimage *logo)
+int splash_screen_check_header(logo_img_header *header)
{
- if (memcmp(logo->header.magic, LOGO_IMG_MAGIC, 8))
+ if (memcmp(header->magic, LOGO_IMG_MAGIC, 8))
return -1;
- if (logo->header.width == 0 || logo->header.height == 0)
+ if (header->width == 0 || header->height == 0)
return -1;
return 0;
}
-struct fbimage* splash_screen_flash()
+int splash_screen_flash()
{
struct ptentry *ptn;
struct ptable *ptable;
+ struct logo_img_header *header;
struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = NULL;
-
-
- logo = (struct fbimage *) malloc(ROUNDUP(page_size, sizeof(struct fbimage)));
- ASSERT(logo);
ptable = flash_get_ptable();
if (ptable == NULL) {
- dprintf(CRITICAL, "ERROR: Partition table not found\n");
- goto err;
+ dprintf(CRITICAL, "ERROR: Partition table not found\n");
+ return -1;
}
+
ptn = ptable_find(ptable, "splash");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: splash Partition not found\n");
- goto err;
+ return -1;
}
-
- if (flash_read(ptn, 0,(unsigned int *) logo, sizeof(logo->header))) {
+ if (flash_read(ptn, 0, (void *)logo_header, LOGO_IMG_HEADER_SIZE)) {
dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
- goto err;
+ return -1;
}
- if (splash_screen_check_header(logo)) {
+ header = (struct logo_img_header *)logo_header;
+ if (splash_screen_check_header(header)) {
dprintf(CRITICAL, "ERROR: Boot image header invalid\n");
- goto err;
+ return -1;
}
fb_display = fbcon_display();
if (fb_display) {
- if ((logo->header.width != fb_display->width) || (logo->header.height != fb_display->height)) {
- dprintf(CRITICAL, "Logo config doesn't match with fb config. Fall back to default logo\n");
- goto err;
+ if (header->type && (header->blocks != 0)) { // RLE24 compressed data
+ uint8_t *base = (uint8_t *) fb_display->base + LOGO_IMG_OFFSET;
+
+ /* if the logo is full-screen size, remove "fbcon_clear()" */
+ if ((header->width != fb_display->width)
+ || (header->height != fb_display->height))
+ fbcon_clear();
+
+ if (flash_read(ptn + LOGO_IMG_HEADER_SIZE, 0,
+ (uint32_t *)base,
+ (header->blocks * 512))) {
+ dprintf(CRITICAL, "ERROR: Cannot read splash image from partition\n");
+ return -1;
+ }
+ fbcon_extract_to_screen(header, base);
+ return 0;
}
+
+ if ((header->width != fb_display->width) || (header->height != fb_display->height)) {
+ dprintf(CRITICAL, "Logo config doesn't match with fb config. Fall back default logo\n");
+ return -1;
+ }
+
uint8_t *base = (uint8_t *) fb_display->base;
- if (flash_read(ptn + sizeof(logo->header), 0,
- base,
- ((((logo->header.width * logo->header.height * fb_display->bpp/8) + 511) >> 9) << 9))) {
+ if (flash_read(ptn + LOGO_IMG_HEADER_SIZE, 0,
+ (uint32_t *)base,
+ ((((header->width * header->height * fb_display->bpp/8) + 511) >> 9) << 9))) {
fbcon_clear();
dprintf(CRITICAL, "ERROR: Cannot read splash image from partition\n");
- goto err;
+ return -1;
}
- logo->image = base;
}
- return logo;
-
-err:
- free(logo);
- return NULL;
+ return 0;
}
-struct fbimage* splash_screen_mmc()
+int splash_screen_mmc()
{
int index = INVALID_PTN;
unsigned long long ptn = 0;
struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = NULL;
- uint32_t blocksize;
- uint32_t readsize;
- uint32_t logosize;
- uint32_t ptn_size;
+ struct logo_img_header *header;
index = partition_get_index("splash");
if (index == 0) {
dprintf(CRITICAL, "ERROR: splash Partition table not found\n");
- return NULL;
+ return -1;
}
ptn = partition_get_offset(index);
if (ptn == 0) {
dprintf(CRITICAL, "ERROR: splash Partition invalid\n");
- return NULL;
+ return -1;
}
- ptn_size = partition_get_size(index);
- blocksize = mmc_get_device_blocksize();
- logosize = ROUNDUP(sizeof(logo->header), blocksize);
-
- logo = (struct fbimage *)memalign(CACHE_LINE, ROUNDUP(logosize, CACHE_LINE));
- ASSERT(logo);
-
- if (mmc_read(ptn, (uint32_t *) logo, logosize)) {
+ if (mmc_read(ptn, (uint32_t *)logo_header, LOGO_IMG_HEADER_SIZE)) {
dprintf(CRITICAL, "ERROR: Cannot read splash image header\n");
- goto err;
+ return -1;
}
- if (splash_screen_check_header(logo)) {
+ header = (struct logo_img_header *)logo_header;
+ if (splash_screen_check_header(header)) {
dprintf(CRITICAL, "ERROR: Splash image header invalid\n");
- goto err;
+ return -1;
}
fb_display = fbcon_display();
if (fb_display) {
- if ((logo->header.width != fb_display->width) || (logo->header.height != fb_display->height)) {
+ /* 1 RLE24 compressed data */
+ if (header->type && (header->blocks != 0)) {
+ uint8_t *base = (uint8_t *) fb_display->base + LOGO_IMG_OFFSET;
+
+ /* if the logo is full-screen size, remove "fbcon_clear()" */
+ if ((header->width != fb_display->width)
+ || (header->height != fb_display->height))
+ fbcon_clear();
+
+ if (mmc_read(ptn + LOGO_IMG_HEADER_SIZE,
+ (uint32_t *)base,
+ (header->blocks * 512))) {
+ dprintf(CRITICAL, "ERROR: Cannot read splash image from partition\n");
+ return -1;
+ }
+ fbcon_extract_to_screen(header, base);
+ return 0;
+ }
+
+ /* 2 Raw BGR data */
+ if ((header->width != fb_display->width) || (header->height != fb_display->height)) {
dprintf(CRITICAL, "Logo config doesn't match with fb config. Fall back default logo\n");
- goto err;
+ return -1;
}
uint8_t *base = (uint8_t *) fb_display->base;
- readsize = ROUNDUP((logo->header.width * logo->header.height * fb_display->bpp/8), blocksize);
-
- if (readsize > ptn_size)
- {
- dprintf(CRITICAL, "@%d:Invalid logo header readsize:%u exceeds ptn_size:%u\n", __LINE__, readsize,ptn_size);
- goto err;
- }
-
- if (mmc_read(ptn + logosize,(uint32_t *)base, readsize)) {
+ if (mmc_read(ptn + LOGO_IMG_HEADER_SIZE,
+ (uint32_t *)base,
+ ((((header->width * header->height * fb_display->bpp/8) + 511) >> 9) << 9))) {
fbcon_clear();
dprintf(CRITICAL, "ERROR: Cannot read splash image from partition\n");
- goto err;
+ return -1;
}
- logo->image = base;
}
- return logo;
-
-err:
- free(logo);
- return NULL;
+ return 0;
}
-
-struct fbimage* fetch_image_from_partition()
+int fetch_image_from_partition()
{
if (target_is_emmc_boot()) {
return splash_screen_mmc();
diff --git a/dev/fbcon/fbcon.c b/dev/fbcon/fbcon.c
index ce79a3e..266e220 100644
--- a/dev/fbcon/fbcon.c
+++ b/dev/fbcon/fbcon.c
@@ -92,10 +92,18 @@
static void fbcon_flush(void)
{
+ unsigned total_x, total_y;
+ unsigned bytes_per_bpp;
+
if (config->update_start)
config->update_start();
if (config->update_done)
while (!config->update_done());
+
+ total_x = config->width;
+ total_y = config->height;
+ bytes_per_bpp = ((config->bpp) / 8);
+ arch_clean_invalidate_cache_range((addr_t) config->base, (total_x * total_y * bytes_per_bpp));
}
/* TODO: Take stride into account */
@@ -183,10 +191,10 @@
fg = RGB565_WHITE;
bg = RGB565_BLACK;
break;
- case FB_FORMAT_RGB888:
- fg = RGB888_WHITE;
- bg = RGB888_BLACK;
- break;
+ case FB_FORMAT_RGB888:
+ fg = RGB888_WHITE;
+ bg = RGB888_BLACK;
+ break;
default:
dprintf(CRITICAL, "unknown framebuffer pixel format\n");
ASSERT(0);
@@ -206,128 +214,132 @@
struct fbcon_config* fbcon_display(void)
{
- return config;
+ return config;
}
-
-extern struct fbimage* fetch_image_from_partition();
-void fbcon_putImage(struct fbimage *fbimg, bool flag);
-
-void display_image_on_screen()
+void fbcon_extract_to_screen(logo_img_header *header, void* address)
{
- struct fbimage default_fbimg, *fbimg;
- bool flag = true;
+ const uint8_t *imagestart = (const uint8_t *)address;
+ uint pos = 0, offset;
+ uint count = 0;
+ uint x = 0, y = 0;
+ uint8_t *base, *p;
- fbcon_clear();
- fbimg = fetch_image_from_partition();
-
- if(!fbimg) {
- flag = false;
- fbimg = &default_fbimg;
- fbimg->header.width = SPLASH_IMAGE_WIDTH;
- fbimg->header.height = SPLASH_IMAGE_HEIGHT;
-#if DISPLAY_TYPE_MIPI
- fbimg->image = (unsigned char *)imageBuffer_rgb888;
-#else
- fbimg->image = (unsigned char *)imageBuffer;
-#endif
+ if (!config || header->width > config->width
+ || header->height > config->height) {
+ dprintf(INFO, "the logo img is too large\n");
+ return;
}
- fbcon_putImage(fbimg, flag);
- if(flag)
- free(fbimg);
+ base = (uint8_t *) config->base;
+
+ /* put the logo to be center */
+ offset = (config->height - header->height) / 2;
+ if (offset)
+ base += (offset * config->width) * 3;
+ offset = (config->width - header->width ) / 2;
+
+ x = offset;
+ while (count < (uint)header->height * (uint)header->width) {
+ uint8_t run = *(imagestart + pos);
+ bool repeat_run = (run & 0x80);
+ uint runlen = (run & 0x7f) + 1;
+ uint runpos;
+
+ /* consume the run byte */
+ pos++;
+
+ p = base + (y * config->width + x) * 3;
+
+ /* start of a run */
+ for (runpos = 0; runpos < runlen; runpos++) {
+ *p++ = *(imagestart + pos);
+ *p++ = *(imagestart + pos + 1);
+ *p++ = *(imagestart + pos + 2);
+ count++;
+
+ x++;
+
+ /* if a run of raw pixels, consume an input pixel */
+ if (!repeat_run)
+ pos += 3;
+ }
+
+ /* if this was a run of repeated pixels, consume the one input pixel we repeated */
+ if (repeat_run)
+ pos += 3;
+
+ /* the generator will keep compressing data line by line */
+ /* don't cross the lines */
+ if (x == header->width + offset) {
+ y++;
+ x = offset;
+ }
+ }
+
}
-void fbcon_putImage(struct fbimage *fbimg, bool flag)
+void display_default_image_on_screen(void)
{
- unsigned i = 0;
- unsigned total_x;
- unsigned total_y;
- unsigned bytes_per_bpp;
- unsigned image_base;
- unsigned width = 0, pitch = 0, height = 0;
-#if DISPLAY_TYPE_MIPI
- unsigned char *logo_base = NULL;
-#endif
- struct logo_img_header *header = NULL;
-
+ unsigned i = 0;
+ unsigned total_x;
+ unsigned total_y;
+ unsigned bytes_per_bpp;
+ unsigned image_base;
if (!config) {
dprintf(CRITICAL,"NULL configuration, image cannot be displayed\n");
return;
}
- if(fbimg) {
- header = &fbimg->header;
- width = pitch = header->width;
- height = header->height;
- }
+ fbcon_clear(); // clear screen with Black color
total_x = config->width;
total_y = config->height;
bytes_per_bpp = ((config->bpp) / 8);
+ image_base = ((((total_y/2) - (SPLASH_IMAGE_HEIGHT / 2) - 1) *
+ (config->width)) + (total_x/2 - (SPLASH_IMAGE_WIDTH / 2)));
#if DISPLAY_TYPE_MIPI
- if(fbimg) {
- logo_base = (unsigned char *)fbimg->image;
- }
- if (bytes_per_bpp == 3)
- {
- if(flag && header) {
- if (header->width == config->width && header->height == config->height)
- return;
- else {
- logo_base = (unsigned char *)config->base + LOGO_IMG_OFFSET;
- if (header->width > config->width) {
- width = config->width;
- pitch = header->width;
- logo_base += (header->width - config->width) / 2 * bytes_per_bpp;
- } else {
- width = pitch = header->width;
- }
-
- if (header->height > config->height) {
- height = config->height;
- logo_base += (header->height - config->height) / 2 * pitch * bytes_per_bpp;
- } else {
- height = header->height;
- }
- }
- }
-
- image_base = ((((total_y/2) - (height / 2) ) *
- (config->width)) + (total_x/2 - (width / 2)));
- for (i = 0; i < height; i++) {
+ if (bytes_per_bpp == 3) {
+ for (i = 0; i < SPLASH_IMAGE_HEIGHT; i++) {
memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp),
- logo_base + (i * pitch * bytes_per_bpp), width * bytes_per_bpp);
+ imageBuffer_rgb888 + (i * SPLASH_IMAGE_WIDTH * bytes_per_bpp),
+ SPLASH_IMAGE_WIDTH * bytes_per_bpp);
}
- /* Flush the contents to memory before giving the data to dma */
- arch_clean_invalidate_cache_range((addr_t) config->base, (total_x * total_y * bytes_per_bpp));
}
-
fbcon_flush();
-
#if DISPLAY_MIPI_PANEL_NOVATEK_BLUE
if(is_cmd_mode_enabled())
- mipi_dsi_cmd_mode_trigger();
+ mipi_dsi_cmd_mode_trigger();
#endif
#else
- if (bytes_per_bpp == 2)
- {
- image_base = ((((total_y/2) - (height / 2) ) *
- (config->width)) + (total_x/2 - (width / 2)));
- for (i = 0; i < header->width; i++)
- {
- memcpy (config->base +
- ((image_base + (i * (config->width))) * bytes_per_bpp),
- (fbimg->image + (i * header->height * bytes_per_bpp)),
- (header->height * bytes_per_bpp));
+ if (bytes_per_bpp == 2) {
+ for (i = 0; i < SPLASH_IMAGE_HEIGHT; i++) {
+ memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp),
+ imageBuffer + (i * SPLASH_IMAGE_WIDTH * bytes_per_bpp),
+ SPLASH_IMAGE_WIDTH * bytes_per_bpp);
}
}
- /* Flush the contents to memory before giving the data to dma */
- arch_clean_invalidate_cache_range((addr_t) config->base, (total_x * total_y * bytes_per_bpp));
fbcon_flush();
#endif
}
+
+
+void display_image_on_screen(void)
+{
+#if DISPLAY_TYPE_MIPI
+ int fetch_image_from_partition();
+
+ if (fetch_image_from_partition() < 0) {
+ display_default_image_on_screen();
+ } else {
+ /* data has been put into the right place */
+ fbcon_flush();
+ }
+#else
+ display_default_image_on_screen();
+#endif
+}
diff --git a/include/dev/fbcon.h b/include/dev/fbcon.h
index 2587277..e96b663 100644
--- a/include/dev/fbcon.h
+++ b/include/dev/fbcon.h
@@ -2,7 +2,7 @@
* Copyright (c) 2008, Google Inc.
* All rights reserved.
*
- * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,17 +35,20 @@
#define LOGO_IMG_OFFSET (12*1024*1024)
#define LOGO_IMG_MAGIC "SPLASH!!"
#define LOGO_IMG_MAGIC_SIZE sizeof(LOGO_IMG_MAGIC) - 1
+#define LOGO_IMG_HEADER_SIZE 512
-
-struct logo_img_header {
- unsigned char magic[LOGO_IMG_MAGIC_SIZE]; // "SPLASH!!"
- uint32_t width; // logo's width, little endian
- uint32_t height; // logo's height, little endian
- uint32_t offset;
-};
+typedef struct logo_img_header {
+ unsigned char magic[LOGO_IMG_MAGIC_SIZE]; // "SPLASH!!"
+ uint32_t width; // logo's width, little endian
+ uint32_t height; // logo's height, little endian
+ uint32_t type; // 0, Raw BGR data; 1, RLE24 Compressed data
+ uint32_t blocks; // block number, compressed data size / 512
+ uint32_t offset;
+ uint8_t reserved[512-28];
+}logo_img_header;
struct fbimage {
- struct logo_img_header header;
+ struct logo_img_header header;
void *image;
};
@@ -70,5 +73,6 @@
void fbcon_putc(char c);
void fbcon_clear(void);
struct fbcon_config* fbcon_display(void);
+void fbcon_extract_to_screen(logo_img_header *header, void* address);
#endif /* __DEV_FBCON_H */