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