1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2008 Semihalf
5 * Written by: Rafal Czubak <rcz@semihalf.com>
6 * Bartlomiej Sieka <tur@semihalf.com>
22 #if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
23 /* env variable holding the location of the update file */
24 #define UPDATE_FILE_ENV "updatefile"
26 extern ulong tftp_timeout_ms;
27 extern int tftp_timeout_count_max;
28 #ifdef CONFIG_MTD_NOR_FLASH
30 #include <mtd/cfi_flash.h>
31 static uchar *saved_prot_info;
33 static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
36 ulong saved_timeout_msecs;
37 int saved_timeout_count;
38 char *saved_netretry, *saved_bootfile;
41 /* save used globals and env variable */
42 saved_timeout_msecs = tftp_timeout_ms;
43 saved_timeout_count = tftp_timeout_count_max;
44 saved_netretry = strdup(env_get("netretry"));
45 saved_bootfile = strdup(net_boot_file_name);
47 /* set timeouts for auto-update */
48 tftp_timeout_ms = msec_max;
49 tftp_timeout_count_max = cnt_max;
51 /* we don't want to retry the connection if errors occur */
52 env_set("netretry", "no");
54 /* download the update file */
55 image_load_addr = addr;
56 copy_filename(net_boot_file_name, filename, sizeof(net_boot_file_name));
57 size = net_loop(TFTPGET);
62 flush_cache(addr, size);
64 /* restore changed globals and env variable */
65 tftp_timeout_ms = saved_timeout_msecs;
66 tftp_timeout_count_max = saved_timeout_count;
68 env_set("netretry", saved_netretry);
69 if (saved_netretry != NULL)
72 if (saved_bootfile != NULL) {
73 copy_filename(net_boot_file_name, saved_bootfile,
74 sizeof(net_boot_file_name));
81 #ifdef CONFIG_MTD_NOR_FLASH
82 static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
93 calloc(CFI_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
98 for (bank = 0; bank < CFI_FLASH_BANKS; ++bank) {
100 info = &flash_info[bank];
102 /* Nothing to do if the bank doesn't exist */
103 if (info->sector_count == 0)
106 /* Point to current bank protection information */
107 sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
110 * Adjust addr_first or addr_last if we are on bank boundary.
111 * Address space between banks must be continuous for other
112 * flash functions (like flash_sect_erase or flash_write) to
113 * succeed. Banks must also be numbered in correct order,
114 * according to increasing addresses.
116 if (addr_last > info->start[0] + info->size - 1)
117 addr_last = info->start[0] + info->size - 1;
118 if (addr_first < info->start[0])
119 addr_first = info->start[0];
121 for (i = 0; i < info->sector_count; i++) {
122 /* Save current information about protected sectors */
125 if ((s >= addr_first) && (s <= addr_last))
126 sp_info_ptr[i] = info->protect[i];
130 /* Protect/unprotect sectors */
131 if (sp_info_ptr[i] == 1) {
132 #if defined(CONFIG_SYS_FLASH_PROTECTION)
133 if (flash_real_protect(info, i, prot))
136 info->protect[i] = prot;
143 printf("%sProtected %d sectors\n",
144 prot ? "": "Un-", cnt);
148 if((prot == 1) && saved_prot_info)
149 free(saved_prot_info);
155 static int update_flash(ulong addr_source, ulong addr_first, ulong size)
157 #ifdef CONFIG_MTD_NOR_FLASH
158 ulong addr_last = addr_first + size - 1;
160 /* round last address to the sector boundary */
161 if (flash_sect_roundb(&addr_last) > 0)
164 if (addr_first >= addr_last) {
165 printf("Error: end address exceeds addressing space\n");
169 /* remove protection on processed sectors */
170 if (update_flash_protect(0, addr_first, addr_last) > 0) {
171 printf("Error: could not unprotect flash sectors\n");
175 printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
176 if (flash_sect_erase(addr_first, addr_last) > 0) {
177 printf("Error: could not erase flash\n");
181 printf("Copying to flash...");
182 if (flash_write((char *)addr_source, addr_first, size) > 0) {
183 printf("Error: could not copy to flash\n");
188 /* enable protection on processed sectors */
189 if (update_flash_protect(1, addr_first, addr_last) > 0) {
190 printf("Error: could not protect flash sectors\n");
196 #endif /* CONFIG_DFU_TFTP || CONFIG_UPDATE_TFTP */
198 static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
199 ulong *fladdr, ulong *size)
203 if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
206 if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
214 #if defined(CONFIG_DFU_TFTP) || defined(CONFIG_UPDATE_TFTP)
215 int update_tftp(ulong addr, char *interface, char *devstring)
217 char *filename, *env_addr, *fit_image_name;
218 ulong update_addr, update_fladdr, update_size;
219 int images_noffset, ndepth, noffset;
220 bool update_tftp_dfu;
224 if (interface == NULL && devstring == NULL) {
225 update_tftp_dfu = false;
226 } else if (interface && devstring) {
227 update_tftp_dfu = true;
229 pr_err("Interface: %s and devstring: %s not supported!\n",
230 interface, devstring);
234 /* use already present image */
236 goto got_update_file;
238 printf("Auto-update from TFTP: ");
240 /* get the file name of the update file */
241 filename = env_get(UPDATE_FILE_ENV);
242 if (filename == NULL) {
243 printf("failed, env. variable '%s' not found\n",
248 printf("trying update file '%s'\n", filename);
250 /* get load address of downloaded update file */
251 env_addr = env_get("loadaddr");
253 addr = hextoul(env_addr, NULL);
255 addr = CONFIG_UPDATE_LOAD_ADDR;
258 if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
259 CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
260 printf("Can't load update file, aborting auto-update\n");
265 fit = map_sysmem(addr, 0);
267 if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
268 printf("Bad FIT format of the update file, aborting "
273 /* process updates */
274 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
277 noffset = fdt_next_node(fit, images_noffset, &ndepth);
278 while (noffset >= 0 && ndepth > 0) {
282 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
283 printf("Processing update '%s' :", fit_image_name);
285 if (!fit_image_verify(fit, noffset)) {
286 printf("Error: invalid update hash, aborting\n");
292 if (update_fit_getparams(fit, noffset, &update_addr,
293 &update_fladdr, &update_size)) {
294 printf("Error: can't get update parameters, aborting\n");
299 if (!update_tftp_dfu) {
300 if (update_flash(update_addr, update_fladdr,
302 printf("Error: can't flash update, aborting\n");
306 } else if (fit_image_check_type(fit, noffset,
308 ret = dfu_write_by_name(fit_image_name,
310 update_size, interface,
316 noffset = fdt_next_node(fit, noffset, &ndepth);
321 #endif /* CONFIG_DFU_UPDATE || CONFIG_UPDATE_TFTP */
323 #ifdef CONFIG_UPDATE_FIT
325 * fit_update - update storage with FIT image
326 * @fit: Pointer to FIT image
328 * Update firmware on storage using FIT image as input.
329 * The storage area to be update will be identified by the name
330 * in FIT and matching it to "dfu_alt_info" variable.
332 * Return: 0 - on success, non-zero - otherwise
334 int fit_update(const void *fit)
336 char *fit_image_name;
337 ulong update_addr, update_fladdr, update_size;
338 int images_noffset, ndepth, noffset;
344 if (fit_check_format((void *)fit, IMAGE_SIZE_INVAL)) {
345 printf("Bad FIT format of the update file, aborting auto-update\n");
349 /* process updates */
350 images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
353 noffset = fdt_next_node(fit, images_noffset, &ndepth);
354 while (noffset >= 0 && ndepth > 0) {
358 fit_image_name = (char *)fit_get_name(fit, noffset, NULL);
359 printf("Processing update '%s' :", fit_image_name);
361 if (!fit_image_verify(fit, noffset)) {
362 printf("Error: invalid update hash, aborting\n");
368 if (update_fit_getparams(fit, noffset, &update_addr,
369 &update_fladdr, &update_size)) {
370 printf("Error: can't get update parameters, aborting\n");
375 if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) {
376 ret = dfu_write_by_name(fit_image_name,
378 update_size, NULL, NULL);
383 noffset = fdt_next_node(fit, noffset, &ndepth);
388 #endif /* CONFIG_UPDATE_FIT */