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