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 x = simple_strtoul(argv[2], NULL, 10); 128 y = simple_strtoul(argv[3], NULL, 10); 129 break; 130 default: 131 return CMD_RET_USAGE; 132 } 133 134 return (bmp_display(addr, x, y)); 135 } 136 137 static cmd_tbl_t cmd_bmp_sub[] = { 138 U_BOOT_CMD_MKENT(info, 3, 0, do_bmp_info, "", ""), 139 U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""), 140 }; 141 142 #ifdef CONFIG_NEEDS_MANUAL_RELOC 143 void bmp_reloc(void) { 144 fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub)); 145 } 146 #endif 147 148 /* 149 * Subroutine: do_bmp 150 * 151 * Description: Handler for 'bmp' command.. 152 * 153 * Inputs: argv[1] contains the subcommand 154 * 155 * Return: None 156 * 157 */ 158 static int do_bmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 159 { 160 cmd_tbl_t *c; 161 162 /* Strip off leading 'bmp' command argument */ 163 argc--; 164 argv++; 165 166 c = find_cmd_tbl(argv[0], &cmd_bmp_sub[0], ARRAY_SIZE(cmd_bmp_sub)); 167 168 if (c) 169 return c->cmd(cmdtp, flag, argc, argv); 170 else 171 return CMD_RET_USAGE; 172 } 173 174 U_BOOT_CMD( 175 bmp, 5, 1, do_bmp, 176 "manipulate BMP image data", 177 "info <imageAddr> - display image info\n" 178 "bmp display <imageAddr> [x y] - display image at x,y" 179 ); 180 181 /* 182 * Subroutine: bmp_info 183 * 184 * Description: Show information about bmp file in memory 185 * 186 * Inputs: addr address of the bmp file 187 * 188 * Return: None 189 * 190 */ 191 static int bmp_info(ulong addr) 192 { 193 struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0); 194 void *bmp_alloc_addr = NULL; 195 unsigned long len; 196 197 if (!((bmp->header.signature[0]=='B') && 198 (bmp->header.signature[1]=='M'))) 199 bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 200 201 if (bmp == NULL) { 202 printf("There is no valid bmp file at the given address\n"); 203 return 1; 204 } 205 206 printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width), 207 le32_to_cpu(bmp->header.height)); 208 printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); 209 printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); 210 211 if (bmp_alloc_addr) 212 free(bmp_alloc_addr); 213 214 return(0); 215 } 216 217 /* 218 * Subroutine: bmp_display 219 * 220 * Description: Display bmp file located in memory 221 * 222 * Inputs: addr address of the bmp file 223 * 224 * Return: None 225 * 226 */ 227 int bmp_display(ulong addr, int x, int y) 228 { 229 #ifdef CONFIG_DM_VIDEO 230 struct udevice *dev; 231 #endif 232 int ret; 233 struct bmp_image *bmp = map_sysmem(addr, 0); 234 void *bmp_alloc_addr = NULL; 235 unsigned long len; 236 237 if (!((bmp->header.signature[0]=='B') && 238 (bmp->header.signature[1]=='M'))) 239 bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 240 241 if (!bmp) { 242 printf("There is no valid bmp file at the given address\n"); 243 return 1; 244 } 245 addr = map_to_sysmem(bmp); 246 247 #ifdef CONFIG_DM_VIDEO 248 ret = uclass_first_device_err(UCLASS_VIDEO, &dev); 249 if (!ret) { 250 bool align = false; 251 252 # ifdef CONFIG_SPLASH_SCREEN_ALIGN 253 align = true; 254 # endif /* CONFIG_SPLASH_SCREEN_ALIGN */ 255 ret = video_bmp_display(dev, addr, x, y, align); 256 } 257 #elif defined(CONFIG_LCD) 258 ret = lcd_display_bitmap(addr, x, y); 259 #elif defined(CONFIG_VIDEO) 260 ret = video_display_bitmap(addr, x, y); 261 #else 262 # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO 263 #endif 264 265 if (bmp_alloc_addr) 266 free(bmp_alloc_addr); 267 268 return ret ? CMD_RET_FAILURE : 0; 269 } 270