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 default: 124 printf("Error: unsupported location storage.\n"); 125 return -ENODEV; 126 } 127 128 if (res) 129 printf("Error: could not access storage.\n"); 130 131 return res; 132 } 133 134 #ifdef CONFIG_USB_STORAGE 135 static int splash_init_usb(void) 136 { 137 int err; 138 139 err = usb_init(); 140 if (err) 141 return err; 142 143 return usb_stor_scan(1) < 0 ? -ENODEV : 0; 144 } 145 #else 146 static inline int splash_init_usb(void) 147 { 148 printf("Cannot load splash image: no USB support\n"); 149 return -ENOSYS; 150 } 151 #endif 152 153 #ifdef CONFIG_CMD_SATA 154 static int splash_init_sata(void) 155 { 156 return sata_initialize(); 157 } 158 #else 159 static inline int splash_init_sata(void) 160 { 161 printf("Cannot load splash image: no SATA support\n"); 162 return -ENOSYS; 163 } 164 #endif 165 166 #define SPLASH_SOURCE_DEFAULT_FILE_NAME "splash.bmp" 167 168 static int splash_load_fs(struct splash_location *location, u32 bmp_load_addr) 169 { 170 int res = 0; 171 loff_t bmp_size; 172 char *splash_file; 173 174 splash_file = getenv("splashfile"); 175 if (!splash_file) 176 splash_file = SPLASH_SOURCE_DEFAULT_FILE_NAME; 177 178 if (location->storage == SPLASH_STORAGE_USB) 179 res = splash_init_usb(); 180 181 if (location->storage == SPLASH_STORAGE_SATA) 182 res = splash_init_sata(); 183 184 if (res) 185 return res; 186 187 res = splash_select_fs_dev(location); 188 if (res) 189 return res; 190 191 res = fs_size(splash_file, &bmp_size); 192 if (res) { 193 printf("Error (%d): cannot determine file size\n", res); 194 return res; 195 } 196 197 if (bmp_load_addr + bmp_size >= gd->start_addr_sp) { 198 printf("Error: splashimage address too high. Data overwrites U-Boot and/or placed beyond DRAM boundaries.\n"); 199 return -EFAULT; 200 } 201 202 splash_select_fs_dev(location); 203 return fs_read(splash_file, bmp_load_addr, 0, 0, NULL); 204 } 205 206 /** 207 * select_splash_location - return the splash location based on board support 208 * and env variable "splashsource". 209 * 210 * @locations: An array of supported splash locations. 211 * @size: Size of splash_locations array. 212 * 213 * @return: If a null set of splash locations is given, or 214 * splashsource env variable is set to unsupported value 215 * return NULL. 216 * If splashsource env variable is not defined 217 * return the first entry in splash_locations as default. 218 * If splashsource env variable contains a supported value 219 * return the location selected by splashsource. 220 */ 221 static struct splash_location *select_splash_location( 222 struct splash_location *locations, uint size) 223 { 224 int i; 225 char *env_splashsource; 226 227 if (!locations || size == 0) 228 return NULL; 229 230 env_splashsource = getenv("splashsource"); 231 if (env_splashsource == NULL) 232 return &locations[0]; 233 234 for (i = 0; i < size; i++) { 235 if (!strcmp(locations[i].name, env_splashsource)) 236 return &locations[i]; 237 } 238 239 printf("splashsource env variable set to unsupported value\n"); 240 return NULL; 241 } 242 243 /** 244 * splash_source_load - load splash image from a supported location. 245 * 246 * Select a splash image location based on the value of splashsource environment 247 * variable and the board supported splash source locations, and load a 248 * splashimage to the address pointed to by splashimage environment variable. 249 * 250 * @locations: An array of supported splash locations. 251 * @size: Size of splash_locations array. 252 * 253 * @return: 0 on success, negative value on failure. 254 */ 255 int splash_source_load(struct splash_location *locations, uint size) 256 { 257 struct splash_location *splash_location; 258 char *env_splashimage_value; 259 u32 bmp_load_addr; 260 261 env_splashimage_value = getenv("splashimage"); 262 if (env_splashimage_value == NULL) 263 return -ENOENT; 264 265 bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16); 266 if (bmp_load_addr == 0) { 267 printf("Error: bad splashimage address specified\n"); 268 return -EFAULT; 269 } 270 271 splash_location = select_splash_location(locations, size); 272 if (!splash_location) 273 return -EINVAL; 274 275 if (splash_location->flags & SPLASH_STORAGE_RAW) 276 return splash_load_raw(splash_location, bmp_load_addr); 277 else if (splash_location->flags & SPLASH_STORAGE_FS) 278 return splash_load_fs(splash_location, bmp_load_addr); 279 280 return -EINVAL; 281 } 282