xref: /rk3399_rockchip-uboot/common/spl/spl_ymodem.c (revision dd6bf9025c2fd8ef0860e6e3ff4c12bc202fc64a)
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>
17fa715193SLokesh Vutla #include <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 
3247f7bcaeSTom Rini static int getcymodem(void) {
3347f7bcaeSTom Rini 	if (tstc())
3447f7bcaeSTom Rini 		return (getc());
3547f7bcaeSTom Rini 	return -1;
3647f7bcaeSTom Rini }
3747f7bcaeSTom Rini 
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 
71*dd6bf902SSimon Glass static int spl_ymodem_load_image(struct spl_boot_device *bootdev)
7247f7bcaeSTom Rini {
7347f7bcaeSTom Rini 	int size = 0;
7447f7bcaeSTom Rini 	int err;
7547f7bcaeSTom Rini 	int res;
7647f7bcaeSTom Rini 	int ret;
7747f7bcaeSTom Rini 	connection_info_t info;
7847f7bcaeSTom Rini 	char buf[BUF_SIZE];
7947f7bcaeSTom Rini 	ulong addr = 0;
8047f7bcaeSTom Rini 
8147f7bcaeSTom Rini 	info.mode = xyzModem_ymodem;
8247f7bcaeSTom Rini 	ret = xyzModem_stream_open(&info, &err);
83fa715193SLokesh Vutla 	if (ret) {
8447f7bcaeSTom Rini 		printf("spl: ymodem err - %s\n", xyzModem_error(err));
8536afd451SNikita Kiryanov 		return ret;
8647f7bcaeSTom Rini 	}
8747f7bcaeSTom Rini 
88fa715193SLokesh Vutla 	res = xyzModem_stream_read(buf, BUF_SIZE, &err);
89fa715193SLokesh Vutla 	if (res <= 0)
90fa715193SLokesh Vutla 		goto end_stream;
91fa715193SLokesh Vutla 
92fa715193SLokesh Vutla 	if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) &&
93fa715193SLokesh Vutla 	    image_get_magic((struct image_header *)buf) == FDT_MAGIC) {
94fa715193SLokesh Vutla 		struct spl_load_info load;
95fa715193SLokesh Vutla 		struct ymodem_fit_info info;
96fa715193SLokesh Vutla 
97fa715193SLokesh Vutla 		debug("Found FIT\n");
98fa715193SLokesh Vutla 		load.dev = NULL;
99fa715193SLokesh Vutla 		load.priv = (void *)&info;
100fa715193SLokesh Vutla 		load.filename = NULL;
101fa715193SLokesh Vutla 		load.bl_len = 1;
102fa715193SLokesh Vutla 		info.buf = buf;
103fa715193SLokesh Vutla 		info.image_read = BUF_SIZE;
104fa715193SLokesh Vutla 		load.read = ymodem_read_fit;
105fa715193SLokesh Vutla 		ret =  spl_load_simple_fit(&load, 0, (void *)buf);
106fa715193SLokesh Vutla 		size = info.image_read;
107fa715193SLokesh Vutla 
108fa715193SLokesh Vutla 		while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
109fa715193SLokesh Vutla 			size += res;
110fa715193SLokesh Vutla 	} else {
11171316c1dSSimon Glass 		spl_parse_image_header(&spl_image, (struct image_header *)buf);
11271316c1dSSimon Glass 		ret = spl_parse_image_header(&spl_image,
11371316c1dSSimon Glass 					     (struct image_header *)buf);
114fa715193SLokesh Vutla 		if (ret)
115fa715193SLokesh Vutla 			return ret;
116fa715193SLokesh Vutla 		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 }
135*dd6bf902SSimon Glass SPL_LOAD_IMAGE_METHOD(0, BOOT_DEVICE_UART, spl_ymodem_load_image);
136