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