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