blob: 35f8f80013a8b02821c22bd95eb1cd32c0d45aae [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Matt Porter24de3572012-01-31 12:03:57 +00002/*
3 * (C) Copyright 2000-2004
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 *
6 * (C) Copyright 2011
7 * Texas Instruments, <www.ti.com>
8 *
9 * Matt Porter <mporter@ti.com>
Matt Porter24de3572012-01-31 12:03:57 +000010 */
11#include <common.h>
Tom Rini47f7bca2012-08-13 12:03:19 -070012#include <spl.h>
Matt Porter24de3572012-01-31 12:03:57 +000013#include <xyzModem.h>
14#include <asm/u-boot.h>
15#include <asm/utils.h>
Masahiro Yamadab08c8c42018-03-05 01:20:11 +090016#include <linux/libfdt.h>
Matt Porter24de3572012-01-31 12:03:57 +000017
18#define BUF_SIZE 1024
19
Lokesh Vutlafa715192016-05-24 10:34:44 +053020/*
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 */
26struct ymodem_fit_info {
27 int image_read;
28 char *buf;
29};
30
Matt Porter24de3572012-01-31 12:03:57 +000031static int getcymodem(void) {
32 if (tstc())
33 return (getc());
34 return -1;
35}
36
Lokesh Vutlafa715192016-05-24 10:34:44 +053037static 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
Simon Glass2a2ee2a2016-09-24 18:20:13 -060070static int spl_ymodem_load_image(struct spl_image_info *spl_image,
71 struct spl_boot_device *bootdev)
Matt Porter24de3572012-01-31 12:03:57 +000072{
73 int size = 0;
74 int err;
75 int res;
76 int ret;
77 connection_info_t info;
78 char buf[BUF_SIZE];
Matt Porter24de3572012-01-31 12:03:57 +000079 ulong addr = 0;
80
81 info.mode = xyzModem_ymodem;
82 ret = xyzModem_stream_open(&info, &err);
Lokesh Vutlafa715192016-05-24 10:34:44 +053083 if (ret) {
Matt Porter24de3572012-01-31 12:03:57 +000084 printf("spl: ymodem err - %s\n", xyzModem_error(err));
Nikita Kiryanov36afd452015-11-08 17:11:49 +020085 return ret;
Matt Porter24de3572012-01-31 12:03:57 +000086 }
87
Lokesh Vutlafa715192016-05-24 10:34:44 +053088 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;
Simon Glassf4d7d852016-09-24 18:20:16 -0600105 ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf);
Lokesh Vutlafa715192016-05-24 10:34:44 +0530106 size = info.image_read;
107
108 while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0)
109 size += res;
110 } else {
Simon Glass2a2ee2a2016-09-24 18:20:13 -0600111 ret = spl_parse_image_header(spl_image,
Simon Glass71316c12016-09-24 18:19:53 -0600112 (struct image_header *)buf);
Lokesh Vutlafa715192016-05-24 10:34:44 +0530113 if (ret)
114 return ret;
Simon Glass2a2ee2a2016-09-24 18:20:13 -0600115 addr = spl_image->load_addr;
Lokesh Vutlafa715192016-05-24 10:34:44 +0530116 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
127end_stream:
Matt Porter24de3572012-01-31 12:03:57 +0000128 xyzModem_stream_close(&err);
129 xyzModem_stream_terminate(false, &getcymodem);
130
131 printf("Loaded %d bytes\n", size);
Nikita Kiryanov36afd452015-11-08 17:11:49 +0200132 return 0;
Matt Porter24de3572012-01-31 12:03:57 +0000133}
Simon Glassebc4ef62016-11-30 15:30:50 -0700134SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image);