xref: /openbmc/u-boot/cmd/bmp.c (revision 500ad54e)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22e192b24SSimon Glass /*
32e192b24SSimon Glass  * (C) Copyright 2002
42e192b24SSimon Glass  * Detlev Zundel, DENX Software Engineering, dzu@denx.de.
52e192b24SSimon Glass  */
62e192b24SSimon Glass 
72e192b24SSimon Glass /*
82e192b24SSimon Glass  * BMP handling routines
92e192b24SSimon Glass  */
102e192b24SSimon Glass 
112e192b24SSimon Glass #include <common.h>
122e192b24SSimon Glass #include <dm.h>
132e192b24SSimon Glass #include <lcd.h>
142e192b24SSimon Glass #include <mapmem.h>
152e192b24SSimon Glass #include <bmp_layout.h>
162e192b24SSimon Glass #include <command.h>
172e192b24SSimon Glass #include <asm/byteorder.h>
182e192b24SSimon Glass #include <malloc.h>
192e192b24SSimon Glass #include <mapmem.h>
202e192b24SSimon Glass #include <splash.h>
212e192b24SSimon Glass #include <video.h>
222e192b24SSimon Glass 
232e192b24SSimon Glass static int bmp_info (ulong addr);
242e192b24SSimon Glass 
252e192b24SSimon Glass /*
262e192b24SSimon Glass  * Allocate and decompress a BMP image using gunzip().
272e192b24SSimon Glass  *
282e192b24SSimon Glass  * Returns a pointer to the decompressed image data. This pointer is
292e192b24SSimon Glass  * aligned to 32-bit-aligned-address + 2.
302e192b24SSimon Glass  * See doc/README.displaying-bmps for explanation.
312e192b24SSimon Glass  *
322e192b24SSimon Glass  * The allocation address is passed to 'alloc_addr' and must be freed
332e192b24SSimon Glass  * by the caller after use.
342e192b24SSimon Glass  *
352e192b24SSimon Glass  * Returns NULL if decompression failed, or if the decompressed data
362e192b24SSimon Glass  * didn't contain a valid BMP signature.
372e192b24SSimon Glass  */
382e192b24SSimon Glass #ifdef CONFIG_VIDEO_BMP_GZIP
gunzip_bmp(unsigned long addr,unsigned long * lenp,void ** alloc_addr)392e192b24SSimon Glass struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
402e192b24SSimon Glass 			     void **alloc_addr)
412e192b24SSimon Glass {
422e192b24SSimon Glass 	void *dst;
432e192b24SSimon Glass 	unsigned long len;
442e192b24SSimon Glass 	struct bmp_image *bmp;
452e192b24SSimon Glass 
462e192b24SSimon Glass 	/*
472e192b24SSimon Glass 	 * Decompress bmp image
482e192b24SSimon Glass 	 */
492e192b24SSimon Glass 	len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
502e192b24SSimon Glass 	/* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */
512e192b24SSimon Glass 	dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE + 3);
522e192b24SSimon Glass 	if (dst == NULL) {
532e192b24SSimon Glass 		puts("Error: malloc in gunzip failed!\n");
542e192b24SSimon Glass 		return NULL;
552e192b24SSimon Glass 	}
562e192b24SSimon Glass 
572e192b24SSimon Glass 	bmp = dst;
582e192b24SSimon Glass 
592e192b24SSimon Glass 	/* align to 32-bit-aligned-address + 2 */
60*77195216SAdam Heinrich 	bmp = (struct bmp_image *)((((uintptr_t)dst + 1) & ~3) + 2);
612e192b24SSimon Glass 
622e192b24SSimon Glass 	if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, map_sysmem(addr, 0),
632e192b24SSimon Glass 		   &len) != 0) {
642e192b24SSimon Glass 		free(dst);
652e192b24SSimon Glass 		return NULL;
662e192b24SSimon Glass 	}
672e192b24SSimon Glass 	if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)
682e192b24SSimon Glass 		puts("Image could be truncated"
692e192b24SSimon Glass 				" (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
702e192b24SSimon Glass 
712e192b24SSimon Glass 	/*
722e192b24SSimon Glass 	 * Check for bmp mark 'BM'
732e192b24SSimon Glass 	 */
742e192b24SSimon Glass 	if (!((bmp->header.signature[0] == 'B') &&
752e192b24SSimon Glass 	      (bmp->header.signature[1] == 'M'))) {
762e192b24SSimon Glass 		free(dst);
772e192b24SSimon Glass 		return NULL;
782e192b24SSimon Glass 	}
792e192b24SSimon Glass 
802e192b24SSimon Glass 	debug("Gzipped BMP image detected!\n");
812e192b24SSimon Glass 
822e192b24SSimon Glass 	*alloc_addr = dst;
832e192b24SSimon Glass 	return bmp;
842e192b24SSimon Glass }
852e192b24SSimon Glass #else
gunzip_bmp(unsigned long addr,unsigned long * lenp,void ** alloc_addr)862e192b24SSimon Glass struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp,
872e192b24SSimon Glass 			     void **alloc_addr)
882e192b24SSimon Glass {
892e192b24SSimon Glass 	return NULL;
902e192b24SSimon Glass }
912e192b24SSimon Glass #endif
922e192b24SSimon Glass 
do_bmp_info(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])932e192b24SSimon Glass static int do_bmp_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
942e192b24SSimon Glass {
952e192b24SSimon Glass 	ulong addr;
962e192b24SSimon Glass 
972e192b24SSimon Glass 	switch (argc) {
982e192b24SSimon Glass 	case 1:		/* use load_addr as default address */
992e192b24SSimon Glass 		addr = load_addr;
1002e192b24SSimon Glass 		break;
1012e192b24SSimon Glass 	case 2:		/* use argument */
1022e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
1032e192b24SSimon Glass 		break;
1042e192b24SSimon Glass 	default:
1052e192b24SSimon Glass 		return CMD_RET_USAGE;
1062e192b24SSimon Glass 	}
1072e192b24SSimon Glass 
1082e192b24SSimon Glass 	return (bmp_info(addr));
1092e192b24SSimon Glass }
1102e192b24SSimon Glass 
do_bmp_display(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1112e192b24SSimon Glass static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
1122e192b24SSimon Glass {
1132e192b24SSimon Glass 	ulong addr;
1142e192b24SSimon Glass 	int x = 0, y = 0;
1152e192b24SSimon Glass 
1162e192b24SSimon Glass 	splash_get_pos(&x, &y);
1172e192b24SSimon Glass 
1182e192b24SSimon Glass 	switch (argc) {
1192e192b24SSimon Glass 	case 1:		/* use load_addr as default address */
1202e192b24SSimon Glass 		addr = load_addr;
1212e192b24SSimon Glass 		break;
1222e192b24SSimon Glass 	case 2:		/* use argument */
1232e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
1242e192b24SSimon Glass 		break;
1252e192b24SSimon Glass 	case 4:
1262e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
127b0fcedb7SPatrick Delaunay 		if (!strcmp(argv[2], "m"))
128b0fcedb7SPatrick Delaunay 			x = BMP_ALIGN_CENTER;
129b0fcedb7SPatrick Delaunay 		else
1302e192b24SSimon Glass 			x = simple_strtoul(argv[2], NULL, 10);
131b0fcedb7SPatrick Delaunay 		if (!strcmp(argv[3], "m"))
132b0fcedb7SPatrick Delaunay 			y = BMP_ALIGN_CENTER;
133b0fcedb7SPatrick Delaunay 		else
1342e192b24SSimon Glass 			y = simple_strtoul(argv[3], NULL, 10);
1352e192b24SSimon Glass 		break;
1362e192b24SSimon Glass 	default:
1372e192b24SSimon Glass 		return CMD_RET_USAGE;
1382e192b24SSimon Glass 	}
1392e192b24SSimon Glass 
1402e192b24SSimon Glass 	 return (bmp_display(addr, x, y));
1412e192b24SSimon Glass }
1422e192b24SSimon Glass 
1432e192b24SSimon Glass static cmd_tbl_t cmd_bmp_sub[] = {
1442e192b24SSimon Glass 	U_BOOT_CMD_MKENT(info, 3, 0, do_bmp_info, "", ""),
1452e192b24SSimon Glass 	U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""),
1462e192b24SSimon Glass };
1472e192b24SSimon Glass 
1482e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC
bmp_reloc(void)1492e192b24SSimon Glass void bmp_reloc(void) {
1502e192b24SSimon Glass 	fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub));
1512e192b24SSimon Glass }
1522e192b24SSimon Glass #endif
1532e192b24SSimon Glass 
1542e192b24SSimon Glass /*
1552e192b24SSimon Glass  * Subroutine:  do_bmp
1562e192b24SSimon Glass  *
1572e192b24SSimon Glass  * Description: Handler for 'bmp' command..
1582e192b24SSimon Glass  *
1592e192b24SSimon Glass  * Inputs:	argv[1] contains the subcommand
1602e192b24SSimon Glass  *
1612e192b24SSimon Glass  * Return:      None
1622e192b24SSimon Glass  *
1632e192b24SSimon Glass  */
do_bmp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1642e192b24SSimon Glass static int do_bmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1652e192b24SSimon Glass {
1662e192b24SSimon Glass 	cmd_tbl_t *c;
1672e192b24SSimon Glass 
1682e192b24SSimon Glass 	/* Strip off leading 'bmp' command argument */
1692e192b24SSimon Glass 	argc--;
1702e192b24SSimon Glass 	argv++;
1712e192b24SSimon Glass 
1722e192b24SSimon Glass 	c = find_cmd_tbl(argv[0], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub));
1732e192b24SSimon Glass 
1742e192b24SSimon Glass 	if (c)
1752e192b24SSimon Glass 		return  c->cmd(cmdtp, flag, argc, argv);
1762e192b24SSimon Glass 	else
1772e192b24SSimon Glass 		return CMD_RET_USAGE;
1782e192b24SSimon Glass }
1792e192b24SSimon Glass 
1802e192b24SSimon Glass U_BOOT_CMD(
1812e192b24SSimon Glass 	bmp,	5,	1,	do_bmp,
1822e192b24SSimon Glass 	"manipulate BMP image data",
1832e192b24SSimon Glass 	"info <imageAddr>          - display image info\n"
1842e192b24SSimon Glass 	"bmp display <imageAddr> [x y] - display image at x,y"
1852e192b24SSimon Glass );
1862e192b24SSimon Glass 
1872e192b24SSimon Glass /*
1882e192b24SSimon Glass  * Subroutine:  bmp_info
1892e192b24SSimon Glass  *
1902e192b24SSimon Glass  * Description: Show information about bmp file in memory
1912e192b24SSimon Glass  *
1922e192b24SSimon Glass  * Inputs:	addr		address of the bmp file
1932e192b24SSimon Glass  *
1942e192b24SSimon Glass  * Return:      None
1952e192b24SSimon Glass  *
1962e192b24SSimon Glass  */
bmp_info(ulong addr)1972e192b24SSimon Glass static int bmp_info(ulong addr)
1982e192b24SSimon Glass {
1992e192b24SSimon Glass 	struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0);
2002e192b24SSimon Glass 	void *bmp_alloc_addr = NULL;
2012e192b24SSimon Glass 	unsigned long len;
2022e192b24SSimon Glass 
2032e192b24SSimon Glass 	if (!((bmp->header.signature[0]=='B') &&
2042e192b24SSimon Glass 	      (bmp->header.signature[1]=='M')))
2052e192b24SSimon Glass 		bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr);
2062e192b24SSimon Glass 
2072e192b24SSimon Glass 	if (bmp == NULL) {
2082e192b24SSimon Glass 		printf("There is no valid bmp file at the given address\n");
2092e192b24SSimon Glass 		return 1;
2102e192b24SSimon Glass 	}
2112e192b24SSimon Glass 
2122e192b24SSimon Glass 	printf("Image size    : %d x %d\n", le32_to_cpu(bmp->header.width),
2132e192b24SSimon Glass 	       le32_to_cpu(bmp->header.height));
2142e192b24SSimon Glass 	printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count));
2152e192b24SSimon Glass 	printf("Compression   : %d\n", le32_to_cpu(bmp->header.compression));
2162e192b24SSimon Glass 
2172e192b24SSimon Glass 	if (bmp_alloc_addr)
2182e192b24SSimon Glass 		free(bmp_alloc_addr);
2192e192b24SSimon Glass 
2202e192b24SSimon Glass 	return(0);
2212e192b24SSimon Glass }
2222e192b24SSimon Glass 
2232e192b24SSimon Glass /*
2242e192b24SSimon Glass  * Subroutine:  bmp_display
2252e192b24SSimon Glass  *
2262e192b24SSimon Glass  * Description: Display bmp file located in memory
2272e192b24SSimon Glass  *
2282e192b24SSimon Glass  * Inputs:	addr		address of the bmp file
2292e192b24SSimon Glass  *
2302e192b24SSimon Glass  * Return:      None
2312e192b24SSimon Glass  *
2322e192b24SSimon Glass  */
bmp_display(ulong addr,int x,int y)2332e192b24SSimon Glass int bmp_display(ulong addr, int x, int y)
2342e192b24SSimon Glass {
2352e192b24SSimon Glass #ifdef CONFIG_DM_VIDEO
2362e192b24SSimon Glass 	struct udevice *dev;
2372e192b24SSimon Glass #endif
2382e192b24SSimon Glass 	int ret;
2392e192b24SSimon Glass 	struct bmp_image *bmp = map_sysmem(addr, 0);
2402e192b24SSimon Glass 	void *bmp_alloc_addr = NULL;
2412e192b24SSimon Glass 	unsigned long len;
2422e192b24SSimon Glass 
2432e192b24SSimon Glass 	if (!((bmp->header.signature[0]=='B') &&
2442e192b24SSimon Glass 	      (bmp->header.signature[1]=='M')))
2452e192b24SSimon Glass 		bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr);
2462e192b24SSimon Glass 
2472e192b24SSimon Glass 	if (!bmp) {
2482e192b24SSimon Glass 		printf("There is no valid bmp file at the given address\n");
2492e192b24SSimon Glass 		return 1;
2502e192b24SSimon Glass 	}
2512e192b24SSimon Glass 	addr = map_to_sysmem(bmp);
2522e192b24SSimon Glass 
2532e192b24SSimon Glass #ifdef CONFIG_DM_VIDEO
2543f603cbbSSimon Glass 	ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
2552e192b24SSimon Glass 	if (!ret) {
2562e192b24SSimon Glass 		bool align = false;
2572e192b24SSimon Glass 
258b0fcedb7SPatrick Delaunay 		if (CONFIG_IS_ENABLED(SPLASH_SCREEN_ALIGN) ||
259b0fcedb7SPatrick Delaunay 		    x == BMP_ALIGN_CENTER ||
260b0fcedb7SPatrick Delaunay 		    y == BMP_ALIGN_CENTER)
2612e192b24SSimon Glass 			align = true;
262b0fcedb7SPatrick Delaunay 
2632e192b24SSimon Glass 		ret = video_bmp_display(dev, addr, x, y, align);
2642e192b24SSimon Glass 	}
2652e192b24SSimon Glass #elif defined(CONFIG_LCD)
2662e192b24SSimon Glass 	ret = lcd_display_bitmap(addr, x, y);
2672e192b24SSimon Glass #elif defined(CONFIG_VIDEO)
2682e192b24SSimon Glass 	ret = video_display_bitmap(addr, x, y);
2692e192b24SSimon Glass #else
2702e192b24SSimon Glass # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO
2712e192b24SSimon Glass #endif
2722e192b24SSimon Glass 
2732e192b24SSimon Glass 	if (bmp_alloc_addr)
2742e192b24SSimon Glass 		free(bmp_alloc_addr);
2752e192b24SSimon Glass 
276e517db73SSimon Glass 	return ret ? CMD_RET_FAILURE : 0;
2772e192b24SSimon Glass }
278