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