xref: /rk3399_rockchip-uboot/common/spl/spl_ymodem.c (revision 0e00a84cdedf7a1949486746225b35984b351eca)
147f7bcaeSTom Rini /*
247f7bcaeSTom Rini  * (C) Copyright 2000-2004
347f7bcaeSTom Rini  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
447f7bcaeSTom Rini  *
547f7bcaeSTom Rini  * (C) Copyright 2011
647f7bcaeSTom Rini  * Texas Instruments, <www.ti.com>
747f7bcaeSTom Rini  *
847f7bcaeSTom Rini  * Matt Porter <mporter@ti.com>
947f7bcaeSTom Rini  *
101a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
1147f7bcaeSTom Rini  */
1247f7bcaeSTom Rini #include <common.h>
1347f7bcaeSTom Rini #include <spl.h>
1447f7bcaeSTom Rini #include <xyzModem.h>
1547f7bcaeSTom Rini #include <asm/u-boot.h>
1647f7bcaeSTom Rini #include <asm/utils.h>
17*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
1847f7bcaeSTom Rini 
1947f7bcaeSTom Rini #define BUF_SIZE 1024
2047f7bcaeSTom Rini 
21fa715193SLokesh Vutla /*
22fa715193SLokesh Vutla  * Information required to load image using ymodem.
23fa715193SLokesh Vutla  *
24fa715193SLokesh Vutla  * @image_read: Now of bytes read from the image.
25fa715193SLokesh Vutla  * @buf: pointer to the previous read block.
26fa715193SLokesh Vutla  */
27fa715193SLokesh Vutla struct ymodem_fit_info {
28fa715193SLokesh Vutla 	int image_read;
29fa715193SLokesh Vutla 	char *buf;
30fa715193SLokesh Vutla };
31fa715193SLokesh Vutla 
getcymodem(void)3247f7bcaeSTom Rini static int getcymodem(void) {
3347f7bcaeSTom Rini 	if (tstc())
3447f7bcaeSTom Rini 		return (getc());
3547f7bcaeSTom Rini 	return -1;
3647f7bcaeSTom Rini }
3747f7bcaeSTom Rini 
ymodem_read_fit(struct spl_load_info * load,ulong offset,ulong size,void * addr)38fa715193SLokesh Vutla static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset,
39fa715193SLokesh Vutla 			     ulong size, void *addr)
40fa715193SLokesh Vutla {
41fa715193SLokesh Vutla 	int res, err;
42fa715193SLokesh Vutla 	struct ymodem_fit_info *info = load->priv;
43fa715193SLokesh Vutla 	char *buf = info->buf;
44fa715193SLokesh Vutla 
45fa715193SLokesh Vutla 	while (info->image_read < offset) {
46fa715193SLokesh Vutla 		res = xyzModem_stream_read(buf, BUF_SIZE, &err);
47fa715193SLokesh Vutla 		if (res <= 0)
48fa715193SLokesh Vutla 			return res;
49fa715193SLokesh Vutla 		info->image_read += res;
50fa715193SLokesh Vutla 	}
51fa715193SLokesh Vutla 
52fa715193SLokesh Vutla 	if (info->image_read > offset) {
53fa715193SLokesh Vutla 		res = info->image_read - offset;
54fa715193SLokesh Vutla 		memcpy(addr, &buf[BUF_SIZE - res], res);
55fa715193SLokesh Vutla 		addr = addr + res;
56fa715193SLokesh Vutla 	}
57fa715193SLokesh Vutla 
58fa715193SLokesh Vutla 	while (info->image_read < offset + size) {
59fa715193SLokesh Vutla 		res = xyzModem_stream_read(buf, BUF_SIZE, &err);
60fa715193SLokesh Vutla 		if (res <= 0)
61fa715193SLokesh Vutla 			return res;
62fa715193SLokesh Vutla 
63fa715193SLokesh Vutla 		memcpy(addr, buf, res);
64fa715193SLokesh Vutla 		info->image_read += res;
65fa715193SLokesh Vutla 		addr += res;
66fa715193SLokesh Vutla 	}
67fa715193SLokesh Vutla 
68fa715193SLokesh Vutla 	return size;
69fa715193SLokesh Vutla }
70fa715193SLokesh Vutla 
spl_ymodem_load_image(struct spl_image_info * spl_image,struct spl_boot_device * bootdev)712a2ee2acSSimon Glass static int spl_ymodem_load_image(struct spl_image_info *spl_image,
722a2ee2acSSimon Glass 				 struct spl_boot_device *bootdev)
7347f7bcaeSTom Rini {
7447f7bcaeSTom Rini 	int size = 0;
7547f7bcaeSTom Rini 	int err;
7647f7bcaeSTom Rini 	int res;
7747f7bcaeSTom Rini 	int ret;
7847f7bcaeSTom Rini 	connection_info_t info;
7947f7bcaeSTom Rini 	char buf[BUF_SIZE];
8047f7bcaeSTom Rini 	ulong addr = 0;
8147f7bcaeSTom Rini 
8247f7bcaeSTom Rini 	info.mode = xyzModem_ymodem;
8347f7bcaeSTom Rini 	ret = xyzModem_stream_open(&info, &err);
84fa715193SLokesh Vutla 	if (ret) {
8547f7bcaeSTom Rini 		printf("spl: ymodem err - %s\n", xyzModem_error(err));
8636afd451SNikita Kiryanov 		return ret;
8747f7bcaeSTom Rini 	}
8847f7bcaeSTom Rini 
89fa715193SLokesh Vutla 	res = xyzModem_stream_read(buf, BUF_SIZE, &err);
90fa715193SLokesh Vutla 	if (res <= 0)
91fa715193SLokesh Vutla 		goto end_stream;
92fa715193SLokesh Vutla 
93fa715193SLokesh Vutla 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
94fa715193SLokesh Vutla 	    image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
95fa715193SLokesh Vutla 		struct spl_load_info load;
96fa715193SLokesh Vutla 		struct ymodem_fit_info info;
97fa715193SLokesh Vutla 
98fa715193SLokesh Vutla 		debug("Found FIT\n");
99fa715193SLokesh Vutla 		load.dev = NULL;
100fa715193SLokesh Vutla 		load.priv = (void *)&info;
101fa715193SLokesh Vutla 		load.filename = NULL;
102fa715193SLokesh Vutla 		load.bl_len = 1;
103fa715193SLokesh Vutla 		info.buf = buf;
104fa715193SLokesh Vutla 		info.image_read = BUF_SIZE;
105fa715193SLokesh Vutla 		load.read = ymodem_read_fit;
106f4d7d859SSimon Glass 		ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
107fa715193SLokesh Vutla 		size = info.image_read;
108fa715193SLokesh Vutla 
109fa715193SLokesh Vutla 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
110fa715193SLokesh Vutla 			size += res;
111fa715193SLokesh Vutla 	} else {
1122a2ee2acSSimon Glass 		ret = spl_parse_image_header(spl_image,
11371316c1dSSimon Glass 					     (struct image_header *)buf);
114fa715193SLokesh Vutla 		if (ret)
115fa715193SLokesh Vutla 			return ret;
1162a2ee2acSSimon Glass 		addr = spl_image->load_addr;
117fa715193SLokesh Vutla 		memcpy((void *)addr, buf, res);
118fa715193SLokesh Vutla 		size += res;
119fa715193SLokesh Vutla 		addr += res;
120fa715193SLokesh Vutla 
121fa715193SLokesh Vutla 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) {
122fa715193SLokesh Vutla 			memcpy((void *)addr, buf, res);
123fa715193SLokesh Vutla 			size += res;
124fa715193SLokesh Vutla 			addr += res;
125fa715193SLokesh Vutla 		}
126fa715193SLokesh Vutla 	}
127fa715193SLokesh Vutla 
128fa715193SLokesh Vutla end_stream:
12947f7bcaeSTom Rini 	xyzModem_stream_close(&err);
13047f7bcaeSTom Rini 	xyzModem_stream_terminate(false, &getcymodem);
13147f7bcaeSTom Rini 
13247f7bcaeSTom Rini 	printf("Loaded %d bytes\n", size);
13336afd451SNikita Kiryanov 	return 0;
13447f7bcaeSTom Rini }
135ebc4ef61SSimon Glass SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);
136