1 /* 2 * (C) Copyright 2008 Semihalf 3 * 4 * Written by: Rafal Czubak <rcz@semihalf.com> 5 * Bartlomiej Sieka <tur@semihalf.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 12 #if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT)) 13 #error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature" 14 #endif 15 16 #if defined(CONFIG_UPDATE_TFTP) && !defined(CONFIG_MTD_NOR_FLASH) 17 #error "CONFIG_UPDATE_TFTP and !CONFIG_MTD_NOR_FLASH needed for legacy behaviour" 18 #endif 19 20 #include <command.h> 21 #include <flash.h> 22 #include <net.h> 23 #include <net/tftp.h> 24 #include <malloc.h> 25 #include <dfu.h> 26 #include <errno.h> 27 #include <mtd/cfi_flash.h> 28 29 /* env variable holding the location of the update file */ 30 #define UPDATE_FILE_ENV "updatefile" 31 32 /* set configuration defaults if needed */ 33 #ifndef CONFIG_UPDATE_LOAD_ADDR 34 #define CONFIG_UPDATE_LOAD_ADDR 0x100000 35 #endif 36 37 #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX 38 #define CONFIG_UPDATE_TFTP_MSEC_MAX 100 39 #endif 40 41 #ifndef CONFIG_UPDATE_TFTP_CNT_MAX 42 #define CONFIG_UPDATE_TFTP_CNT_MAX 0 43 #endif 44 45 extern ulong tftp_timeout_ms; 46 extern int tftp_timeout_count_max; 47 extern ulong load_addr; 48 #ifdef CONFIG_MTD_NOR_FLASH 49 extern flash_info_t flash_info[]; 50 static uchar *saved_prot_info; 51 #endif 52 static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr) 53 { 54 int size, rv; 55 ulong saved_timeout_msecs; 56 int saved_timeout_count; 57 char *saved_netretry, *saved_bootfile; 58 59 rv = 0; 60 /* save used globals and env variable */ 61 saved_timeout_msecs = tftp_timeout_ms; 62 saved_timeout_count = tftp_timeout_count_max; 63 saved_netretry = strdup(env_get("netretry")); 64 saved_bootfile = strdup(net_boot_file_name); 65 66 /* set timeouts for auto-update */ 67 tftp_timeout_ms = msec_max; 68 tftp_timeout_count_max = cnt_max; 69 70 /* we don't want to retry the connection if errors occur */ 71 env_set("netretry", "no"); 72 73 /* download the update file */ 74 load_addr = addr; 75 copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name)); 76 size = net_loop(TFTPGET); 77 78 if (size < 0) 79 rv = 1; 80 else if (size > 0) 81 flush_cache(addr, size); 82 83 /* restore changed globals and env variable */ 84 tftp_timeout_ms = saved_timeout_msecs; 85 tftp_timeout_count_max = saved_timeout_count; 86 87 env_set("netretry", saved_netretry); 88 if (saved_netretry != NULL) 89 free(saved_netretry); 90 91 if (saved_bootfile != NULL) { 92 copy_filename(net_boot_file_name, saved_bootfile, 93 sizeof(net_boot_file_name)); 94 free(saved_bootfile); 95 } 96 97 return rv; 98 } 99 100 #ifdef CONFIG_MTD_NOR_FLASH 101 static int update_flash_protect(int prot, ulong addr_first, ulong addr_last) 102 { 103 uchar *sp_info_ptr; 104 ulong s; 105 int i, bank, cnt; 106 flash_info_t *info; 107 108 sp_info_ptr = NULL; 109 110 if (prot == 0) { 111 saved_prot_info = 112 calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1); 113 if (!saved_prot_info) 114 return 1; 115 } 116 117 for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { 118 cnt = 0; 119 info = &flash_info[bank]; 120 121 /* Nothing to do if the bank doesn't exist */ 122 if (info->sector_count == 0) 123 return 0; 124 125 /* Point to current bank protection information */ 126 sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT); 127 128 /* 129 * Adjust addr_first or addr_last if we are on bank boundary. 130 * Address space between banks must be continuous for other 131 * flash functions (like flash_sect_erase or flash_write) to 132 * succeed. Banks must also be numbered in correct order, 133 * according to increasing addresses. 134 */ 135 if (addr_last > info->start[0] + info->size - 1) 136 addr_last = info->start[0] + info->size - 1; 137 if (addr_first < info->start[0]) 138 addr_first = info->start[0]; 139 140 for (i = 0; i < info->sector_count; i++) { 141 /* Save current information about protected sectors */ 142 if (prot == 0) { 143 s = info->start[i]; 144 if ((s >= addr_first) && (s <= addr_last)) 145 sp_info_ptr[i] = info->protect[i]; 146 147 } 148 149 /* Protect/unprotect sectors */ 150 if (sp_info_ptr[i] == 1) { 151 #if defined(CONFIG_SYS_FLASH_PROTECTION) 152 if (flash_real_protect(info, i, prot)) 153 return 1; 154 #else 155 info->protect[i] = prot; 156 #endif 157 cnt++; 158 } 159 } 160 161 if (cnt) { 162 printf("%sProtected %d sectors\n", 163 prot ? "": "Un-", cnt); 164 } 165 } 166 167 if((prot == 1) && saved_prot_info) 168 free(saved_prot_info); 169 170 return 0; 171 } 172 #endif 173 174 static int update_flash(ulong addr_source, ulong addr_first, ulong size) 175 { 176 #ifdef CONFIG_MTD_NOR_FLASH 177 ulong addr_last = addr_first + size - 1; 178 179 /* round last address to the sector boundary */ 180 if (flash_sect_roundb(&addr_last) > 0) 181 return 1; 182 183 if (addr_first >= addr_last) { 184 printf("Error: end address exceeds addressing space\n"); 185 return 1; 186 } 187 188 /* remove protection on processed sectors */ 189 if (update_flash_protect(0, addr_first, addr_last) > 0) { 190 printf("Error: could not unprotect flash sectors\n"); 191 return 1; 192 } 193 194 printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last); 195 if (flash_sect_erase(addr_first, addr_last) > 0) { 196 printf("Error: could not erase flash\n"); 197 return 1; 198 } 199 200 printf("Copying to flash..."); 201 if (flash_write((char *)addr_source, addr_first, size) > 0) { 202 printf("Error: could not copy to flash\n"); 203 return 1; 204 } 205 printf("done\n"); 206 207 /* enable protection on processed sectors */ 208 if (update_flash_protect(1, addr_first, addr_last) > 0) { 209 printf("Error: could not protect flash sectors\n"); 210 return 1; 211 } 212 #endif 213 return 0; 214 } 215 216 static int update_fit_getparams(const void *fit, int noffset, ulong *addr, 217 ulong *fladdr, ulong *size) 218 { 219 const void *data; 220 221 if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) 222 return 1; 223 224 if (fit_image_get_load(fit, noffset, (ulong *)fladdr)) 225 return 1; 226 227 *addr = (ulong)data; 228 229 return 0; 230 } 231 232 int update_tftp(ulong addr, char *interface, char *devstring) 233 { 234 char *filename, *env_addr, *fit_image_name; 235 ulong update_addr, update_fladdr, update_size; 236 int images_noffset, ndepth, noffset; 237 bool update_tftp_dfu; 238 int ret = 0; 239 void *fit; 240 241 if (interface == NULL && devstring == NULL) { 242 update_tftp_dfu = false; 243 } else if (interface && devstring) { 244 update_tftp_dfu = true; 245 } else { 246 pr_err("Interface: %s and devstring: %s not supported!\n", 247 interface, devstring); 248 return -EINVAL; 249 } 250 251 /* use already present image */ 252 if (addr) 253 goto got_update_file; 254 255 printf("Auto-update from TFTP: "); 256 257 /* get the file name of the update file */ 258 filename = env_get(UPDATE_FILE_ENV); 259 if (filename == NULL) { 260 printf("failed, env. variable '%s' not found\n", 261 UPDATE_FILE_ENV); 262 return 1; 263 } 264 265 printf("trying update file '%s'\n", filename); 266 267 /* get load address of downloaded update file */ 268 env_addr = env_get("loadaddr"); 269 if (env_addr) 270 addr = simple_strtoul(env_addr, NULL, 16); 271 else 272 addr = CONFIG_UPDATE_LOAD_ADDR; 273 274 275 if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX, 276 CONFIG_UPDATE_TFTP_CNT_MAX, addr)) { 277 printf("Can't load update file, aborting auto-update\n"); 278 return 1; 279 } 280 281 got_update_file: 282 fit = (void *)addr; 283 284 if (!fit_check_format((void *)fit)) { 285 printf("Bad FIT format of the update file, aborting " 286 "auto-update\n"); 287 return 1; 288 } 289 290 /* process updates */ 291 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); 292 293 ndepth = 0; 294 noffset = fdt_next_node(fit, images_noffset, &ndepth); 295 while (noffset >= 0 && ndepth > 0) { 296 if (ndepth != 1) 297 goto next_node; 298 299 fit_image_name = (char *)fit_get_name(fit, noffset, NULL); 300 printf("Processing update '%s' :", fit_image_name); 301 302 if (!fit_image_verify(fit, noffset)) { 303 printf("Error: invalid update hash, aborting\n"); 304 ret = 1; 305 goto next_node; 306 } 307 308 printf("\n"); 309 if (update_fit_getparams(fit, noffset, &update_addr, 310 &update_fladdr, &update_size)) { 311 printf("Error: can't get update parameteres, " 312 "aborting\n"); 313 ret = 1; 314 goto next_node; 315 } 316 317 if (!update_tftp_dfu) { 318 if (update_flash(update_addr, update_fladdr, 319 update_size)) { 320 printf("Error: can't flash update, aborting\n"); 321 ret = 1; 322 goto next_node; 323 } 324 } else if (fit_image_check_type(fit, noffset, 325 IH_TYPE_FIRMWARE)) { 326 ret = dfu_tftp_write(fit_image_name, update_addr, 327 update_size, interface, devstring); 328 if (ret) 329 return ret; 330 } 331 next_node: 332 noffset = fdt_next_node(fit, noffset, &ndepth); 333 } 334 335 return ret; 336 } 337