1 /* 2 * (C) Copyright 2014 CompuLab, Ltd. <www.compulab.co.il> 3 * 4 * Authors: Igor Grinberg <grinberg@compulab.co.il> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <bmp_layout.h> 11 #include <errno.h> 12 #include <fs.h> 13 #include <image.h> 14 #include <nand.h> 15 #include <sata.h> 16 #include <spi.h> 17 #include <spi_flash.h> 18 #include <splash.h> 19 #include <usb.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 #ifdef CONFIG_SPI_FLASH 24 static struct spi_flash *sf; 25 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size) 26 { 27 if (!sf) { 28 sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, 29 CONFIG_SF_DEFAULT_CS, 30 CONFIG_SF_DEFAULT_SPEED, 31 CONFIG_SF_DEFAULT_MODE); 32 if (!sf) 33 return -ENODEV; 34 } 35 36 return spi_flash_read(sf, offset, read_size, (void *)bmp_load_addr); 37 } 38 #else 39 static int splash_sf_read_raw(u32 bmp_load_addr, int offset, size_t read_size) 40 { 41 debug("%s: sf support not available\n", __func__); 42 return -ENOSYS; 43 } 44 #endif 45 46 #ifdef CONFIG_CMD_NAND 47 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size) 48 { 49 return nand_read_skip_bad(nand_info[nand_curr_device], offset, 50 &read_size, NULL, 51 nand_info[nand_curr_device]->size, 52 (u_char *)bmp_load_addr); 53 } 54 #else 55 static int splash_nand_read_raw(u32 bmp_load_addr, int offset, size_t read_size) 56 { 57 debug("%s: nand support not available\n", __func__); 58 return -ENOSYS; 59 } 60 #endif 61 62 static int splash_storage_read_raw(struct splash_location *location, 63 u32 bmp_load_addr, size_t read_size) 64 { 65 u32 offset; 66 67 if (!location) 68 return -EINVAL; 69 70 offset = location->offset; 71 switch (location->storage) { 72 case SPLASH_STORAGE_NAND: 73 return splash_nand_read_raw(bmp_load_addr, offset, read_size); 74 case SPLASH_STORAGE_SF: 75 return splash_sf_read_raw(bmp_load_addr, offset, read_size); 76 default: 77 printf("Unknown splash location\n"); 78 } 79 80 return -EINVAL; 81 } 82 83 static int splash_load_raw(struct splash_location *location, u32 bmp_load_addr) 84 { 85 struct bmp_header *bmp_hdr; 86 int res; 87 size_t bmp_size, bmp_header_size = sizeof(struct bmp_header); 88 89 if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp) 90 goto splash_address_too_high; 91 92 res = splash_storage_read_raw(location, bmp_load_addr, bmp_header_size); 93 if (res < 0) 94 return res; 95 96 bmp_hdr = (struct bmp_header *)bmp_load_addr; 97 bmp_size = le32_to_cpu(bmp_hdr->file_size); 98 99 if (bmp_load_addr + bmp_size >= gd->start_addr_sp) 100 goto splash_address_too_high; 101 102 return splash_storage_read_raw(location, bmp_load_addr, bmp_size); 103 104 splash_address_too_high: 105 printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n"); 106 107 return -EFAULT; 108 } 109 110 static int splash_select_fs_dev(struct splash_location *location) 111 { 112 int res; 113 114 switch (location->storage) { 115 case SPLASH_STORAGE_MMC: 116 res = fs_set_blk_dev("mmc", location->devpart, FS_TYPE_ANY); 117 break; 118 case SPLASH_STORAGE_USB: 119 res = fs_set_blk_dev("usb", location->devpart, FS_TYPE_ANY); 120 break; 121 case SPLASH_STORAGE_SATA: 122 res = fs_set_blk_dev("sata", location->devpart, FS_TYPE_ANY); 123 break; 124 case SPLASH_STORAGE_NAND: 125 if (location->ubivol != NULL) 126 res = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS); 127 else 128 res = -ENODEV; 129 break; 130 default: 131 printf("Error: unsupported location storage.\n"); 132 return -ENODEV; 133 } 134 135 if (res) 136 printf("Error: could not access storage.\n"); 137 138 return res; 139 } 140 141 #ifdef CONFIG_USB_STORAGE 142 static int splash_init_usb(void) 143 { 144 int err; 145 146 err = usb_init(); 147 if (err) 148 return err; 149 150 #ifndef CONFIG_DM_USB 151 err = usb_stor_scan(1) < 0 ? -ENODEV : 0; 152 #endif 153 154 return err; 155 } 156 #else 157 static inline int splash_init_usb(void) 158 { 159 printf("Cannot load splash image: no USB support\n"); 160 return -ENOSYS; 161 } 162 #endif 163 164 #ifdef CONFIG_CMD_SATA 165 static int splash_init_sata(void) 166 { 167 return sata_initialize(); 168 } 169 #else 170 static inline int splash_init_sata(void) 171 { 172 printf("Cannot load splash image: no SATA support\n"); 173 return -ENOSYS; 174 } 175 #endif 176 177 #ifdef CONFIG_CMD_UBIFS 178 static int splash_mount_ubifs(struct splash_location *location) 179 { 180 int res; 181 char cmd[32]; 182 183 sprintf(cmd, "ubi part %s", location->mtdpart); 184 res = run_command(cmd, 0); 185 if (res) 186 return res; 187 188 sprintf(cmd, "ubifsmount %s", location->ubivol); 189 res = run_command(cmd, 0); 190 191 return res; 192 } 193 194 static inline int splash_umount_ubifs(void) 195 { 196 return run_command("ubifsumount", 0); 197 } 198 #else 199 static inline int splash_mount_ubifs(struct splash_location *location) 200 { 201 printf("Cannot load splash image: no UBIFS support\n"); 202 return -ENOSYS; 203 } 204 205 static inline int splash_umount_ubifs(void) 206 { 207 printf("Cannot unmount UBIFS: no UBIFS support\n"); 208 return -ENOSYS; 209 } 210 #endif 211 212 #define SPLASH_SOURCE_DEFAULT_FILE_NAME "splash.bmp" 213 214 static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr) 215 { 216 int res = 0; 217 loff_t bmp_size; 218 char *splash_file; 219 220 splash_file = getenv("splashfile"); 221 if (!splash_file) 222 splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME; 223 224 if (location->storage == SPLASH_STORAGE_USB) 225 res = splash_init_usb(); 226 227 if (location->storage == SPLASH_STORAGE_SATA) 228 res = splash_init_sata(); 229 230 if (location->ubivol != NULL) 231 res = splash_mount_ubifs(location); 232 233 if (res) 234 return res; 235 236 res = splash_select_fs_dev(location); 237 if (res) 238 goto out; 239 240 res = fs_size(splash_file, &bmp_size); 241 if (res) { 242 printf("Error (%d): cannot determine file size\n", res); 243 goto out; 244 } 245 246 if (bmp_load_addr + bmp_size >= gd->start_addr_sp) { 247 printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n"); 248 res = -EFAULT; 249 goto out; 250 } 251 252 splash_select_fs_dev(location); 253 res = fs_read(splash_file, bmp_load_addr, 0, 0, NULL); 254 255 out: 256 if (location->ubivol != NULL) 257 splash_umount_ubifs(); 258 259 return res; 260 } 261 262 /** 263 * select_splash_location - return the splash location based on board support 264 * and env variable "splashsource". 265 * 266 * @locations: An array of supported splash locations. 267 * @size: Size of splash_locations array. 268 * 269 * @return: If a null set of splash locations is given, or 270 * splashsource env variable is set to unsupported value 271 * return NULL. 272 * If splashsource env variable is not defined 273 * return the first entry in splash_locations as default. 274 * If splashsource env variable contains a supported value 275 * return the location selected by splashsource. 276 */ 277 static struct splash_location *select_splash_location( 278 struct splash_location *locations, uint size) 279 { 280 int i; 281 char *env_splashsource; 282 283 if (!locations || size == 0) 284 return NULL; 285 286 env_splashsource = getenv("splashsource"); 287 if (env_splashsource == NULL) 288 return &locations[0]; 289 290 for (i = 0; i < size; i++) { 291 if (!strcmp(locations[i].name, env_splashsource)) 292 return &locations[i]; 293 } 294 295 printf("splashsource env variable set to unsupported value\n"); 296 return NULL; 297 } 298 299 /** 300 * splash_source_load - load splash image from a supported location. 301 * 302 * Select a splash image location based on the value of splashsource environment 303 * variable and the board supported splash source locations, and load a 304 * splashimage to the address pointed to by splashimage environment variable. 305 * 306 * @locations: An array of supported splash locations. 307 * @size: Size of splash_locations array. 308 * 309 * @return: 0 on success, negative value on failure. 310 */ 311 int splash_source_load(struct splash_location *locations, uint size) 312 { 313 struct splash_location *splash_location; 314 char *env_splashimage_value; 315 u32 bmp_load_addr; 316 317 env_splashimage_value = getenv("splashimage"); 318 if (env_splashimage_value == NULL) 319 return -ENOENT; 320 321 bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16); 322 if (bmp_load_addr == 0) { 323 printf("Error: bad splashimage address specified\n"); 324 return -EFAULT; 325 } 326 327 splash_location = select_splash_location(locations, size); 328 if (!splash_location) 329 return -EINVAL; 330 331 if (splash_location->flags & SPLASH_STORAGE_RAW) 332 return splash_load_raw(splash_location, bmp_load_addr); 333 else if (splash_location->flags & SPLASH_STORAGE_FS) 334 return splash_load_fs(splash_location, bmp_load_addr); 335 336 return -EINVAL; 337 } 338