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