• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * auto_update.c
3  *
4  * Description:Read the image from the external storage medium SD or USB and
5  * burn it to the board storage medium.
6  *
7  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23 
24 #include <common.h>
25 #include <environment.h>
26 #include <command.h>
27 #include <malloc.h>
28 #include <image.h>
29 #include <asm/byteorder.h>
30 #include <asm/io.h>
31 #include <spi_flash.h>
32 #include <linux/mtd/mtd.h>
33 #include <fat.h>
34 
35 #if (CONFIG_AUTO_UPDATE == 1)  /* cover the whole file */
36 
37 #ifdef CONFIG_AUTO_SD_UPDATE
38 #ifndef CONFIG_MMC
39 #error "should have defined CONFIG_MMC"
40 #endif
41 #include <mmc.h>
42 #include "mmc_init.c"
43 #endif
44 
45 #if defined CONFIG_AUTO_USB_UPDATE
46 #if !defined CONFIG_USB_OHCI && !defined CONFIG_USB_XHCI
47 #error "should have defined CONFIG_USB_OHCI or CONFIG_USB_XHCI"
48 #endif
49 #ifndef CONFIG_USB_STORAGE
50 #error "should have defined CONFIG_USB_STORAGE"
51 #endif
52 #include <usb.h>
53 #include "usb_init.c"
54 #endif
55 
56 #undef AU_DEBUG
57 #undef debug
58 #ifdef  AU_DEBUG
59 #define debug(fmt, args...) printf(fmt, ##args)
60 #else
61 #define debug(fmt, args...)
62 #endif  /* AU_DEBUG */
63 
64 /* possible names of files on the medium. */
65 #define AU_FIRMWARE "u-boot"
66 #define AU_KERNEL   "kernel"
67 #define AU_ROOTFS   "rootfs"
68 
69 #define NAME_LEN	20
70 #define ENV_LEN		20
71 #define PERCENT		100
72 #define HEX		16
73 #define COUNT		3
74 #define MMC2		2
75 #define MAX_HZ		1000000UL
76 #define SPI_MODE3	3
77 
78 struct flash_layout {
79 	long start;
80 	long end;
81 };
82 static struct spi_flash *flash;
83 
84 struct medium_interface {
85 	char name[NAME_LEN];
86 	int (*init)(void);
87 	void (*exit)(void);
88 };
89 
90 #define MAX_UPDATE_INTF 3
91 static struct medium_interface s_intf[MAX_UPDATE_INTF] = {
92 #ifdef CONFIG_AUTO_SD_UPDATE
93 	{.name = "mmc", .init = mmc_stor_init,  .exit = mmc_stor_exit, },
94 #endif
95 #ifdef CONFIG_AUTO_USB_UPDATE
96 	{.name = "usb", .init = usb_stor_init,  .exit = usb_stor_exit, },
97 #endif
98 };
99 
100 /* layout of the FLASH. ST = start address, ND = end address. */
101 #define AU_FL_FIRMWARE_ST   0x0
102 #define AU_FL_FIRMWARE_ND   0x7FFFF
103 #define AU_FL_KERNEL_ST     0x100000
104 #define AU_FL_KERNEL_ND     0x5FFFFF
105 #define AU_FL_ROOTFS_ST     0x600000
106 #define AU_FL_ROOTFS_ND     0xbFFFFF
107 
108 static int au_stor_curr_dev; /* current device */
109 
110 /* index of each file in the following arrays */
111 #define IDX_FIRMWARE    0
112 #define IDX_KERNEL  1
113 #define IDX_ROOTFS  2
114 
115 /* max. number of files which could interest us */
116 #define AU_MAXFILES 3
117 
118 /* pointers to file names */
119 char *aufile[AU_MAXFILES] = {
120 	AU_FIRMWARE,
121 	AU_KERNEL,
122 	AU_ROOTFS
123 };
124 
125 /* sizes of flash areas for each file */
126 long ausize[AU_MAXFILES] = {
127 	(AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST,
128 	(AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST,
129 	(AU_FL_ROOTFS_ND + 1) - AU_FL_ROOTFS_ST,
130 };
131 
132 /* array of flash areas start and end addresses */
133 struct flash_layout aufl_layout[AU_MAXFILES] = {
134 	{ AU_FL_FIRMWARE_ST,    AU_FL_FIRMWARE_ND, },
135 	{ AU_FL_KERNEL_ST,  AU_FL_KERNEL_ND,   },
136 	{ AU_FL_ROOTFS_ST,  AU_FL_ROOTFS_ND,   },
137 };
138 
139 /* where to load files into memory */
140 #if defined(CONFIG_HI3559AV100ES)
141 #define LOAD_ADDR ((unsigned char *)0x42000000)
142 #else
143 #define LOAD_ADDR ((unsigned char *)0x82000000)
144 #endif
145 /* the app is the largest image */
146 #define MAX_LOADSZ ausize[IDX_ROOTFS]
147 
au_check_cksum_valid(int idx,long nbytes)148 static int au_check_cksum_valid(int idx, long nbytes)
149 {
150 	image_header_t *hdr;
151 	unsigned long checksum;
152 
153 	hdr = (image_header_t *)LOAD_ADDR;
154 
155 	if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
156 		printf("Image %s bad total SIZE\n", aufile[idx]);
157 		return -1;
158 	}
159 	/* check the data CRC */
160 	checksum = ntohl(hdr->ih_dcrc);
161 	if (crc32(0, (unsigned char const *)(LOAD_ADDR + sizeof(*hdr)),
162 			  ntohl(hdr->ih_size)) != checksum) {
163 		printf("Image %s bad data checksum\n", aufile[idx]);
164 		return -1;
165 	}
166 
167 	return 0;
168 }
169 
au_check_header_valid(int idx,long nbytes)170 static int au_check_header_valid(int idx, long nbytes)
171 {
172 	image_header_t *hdr;
173 	unsigned long checksum;
174 
175 	char env[ENV_LEN];
176 	char auversion[ENV_LEN];
177 
178 	hdr = (image_header_t *)LOAD_ADDR;
179 	/* check the easy ones first */
180 
181 #undef CHECK_VALID_DEBUG
182 #ifdef CHECK_VALID_DEBUG
183 	printf("\nmagic %#x %#x\n", ntohl(hdr->ih_magic), IH_MAGIC);
184 	printf("arch %#x %#x\n", hdr->ih_arch, IH_ARCH_ARM);
185 	printf("size %#x %#lx\n", ntohl(hdr->ih_size), nbytes);
186 	printf("type %#x %#x\n", hdr->ih_type, IH_TYPE_KERNEL);
187 #endif
188 	if (nbytes < sizeof(*hdr)) {
189 		printf("Image %s bad header SIZE\n", aufile[idx]);
190 		return -1;
191 	}
192 	if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_ARCH_ARM) {
193 		printf("Image %s bad MAGIC or ARCH\n", aufile[idx]);
194 		return -1;
195 	}
196 	/* check the hdr CRC */
197 	checksum = ntohl(hdr->ih_hcrc);
198 	hdr->ih_hcrc = 0;
199 
200 	if (crc32(0, (unsigned char const *)hdr, sizeof(*hdr)) != checksum) {
201 		printf("Image %s bad header checksum\n", aufile[idx]);
202 		return -1;
203 	}
204 	hdr->ih_hcrc = htonl(checksum);
205 	/* check the type - could do this all in one gigantic if() */
206 	if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
207 		printf("Image %s wrong type\n", aufile[idx]);
208 		return -1;
209 	}
210 	if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) {
211 		printf("Image %s wrong type\n", aufile[idx]);
212 		return -1;
213 	}
214 	if ((idx == IDX_ROOTFS) &&
215 		(hdr->ih_type != IH_TYPE_RAMDISK) &&
216 		(hdr->ih_type != IH_TYPE_FILESYSTEM)) {
217 		printf("Image %s wrong type\n", aufile[idx]);
218 		ausize[idx] = 0;
219 		return -1;
220 	}
221 
222 	/* recycle checksum */
223 	checksum = ntohl(hdr->ih_size);
224 	/* for kernel and app the image header must also fit into flash */
225 	if ((idx == IDX_KERNEL) || (hdr->ih_type == IH_TYPE_RAMDISK))
226 		checksum += sizeof(*hdr);
227 
228 	/* check the size does not exceed space in flash. HUSH scripts */
229 	/* all have ausize[] set to 0 */
230 	if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
231 		printf("Image %s is bigger than FLASH\n", aufile[idx]);
232 		return -1;
233 	}
234 
235 	sprintf(env, "%lx", (unsigned long)ntohl(hdr->ih_time));
236 	setenv(auversion, env);
237 
238 	return 0;
239 }
240 
schedule_notify(unsigned long offset,unsigned long len,unsigned long off_start)241 static void schedule_notify(unsigned long offset, unsigned long len,
242 						unsigned long off_start)
243 {
244 	int percent_complete = -1;
245 
246 	do {
247 		unsigned long long n =
248 				(unsigned long long)(offset - off_start) * PERCENT;
249 		int percent;
250 
251 		do_div(n, len);
252 		percent = (int)n;
253 
254 		/* output progress message only at whole percent
255 		 * steps to reduce the number of messages
256 		 * printed on (slow) serial consoles
257 		 */
258 		if (percent != percent_complete) {
259 			percent_complete = percent;
260 
261 			printf("\rOperation at 0x%lx -- %3d%% complete",
262 				   offset, percent);
263 		}
264 	} while (0);
265 }
266 
spi_flash_erase_op(struct spi_flash * flash,unsigned long offset,unsigned long len)267 static int spi_flash_erase_op(struct spi_flash *flash, unsigned long offset,
268 							  unsigned long len)
269 {
270 	int ret;
271 	struct mtd_info_ex *spiflash_info = get_spiflash_info();
272 	unsigned long erase_start, erase_len, erase_step;
273 
274 	erase_start = offset;
275 	erase_len   = len;
276 	erase_step  = spiflash_info->erasesize;
277 
278 	while (len > 0) {
279 		if (len < erase_step)
280 			erase_step = len;
281 
282 		ret = flash->erase(flash, (u32)offset, erase_step);
283 		if (ret)
284 			return 1;
285 
286 		len -= erase_step;
287 		offset += erase_step;
288 		/* notify real time schedule */
289 		schedule_notify(offset, erase_len, erase_start);
290 	}
291 	return ret;
292 }
293 
spi_flash_write_op(struct spi_flash * flash,unsigned long offset,unsigned long len,char * buf)294 static int spi_flash_write_op(struct spi_flash *flash, unsigned long offset,
295 						unsigned long len, char *buf)
296 {
297 	int ret;
298 	unsigned long write_start, write_len, write_step;
299 	char *pbuf = buf;
300 	struct mtd_info_ex *spiflash_info = get_spiflash_info();
301 
302 	write_start = offset;
303 	write_len   = len;
304 	write_step  = spiflash_info->erasesize;
305 
306 	while (len > 0) {
307 		if (len < write_step)
308 			write_step = len;
309 
310 		ret = flash->write(flash, offset, write_step, pbuf);
311 		if (ret)
312 			break;
313 
314 		offset += write_step;
315 		pbuf   += write_step;
316 		len    -= write_step;
317 		/* notify real time schedule */
318 		schedule_notify(offset, write_len, write_start);
319 	}
320 
321 	return ret;
322 }
323 
au_do_update(int idx,long sz)324 static int au_do_update(int idx, long sz)
325 {
326 	image_header_t *hdr;
327 	unsigned long start, len;
328 	unsigned long write_len;
329 	int rc;
330 	void *buf;
331 	char *pbuf;
332 
333 	hdr = (image_header_t *)LOAD_ADDR;
334 
335 	start = aufl_layout[idx].start;
336 	len = aufl_layout[idx].end - aufl_layout[idx].start + 1;
337 
338 	/*
339 	 * erase the address range.
340 	 */
341 	printf("flash erase...\n");
342 	rc = spi_flash_erase_op(flash, start, len);
343 	if (rc) {
344 		printf("SPI flash sector erase failed\n");
345 		return 1;
346 	}
347 
348 	buf = map_physmem((unsigned long)LOAD_ADDR, len, MAP_WRBACK);
349 	if (!buf) {
350 		puts("Failed to map physical memory\n");
351 		return 1;
352 	}
353 
354 	/* strip the header - except for the kernel and ramdisk */
355 	if (hdr->ih_type == IH_TYPE_KERNEL || hdr->ih_type == IH_TYPE_RAMDISK) {
356 		pbuf = buf;
357 		write_len = sizeof(*hdr) + ntohl(hdr->ih_size);
358 	} else {
359 		pbuf = (buf + sizeof(*hdr));
360 		write_len = ntohl(hdr->ih_size);
361 	}
362 
363 	/* copy the data from RAM to FLASH */
364 	printf("\nflash write...\n");
365 	rc = spi_flash_write_op(flash, start, write_len, pbuf);
366 	if (rc) {
367 		printf("SPI flash write failed, return %d\n", rc);
368 		return 1;
369 	}
370 
371 	/* check the dcrc of the copy */
372 	if (crc32(0, (unsigned char const *)(buf + sizeof(*hdr)),
373 			  ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) {
374 		printf("Image %s Bad Data Checksum After COPY\n", aufile[idx]);
375 		return -1;
376 	}
377 
378 	unmap_physmem(buf, len);
379 
380 	return 0;
381 }
382 
get_update_env(char * img_start,char * img_end)383 static void get_update_env(char *img_start, char *img_end)
384 {
385 	long start = -1;
386 	long end = 0;
387 	char *env;
388 
389 	/*
390 	 * check whether start and end are defined in environment
391 	 * variables.
392 	 */
393 	env = env_get(img_start);
394 	if (env != NULL)
395 		start = simple_strtoul(env, NULL, HEX);
396 
397 	env = env_get(img_end);
398 	if (env != NULL)
399 		end = simple_strtoul(env, NULL, HEX);
400 
401 	if (start >= 0 && end && end > start) {
402 		ausize[IDX_FIRMWARE] = (end + 1) - start;
403 		aufl_layout[0].start = start;
404 		aufl_layout[0].end = end;
405 	}
406 }
407 
408 /*
409  * If none of the update file(u-boot, kernel or rootfs) was found
410  * in the medium, return -1;
411  * If u-boot has been updated, return 1;
412  * Others, return 0;
413  */
update_to_flash(void)414 static int update_to_flash(void)
415 {
416 	int i;
417 	long sz;
418 	int res, cnt;
419 	int uboot_updated;
420 	int image_found;
421 
422 	/* just loop thru all the possible files */
423 	for (i = 0; i < AU_MAXFILES; i++) {
424 		/* just read the header */
425 		sz = file_fat_read(aufile[i], LOAD_ADDR, sizeof(image_header_t));
426 		debug("read %s sz %ld hdr %d\n", aufile[i], sz, sizeof(image_header_t));
427 		if (sz <= 0 || sz < sizeof(image_header_t)) {
428 			debug("%s not found\n", aufile[i]);
429 			continue;
430 		}
431 
432 		image_found = 1;
433 
434 		if (au_check_header_valid(i, sz) < 0) {
435 			debug("%s header not valid\n", aufile[i]);
436 			continue;
437 		}
438 
439 		sz = file_fat_read(aufile[i], LOAD_ADDR, MAX_LOADSZ);
440 		debug("read %s sz %ld hdr %d\n", aufile[i], sz, sizeof(image_header_t));
441 		if (sz <= 0 || sz <= sizeof(image_header_t)) {
442 			debug("%s not found\n", aufile[i]);
443 			continue;
444 		}
445 
446 		if (au_check_cksum_valid(i, sz) < 0) {
447 			debug("%s checksum not valid\n", aufile[i]);
448 			continue;
449 		}
450 
451 		/* If u-boot had been updated, we need to
452 		 * save current env to flash
453 		 */
454 		if (strcmp((char *)AU_FIRMWARE, aufile[i]) == 0)
455 			uboot_updated = 1;
456 
457 		/* this is really not a good idea, but it's what the customer wants. */
458 		cnt = 0;
459 		do {
460 			res = au_do_update(i, sz);
461 			/* let the user break out of the loop */
462 			if (ctrlc() || had_ctrlc()) {
463 				clear_ctrlc();
464 
465 				break;
466 			}
467 			cnt++;
468 		} while (res < 0);
469 	}
470 
471 	if (uboot_updated == 1)
472 		return 1;
473 
474 	if (image_found == 1)
475 		return 0;
476 
477 	return -1;
478 }
479 
480 /*
481  * This is called by board_init() after the hardware has been set up
482  * and is usable. Only if SPI flash initialization failed will this function
483  * return -1, otherwise it will return 0;
484  */
do_auto_update(void)485 int do_auto_update(void)
486 {
487 	struct blk_desc *stor_dev;
488 	int old_ctrlc;
489 	int j;
490 	int state = -1;
491 	int dev;
492 
493 	au_stor_curr_dev = -1;
494 	for (j = 0; j < MAX_UPDATE_INTF; j++) {
495 		if ((unsigned long)s_intf[j].name[0] != 0) {
496 			au_stor_curr_dev = s_intf[j].init();
497 			if (au_stor_curr_dev == -1) {
498 				debug("No %s storage device found!\n",
499 					  s_intf[j].name);
500 				continue;
501 			}
502 
503 			dev = 0;
504 
505 #if (defined CONFIG_ARCH_HI3559AV100ES)
506 			if (strncmp("mmc", s_intf[j].name, sizeof("mmc")) == 0)
507 				dev = MMC2;
508 #endif
509 			debug("device name %s!\n", s_intf[j].name);
510 			stor_dev = blk_get_dev(s_intf[j].name, dev);
511 			if (stor_dev == NULL) {
512 				debug("Unknow device type!\n");
513 				continue;
514 			}
515 
516 			if (fat_register_device(stor_dev, 1) != 0) {
517 				debug("Unable to use %s %d:%d for fatls\n",
518 						s_intf[j].name, au_stor_curr_dev, 1);
519 				continue;
520 			}
521 
522 			if (file_fat_detectfs() != 0) {
523 				debug("file_fat_detectfs failed\n");
524 				continue;
525 			}
526 
527 			/*
528 			 * Get image layout from environment.
529 			 * If the start address and the end address
530 			 * were not definedin environment virables,
531 			 * use the default value
532 			 */
533 			get_update_env("firmware_st", "firmware_nd");
534 			get_update_env("kernel_st", "kernel_nd");
535 			get_update_env("rootfs_st", "rootfs_nd");
536 
537 			/*
538 			 * make sure that we see CTRL-C
539 			 * and save the old state
540 			 */
541 			old_ctrlc = disable_ctrlc(0);
542 
543 			/*
544 			 * CONFIG_SF_DEFAULT_SPEED equals 1000000,
545 			 * CONFIG_SF_DEFAULT_MODE equals 0x3
546 			 */
547 			flash = spi_flash_probe(0, 0, MAX_HZ, SPI_MODE3);
548 			if (!flash) {
549 				printf("Failed to initialize SPI flash\n");
550 				return -1;
551 			}
552 
553 			state = update_to_flash();
554 
555 			/* restore the old state */
556 			disable_ctrlc(old_ctrlc);
557 
558 			s_intf[j].exit();
559 
560 			/*
561 			 * no update file found
562 			 */
563 			if (state == -1)
564 				continue;
565 			/*
566 			 * update files have been found on current medium,
567 			 * so just break here
568 			 */
569 			break;
570 		}
571 	}
572 
573 	/*
574 	 * If u-boot has been updated, it's better to save environment to flash
575 	 */
576 	if (state == 1)
577 		saveenv();
578 	return 0;
579 }
580 #endif /* CONFIG_AUTO_UPDATE */
581