1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2002 3*2e192b24SSimon Glass * Detlev Zundel, DENX Software Engineering, dzu@denx.de. 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * BMP handling routines 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass 12*2e192b24SSimon Glass #include <common.h> 13*2e192b24SSimon Glass #include <dm.h> 14*2e192b24SSimon Glass #include <lcd.h> 15*2e192b24SSimon Glass #include <mapmem.h> 16*2e192b24SSimon Glass #include <bmp_layout.h> 17*2e192b24SSimon Glass #include <command.h> 18*2e192b24SSimon Glass #include <asm/byteorder.h> 19*2e192b24SSimon Glass #include <malloc.h> 20*2e192b24SSimon Glass #include <mapmem.h> 21*2e192b24SSimon Glass #include <splash.h> 22*2e192b24SSimon Glass #include <video.h> 23*2e192b24SSimon Glass 24*2e192b24SSimon Glass static int bmp_info (ulong addr); 25*2e192b24SSimon Glass 26*2e192b24SSimon Glass /* 27*2e192b24SSimon Glass * Allocate and decompress a BMP image using gunzip(). 28*2e192b24SSimon Glass * 29*2e192b24SSimon Glass * Returns a pointer to the decompressed image data. This pointer is 30*2e192b24SSimon Glass * aligned to 32-bit-aligned-address + 2. 31*2e192b24SSimon Glass * See doc/README.displaying-bmps for explanation. 32*2e192b24SSimon Glass * 33*2e192b24SSimon Glass * The allocation address is passed to 'alloc_addr' and must be freed 34*2e192b24SSimon Glass * by the caller after use. 35*2e192b24SSimon Glass * 36*2e192b24SSimon Glass * Returns NULL if decompression failed, or if the decompressed data 37*2e192b24SSimon Glass * didn't contain a valid BMP signature. 38*2e192b24SSimon Glass */ 39*2e192b24SSimon Glass #ifdef CONFIG_VIDEO_BMP_GZIP 40*2e192b24SSimon Glass struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, 41*2e192b24SSimon Glass void **alloc_addr) 42*2e192b24SSimon Glass { 43*2e192b24SSimon Glass void *dst; 44*2e192b24SSimon Glass unsigned long len; 45*2e192b24SSimon Glass struct bmp_image *bmp; 46*2e192b24SSimon Glass 47*2e192b24SSimon Glass /* 48*2e192b24SSimon Glass * Decompress bmp image 49*2e192b24SSimon Glass */ 50*2e192b24SSimon Glass len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; 51*2e192b24SSimon Glass /* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */ 52*2e192b24SSimon Glass dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE + 3); 53*2e192b24SSimon Glass if (dst == NULL) { 54*2e192b24SSimon Glass puts("Error: malloc in gunzip failed!\n"); 55*2e192b24SSimon Glass return NULL; 56*2e192b24SSimon Glass } 57*2e192b24SSimon Glass 58*2e192b24SSimon Glass bmp = dst; 59*2e192b24SSimon Glass 60*2e192b24SSimon Glass /* align to 32-bit-aligned-address + 2 */ 61*2e192b24SSimon Glass bmp = (struct bmp_image *)((((unsigned int)dst + 1) & ~3) + 2); 62*2e192b24SSimon Glass 63*2e192b24SSimon Glass if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, map_sysmem(addr, 0), 64*2e192b24SSimon Glass &len) != 0) { 65*2e192b24SSimon Glass free(dst); 66*2e192b24SSimon Glass return NULL; 67*2e192b24SSimon Glass } 68*2e192b24SSimon Glass if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) 69*2e192b24SSimon Glass puts("Image could be truncated" 70*2e192b24SSimon Glass " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); 71*2e192b24SSimon Glass 72*2e192b24SSimon Glass /* 73*2e192b24SSimon Glass * Check for bmp mark 'BM' 74*2e192b24SSimon Glass */ 75*2e192b24SSimon Glass if (!((bmp->header.signature[0] == 'B') && 76*2e192b24SSimon Glass (bmp->header.signature[1] == 'M'))) { 77*2e192b24SSimon Glass free(dst); 78*2e192b24SSimon Glass return NULL; 79*2e192b24SSimon Glass } 80*2e192b24SSimon Glass 81*2e192b24SSimon Glass debug("Gzipped BMP image detected!\n"); 82*2e192b24SSimon Glass 83*2e192b24SSimon Glass *alloc_addr = dst; 84*2e192b24SSimon Glass return bmp; 85*2e192b24SSimon Glass } 86*2e192b24SSimon Glass #else 87*2e192b24SSimon Glass struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, 88*2e192b24SSimon Glass void **alloc_addr) 89*2e192b24SSimon Glass { 90*2e192b24SSimon Glass return NULL; 91*2e192b24SSimon Glass } 92*2e192b24SSimon Glass #endif 93*2e192b24SSimon Glass 94*2e192b24SSimon Glass static int do_bmp_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 95*2e192b24SSimon Glass { 96*2e192b24SSimon Glass ulong addr; 97*2e192b24SSimon Glass 98*2e192b24SSimon Glass switch (argc) { 99*2e192b24SSimon Glass case 1: /* use load_addr as default address */ 100*2e192b24SSimon Glass addr = load_addr; 101*2e192b24SSimon Glass break; 102*2e192b24SSimon Glass case 2: /* use argument */ 103*2e192b24SSimon Glass addr = simple_strtoul(argv[1], NULL, 16); 104*2e192b24SSimon Glass break; 105*2e192b24SSimon Glass default: 106*2e192b24SSimon Glass return CMD_RET_USAGE; 107*2e192b24SSimon Glass } 108*2e192b24SSimon Glass 109*2e192b24SSimon Glass return (bmp_info(addr)); 110*2e192b24SSimon Glass } 111*2e192b24SSimon Glass 112*2e192b24SSimon Glass static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 113*2e192b24SSimon Glass { 114*2e192b24SSimon Glass ulong addr; 115*2e192b24SSimon Glass int x = 0, y = 0; 116*2e192b24SSimon Glass 117*2e192b24SSimon Glass splash_get_pos(&x, &y); 118*2e192b24SSimon Glass 119*2e192b24SSimon Glass switch (argc) { 120*2e192b24SSimon Glass case 1: /* use load_addr as default address */ 121*2e192b24SSimon Glass addr = load_addr; 122*2e192b24SSimon Glass break; 123*2e192b24SSimon Glass case 2: /* use argument */ 124*2e192b24SSimon Glass addr = simple_strtoul(argv[1], NULL, 16); 125*2e192b24SSimon Glass break; 126*2e192b24SSimon Glass case 4: 127*2e192b24SSimon Glass addr = simple_strtoul(argv[1], NULL, 16); 128*2e192b24SSimon Glass x = simple_strtoul(argv[2], NULL, 10); 129*2e192b24SSimon Glass y = simple_strtoul(argv[3], NULL, 10); 130*2e192b24SSimon Glass break; 131*2e192b24SSimon Glass default: 132*2e192b24SSimon Glass return CMD_RET_USAGE; 133*2e192b24SSimon Glass } 134*2e192b24SSimon Glass 135*2e192b24SSimon Glass return (bmp_display(addr, x, y)); 136*2e192b24SSimon Glass } 137*2e192b24SSimon Glass 138*2e192b24SSimon Glass static cmd_tbl_t cmd_bmp_sub[] = { 139*2e192b24SSimon Glass U_BOOT_CMD_MKENT(info, 3, 0, do_bmp_info, "", ""), 140*2e192b24SSimon Glass U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""), 141*2e192b24SSimon Glass }; 142*2e192b24SSimon Glass 143*2e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC 144*2e192b24SSimon Glass void bmp_reloc(void) { 145*2e192b24SSimon Glass fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub)); 146*2e192b24SSimon Glass } 147*2e192b24SSimon Glass #endif 148*2e192b24SSimon Glass 149*2e192b24SSimon Glass /* 150*2e192b24SSimon Glass * Subroutine: do_bmp 151*2e192b24SSimon Glass * 152*2e192b24SSimon Glass * Description: Handler for 'bmp' command.. 153*2e192b24SSimon Glass * 154*2e192b24SSimon Glass * Inputs: argv[1] contains the subcommand 155*2e192b24SSimon Glass * 156*2e192b24SSimon Glass * Return: None 157*2e192b24SSimon Glass * 158*2e192b24SSimon Glass */ 159*2e192b24SSimon Glass static int do_bmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 160*2e192b24SSimon Glass { 161*2e192b24SSimon Glass cmd_tbl_t *c; 162*2e192b24SSimon Glass 163*2e192b24SSimon Glass /* Strip off leading 'bmp' command argument */ 164*2e192b24SSimon Glass argc--; 165*2e192b24SSimon Glass argv++; 166*2e192b24SSimon Glass 167*2e192b24SSimon Glass c = find_cmd_tbl(argv[0], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub)); 168*2e192b24SSimon Glass 169*2e192b24SSimon Glass if (c) 170*2e192b24SSimon Glass return c->cmd(cmdtp, flag, argc, argv); 171*2e192b24SSimon Glass else 172*2e192b24SSimon Glass return CMD_RET_USAGE; 173*2e192b24SSimon Glass } 174*2e192b24SSimon Glass 175*2e192b24SSimon Glass U_BOOT_CMD( 176*2e192b24SSimon Glass bmp, 5, 1, do_bmp, 177*2e192b24SSimon Glass "manipulate BMP image data", 178*2e192b24SSimon Glass "info <imageAddr> - display image info\n" 179*2e192b24SSimon Glass "bmp display <imageAddr> [x y] - display image at x,y" 180*2e192b24SSimon Glass ); 181*2e192b24SSimon Glass 182*2e192b24SSimon Glass /* 183*2e192b24SSimon Glass * Subroutine: bmp_info 184*2e192b24SSimon Glass * 185*2e192b24SSimon Glass * Description: Show information about bmp file in memory 186*2e192b24SSimon Glass * 187*2e192b24SSimon Glass * Inputs: addr address of the bmp file 188*2e192b24SSimon Glass * 189*2e192b24SSimon Glass * Return: None 190*2e192b24SSimon Glass * 191*2e192b24SSimon Glass */ 192*2e192b24SSimon Glass static int bmp_info(ulong addr) 193*2e192b24SSimon Glass { 194*2e192b24SSimon Glass struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0); 195*2e192b24SSimon Glass void *bmp_alloc_addr = NULL; 196*2e192b24SSimon Glass unsigned long len; 197*2e192b24SSimon Glass 198*2e192b24SSimon Glass if (!((bmp->header.signature[0]=='B') && 199*2e192b24SSimon Glass (bmp->header.signature[1]=='M'))) 200*2e192b24SSimon Glass bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 201*2e192b24SSimon Glass 202*2e192b24SSimon Glass if (bmp == NULL) { 203*2e192b24SSimon Glass printf("There is no valid bmp file at the given address\n"); 204*2e192b24SSimon Glass return 1; 205*2e192b24SSimon Glass } 206*2e192b24SSimon Glass 207*2e192b24SSimon Glass printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width), 208*2e192b24SSimon Glass le32_to_cpu(bmp->header.height)); 209*2e192b24SSimon Glass printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); 210*2e192b24SSimon Glass printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); 211*2e192b24SSimon Glass 212*2e192b24SSimon Glass if (bmp_alloc_addr) 213*2e192b24SSimon Glass free(bmp_alloc_addr); 214*2e192b24SSimon Glass 215*2e192b24SSimon Glass return(0); 216*2e192b24SSimon Glass } 217*2e192b24SSimon Glass 218*2e192b24SSimon Glass /* 219*2e192b24SSimon Glass * Subroutine: bmp_display 220*2e192b24SSimon Glass * 221*2e192b24SSimon Glass * Description: Display bmp file located in memory 222*2e192b24SSimon Glass * 223*2e192b24SSimon Glass * Inputs: addr address of the bmp file 224*2e192b24SSimon Glass * 225*2e192b24SSimon Glass * Return: None 226*2e192b24SSimon Glass * 227*2e192b24SSimon Glass */ 228*2e192b24SSimon Glass int bmp_display(ulong addr, int x, int y) 229*2e192b24SSimon Glass { 230*2e192b24SSimon Glass #ifdef CONFIG_DM_VIDEO 231*2e192b24SSimon Glass struct udevice *dev; 232*2e192b24SSimon Glass #endif 233*2e192b24SSimon Glass int ret; 234*2e192b24SSimon Glass struct bmp_image *bmp = map_sysmem(addr, 0); 235*2e192b24SSimon Glass void *bmp_alloc_addr = NULL; 236*2e192b24SSimon Glass unsigned long len; 237*2e192b24SSimon Glass 238*2e192b24SSimon Glass if (!((bmp->header.signature[0]=='B') && 239*2e192b24SSimon Glass (bmp->header.signature[1]=='M'))) 240*2e192b24SSimon Glass bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 241*2e192b24SSimon Glass 242*2e192b24SSimon Glass if (!bmp) { 243*2e192b24SSimon Glass printf("There is no valid bmp file at the given address\n"); 244*2e192b24SSimon Glass return 1; 245*2e192b24SSimon Glass } 246*2e192b24SSimon Glass addr = map_to_sysmem(bmp); 247*2e192b24SSimon Glass 248*2e192b24SSimon Glass #ifdef CONFIG_DM_VIDEO 249*2e192b24SSimon Glass ret = uclass_first_device(UCLASS_VIDEO, &dev); 250*2e192b24SSimon Glass if (!ret) { 251*2e192b24SSimon Glass if (!dev) 252*2e192b24SSimon Glass ret = -ENODEV; 253*2e192b24SSimon Glass if (!ret) { 254*2e192b24SSimon Glass bool align = false; 255*2e192b24SSimon Glass 256*2e192b24SSimon Glass # ifdef CONFIG_SPLASH_SCREEN_ALIGN 257*2e192b24SSimon Glass align = true; 258*2e192b24SSimon Glass # endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 259*2e192b24SSimon Glass ret = video_bmp_display(dev, addr, x, y, align); 260*2e192b24SSimon Glass } 261*2e192b24SSimon Glass } 262*2e192b24SSimon Glass return ret ? CMD_RET_FAILURE : 0; 263*2e192b24SSimon Glass #elif defined(CONFIG_LCD) 264*2e192b24SSimon Glass ret = lcd_display_bitmap(addr, x, y); 265*2e192b24SSimon Glass #elif defined(CONFIG_VIDEO) 266*2e192b24SSimon Glass ret = video_display_bitmap(addr, x, y); 267*2e192b24SSimon Glass #else 268*2e192b24SSimon Glass # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO 269*2e192b24SSimon Glass #endif 270*2e192b24SSimon Glass 271*2e192b24SSimon Glass if (bmp_alloc_addr) 272*2e192b24SSimon Glass free(bmp_alloc_addr); 273*2e192b24SSimon Glass 274*2e192b24SSimon Glass return ret; 275*2e192b24SSimon Glass } 276