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 */