mtd: MTD related config header changes (mtdparts command)
[platform/kernel/u-boot.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  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  *
25  */
26
27 #include <common.h>
28
29 #if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
30 #error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
31 #endif
32
33 #if defined(CONFIG_SYS_NO_FLASH)
34 #error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature"
35 #endif
36
37 #include <command.h>
38 #include <flash.h>
39 #include <net.h>
40 #include <malloc.h>
41
42 /* env variable holding the location of the update file */
43 #define UPDATE_FILE_ENV         "updatefile"
44
45 /* set configuration defaults if needed */
46 #ifndef CONFIG_UPDATE_LOAD_ADDR
47 #define CONFIG_UPDATE_LOAD_ADDR 0x100000
48 #endif
49
50 #ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
51 #define CONFIG_UPDATE_TFTP_MSEC_MAX     100
52 #endif
53
54 #ifndef CONFIG_UPDATE_TFTP_CNT_MAX
55 #define CONFIG_UPDATE_TFTP_CNT_MAX      0
56 #endif
57
58 extern ulong TftpRRQTimeoutMSecs;
59 extern int TftpRRQTimeoutCountMax;
60 extern flash_info_t flash_info[];
61 extern ulong load_addr;
62
63 static uchar *saved_prot_info;
64
65 static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
66 {
67         int size, rv;
68         ulong saved_timeout_msecs;
69         int saved_timeout_count;
70         char *saved_netretry, *saved_bootfile;
71
72         rv = 0;
73         /* save used globals and env variable */
74         saved_timeout_msecs = TftpRRQTimeoutMSecs;
75         saved_timeout_count = TftpRRQTimeoutCountMax;
76         saved_netretry = strdup(getenv("netretry"));
77         saved_bootfile = strdup(BootFile);
78
79         /* set timeouts for auto-update */
80         TftpRRQTimeoutMSecs = msec_max;
81         TftpRRQTimeoutCountMax = cnt_max;
82
83         /* we don't want to retry the connection if errors occur */
84         setenv("netretry", "no");
85
86         /* download the update file */
87         load_addr = addr;
88         copy_filename(BootFile, filename, sizeof(BootFile));
89         size = NetLoop(TFTP);
90
91         if (size < 0)
92                 rv = 1;
93         else if (size > 0)
94                 flush_cache(addr, size);
95
96         /* restore changed globals and env variable */
97         TftpRRQTimeoutMSecs = saved_timeout_msecs;
98         TftpRRQTimeoutCountMax = saved_timeout_count;
99
100         setenv("netretry", saved_netretry);
101         if (saved_netretry != NULL)
102                 free(saved_netretry);
103
104         if (saved_bootfile != NULL) {
105                 copy_filename(BootFile, saved_bootfile, sizeof(BootFile));
106                 free(saved_bootfile);
107         }
108
109         return rv;
110 }
111
112 static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
113 {
114         uchar *sp_info_ptr;
115         ulong s;
116         int i, bank, cnt;
117         flash_info_t *info;
118
119         sp_info_ptr = NULL;
120
121         if (prot == 0) {
122                 saved_prot_info =
123                         calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
124                 if (!saved_prot_info)
125                         return 1;
126         }
127
128         for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
129                 cnt = 0;
130                 info = &flash_info[bank];
131
132                 /* Nothing to do if the bank doesn't exist */
133                 if (info->sector_count == 0)
134                         return 0;
135
136                 /* Point to current bank protection information */
137                 sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
138
139                 /*
140                  * Adjust addr_first or addr_last if we are on bank boundary.
141                  * Address space between banks must be continuous for other
142                  * flash functions (like flash_sect_erase or flash_write) to
143                  * succeed. Banks must also be numbered in correct order,
144                  * according to increasing addresses.
145                  */
146                 if (addr_last > info->start[0] + info->size - 1)
147                         addr_last = info->start[0] + info->size - 1;
148                 if (addr_first < info->start[0])
149                         addr_first = info->start[0];
150
151                 for (i = 0; i < info->sector_count; i++) {
152                         /* Save current information about protected sectors */
153                         if (prot == 0) {
154                                 s = info->start[i];
155                                 if ((s >= addr_first) && (s <= addr_last))
156                                         sp_info_ptr[i] = info->protect[i];
157
158                         }
159
160                         /* Protect/unprotect sectors */
161                         if (sp_info_ptr[i] == 1) {
162 #if defined(CONFIG_SYS_FLASH_PROTECTION)
163                                 if (flash_real_protect(info, i, prot))
164                                         return 1;
165 #else
166                                 info->protect[i] = prot;
167 #endif
168                                 cnt++;
169                         }
170                 }
171
172                 if (cnt) {
173                         printf("%sProtected %d sectors\n",
174                                                 prot ? "": "Un-", cnt);
175                 }
176         }
177
178         if((prot == 1) && saved_prot_info)
179                 free(saved_prot_info);
180
181         return 0;
182 }
183
184 static int update_flash(ulong addr_source, ulong addr_first, ulong size)
185 {
186         ulong addr_last = addr_first + size - 1;
187
188         /* round last address to the sector boundary */
189         if (flash_sect_roundb(&addr_last) > 0)
190                 return 1;
191
192         if (addr_first >= addr_last) {
193                 printf("Error: end address exceeds addressing space\n");
194                 return 1;
195         }
196
197         /* remove protection on processed sectors */
198         if (update_flash_protect(0, addr_first, addr_last) > 0) {
199                 printf("Error: could not unprotect flash sectors\n");
200                 return 1;
201         }
202
203         printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
204         if (flash_sect_erase(addr_first, addr_last) > 0) {
205                 printf("Error: could not erase flash\n");
206                 return 1;
207         }
208
209         printf("Copying to flash...");
210         if (flash_write((char *)addr_source, addr_first, size) > 0) {
211                 printf("Error: could not copy to flash\n");
212                 return 1;
213         }
214         printf("done\n");
215
216         /* enable protection on processed sectors */
217         if (update_flash_protect(1, addr_first, addr_last) > 0) {
218                 printf("Error: could not protect flash sectors\n");
219                 return 1;
220         }
221
222         return 0;
223 }
224
225 static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
226                                                 ulong *fladdr, ulong *size)
227 {
228         const void *data;
229
230         if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
231                 return 1;
232
233         if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
234                 return 1;
235
236         *addr = (ulong)data;
237
238         return 0;
239 }
240
241 void update_tftp(void)
242 {
243         char *filename, *env_addr;
244         int images_noffset, ndepth, noffset;
245         ulong update_addr, update_fladdr, update_size;
246         ulong addr;
247         void *fit;
248
249         printf("Auto-update from TFTP: ");
250
251         /* get the file name of the update file */
252         filename = getenv(UPDATE_FILE_ENV);
253         if (filename == NULL) {
254                 printf("failed, env. variable '%s' not found\n",
255                                                         UPDATE_FILE_ENV);
256                 return;
257         }
258
259         printf("trying update file '%s'\n", filename);
260
261         /* get load address of downloaded update file */
262         if ((env_addr = getenv("loadaddr")) != NULL)
263                 addr = simple_strtoul(env_addr, NULL, 16);
264         else
265                 addr = CONFIG_UPDATE_LOAD_ADDR;
266
267
268         if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
269                                         CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
270                 printf("Can't load update file, aborting auto-update\n");
271                 return;
272         }
273
274         fit = (void *)addr;
275
276         if (!fit_check_format((void *)fit)) {
277                 printf("Bad FIT format of the update file, aborting "
278                                                         "auto-update\n");
279                 return;
280         }
281
282         /* process updates */
283         images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
284
285         ndepth = 0;
286         noffset = fdt_next_node(fit, images_noffset, &ndepth);
287         while (noffset >= 0 && ndepth > 0) {
288                 if (ndepth != 1)
289                         goto next_node;
290
291                 printf("Processing update '%s' :",
292                         fit_get_name(fit, noffset, NULL));
293
294                 if (!fit_image_check_hashes(fit, noffset)) {
295                         printf("Error: invalid update hash, aborting\n");
296                         goto next_node;
297                 }
298
299                 printf("\n");
300                 if (update_fit_getparams(fit, noffset, &update_addr,
301                                         &update_fladdr, &update_size)) {
302                         printf("Error: can't get update parameteres, "
303                                                                 "aborting\n");
304                         goto next_node;
305                 }
306                 if (update_flash(update_addr, update_fladdr, update_size)) {
307                         printf("Error: can't flash update, aborting\n");
308                         goto next_node;
309                 }
310 next_node:
311                 noffset = fdt_next_node(fit, noffset, &ndepth);
312         }
313
314         return;
315 }