Home | History | Annotate | Download | only in spl
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2000-2004
      4  * Wolfgang Denk, DENX Software Engineering, wd (at) denx.de.
      5  *
      6  * (C) Copyright 2011
      7  * Texas Instruments, <www.ti.com>
      8  *
      9  * Matt Porter <mporter (at) ti.com>
     10  */
     11 #include <common.h>
     12 #include <spl.h>
     13 #include <xyzModem.h>
     14 #include <asm/u-boot.h>
     15 #include <asm/utils.h>
     16 #include <linux/libfdt.h>
     17 
     18 #define BUF_SIZE 1024
     19 
     20 /*
     21  * Information required to load image using ymodem.
     22  *
     23  * @image_read: Now of bytes read from the image.
     24  * @buf: pointer to the previous read block.
     25  */
     26 struct ymodem_fit_info {
     27 	int image_read;
     28 	char *buf;
     29 };
     30 
     31 static int getcymodem(void) {
     32 	if (tstc())
     33 		return (getc());
     34 	return -1;
     35 }
     36 
     37 static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset,
     38 			     ulong size, void *addr)
     39 {
     40 	int res, err;
     41 	struct ymodem_fit_info *info = load->priv;
     42 	char *buf = info->buf;
     43 
     44 	while (info->image_read < offset) {
     45 		res = xyzModem_stream_read(buf, BUF_SIZE, &err);
     46 		if (res <= 0)
     47 			return res;
     48 		info->image_read += res;
     49 	}
     50 
     51 	if (info->image_read > offset) {
     52 		res = info->image_read - offset;
     53 		memcpy(addr, &buf[BUF_SIZE - res], res);
     54 		addr = addr + res;
     55 	}
     56 
     57 	while (info->image_read < offset + size) {
     58 		res = xyzModem_stream_read(buf, BUF_SIZE, &err);
     59 		if (res <= 0)
     60 			return res;
     61 
     62 		memcpy(addr, buf, res);
     63 		info->image_read += res;
     64 		addr += res;
     65 	}
     66 
     67 	return size;
     68 }
     69 
     70 static int spl_ymodem_load_image(struct spl_image_info *spl_image,
     71 				 struct spl_boot_device *bootdev)
     72 {
     73 	int size = 0;
     74 	int err;
     75 	int res;
     76 	int ret;
     77 	connection_info_t info;
     78 	char buf[BUF_SIZE];
     79 	ulong addr = 0;
     80 
     81 	info.mode = xyzModem_ymodem;
     82 	ret = xyzModem_stream_open(&info, &err);
     83 	if (ret) {
     84 		printf("spl: ymodem err - %s\n", xyzModem_error(err));
     85 		return ret;
     86 	}
     87 
     88 	res = xyzModem_stream_read(buf, BUF_SIZE, &err);
     89 	if (res <= 0)
     90 		goto end_stream;
     91 
     92 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
     93 	    image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
     94 		struct spl_load_info load;
     95 		struct ymodem_fit_info info;
     96 
     97 		debug("Found FIT\n");
     98 		load.dev = NULL;
     99 		load.priv = (void *)&info;
    100 		load.filename = NULL;
    101 		load.bl_len = 1;
    102 		info.buf = buf;
    103 		info.image_read = BUF_SIZE;
    104 		load.read = ymodem_read_fit;
    105 		ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
    106 		size = info.image_read;
    107 
    108 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
    109 			size += res;
    110 	} else {
    111 		ret = spl_parse_image_header(spl_image,
    112 					     (struct image_header *)buf);
    113 		if (ret)
    114 			return ret;
    115 		addr = spl_image->load_addr;
    116 		memcpy((void *)addr, buf, res);
    117 		size += res;
    118 		addr += res;
    119 
    120 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
    121 			memcpy((void *)addr, buf, res);
    122 			size += res;
    123 			addr += res;
    124 		}
    125 	}
    126 
    127 end_stream:
    128 	xyzModem_stream_close(&err);
    129 	xyzModem_stream_terminate(false, &getcymodem);
    130 
    131 	printf("Loaded %d bytes\n", size);
    132 	return 0;
    133 }
    134 SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);
    135