]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
24de357a MP |
2 | /* |
3 | * (C) Copyright 2000-2004 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
5 | * | |
6 | * (C) Copyright 2011 | |
7 | * Texas Instruments, <www.ti.com> | |
8 | * | |
9 | * Matt Porter <[email protected]> | |
24de357a MP |
10 | */ |
11 | #include <common.h> | |
0c670fc1 | 12 | #include <gzip.h> |
4d72caa5 | 13 | #include <image.h> |
f7ae49fc | 14 | #include <log.h> |
47f7bcae | 15 | #include <spl.h> |
24de357a MP |
16 | #include <xyzModem.h> |
17 | #include <asm/u-boot.h> | |
b08c8c48 | 18 | #include <linux/libfdt.h> |
24de357a MP |
19 | |
20 | #define BUF_SIZE 1024 | |
21 | ||
fa715193 LV |
22 | /* |
23 | * Information required to load image using ymodem. | |
24 | * | |
25 | * @image_read: Now of bytes read from the image. | |
26 | * @buf: pointer to the previous read block. | |
27 | */ | |
28 | struct ymodem_fit_info { | |
29 | int image_read; | |
30 | char *buf; | |
31 | }; | |
32 | ||
24de357a MP |
33 | static int getcymodem(void) { |
34 | if (tstc()) | |
c670aeee | 35 | return (getchar()); |
24de357a MP |
36 | return -1; |
37 | } | |
38 | ||
fa715193 LV |
39 | static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, |
40 | ulong size, void *addr) | |
41 | { | |
095764e3 | 42 | int res, err, buf_offset; |
fa715193 LV |
43 | struct ymodem_fit_info *info = load->priv; |
44 | char *buf = info->buf; | |
c1335e2c | 45 | ulong copy_size = size; |
fa715193 LV |
46 | |
47 | while (info->image_read < offset) { | |
48 | res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
49 | if (res <= 0) | |
9d6ee3e2 AD |
50 | break; |
51 | ||
fa715193 LV |
52 | info->image_read += res; |
53 | } | |
54 | ||
55 | if (info->image_read > offset) { | |
56 | res = info->image_read - offset; | |
095764e3 LV |
57 | if (info->image_read % BUF_SIZE) |
58 | buf_offset = (info->image_read % BUF_SIZE); | |
59 | else | |
60 | buf_offset = BUF_SIZE; | |
c1335e2c VR |
61 | |
62 | if (res > copy_size) { | |
63 | memcpy(addr, &buf[buf_offset - res], copy_size); | |
64 | goto done; | |
65 | } | |
095764e3 | 66 | memcpy(addr, &buf[buf_offset - res], res); |
fa715193 | 67 | addr = addr + res; |
c1335e2c | 68 | copy_size -= res; |
fa715193 LV |
69 | } |
70 | ||
71 | while (info->image_read < offset + size) { | |
72 | res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
73 | if (res <= 0) | |
9d6ee3e2 | 74 | break; |
fa715193 | 75 | |
fa715193 | 76 | info->image_read += res; |
c1335e2c VR |
77 | if (res > copy_size) { |
78 | memcpy(addr, buf, copy_size); | |
79 | goto done; | |
80 | } | |
81 | memcpy(addr, buf, res); | |
fa715193 | 82 | addr += res; |
c1335e2c | 83 | copy_size -= res; |
fa715193 LV |
84 | } |
85 | ||
c1335e2c | 86 | done: |
fa715193 LV |
87 | return size; |
88 | } | |
89 | ||
e413033d AD |
90 | int spl_ymodem_load_image(struct spl_image_info *spl_image, |
91 | struct spl_boot_device *bootdev) | |
24de357a | 92 | { |
92e5cb80 | 93 | ulong size = 0; |
24de357a MP |
94 | int err; |
95 | int res; | |
96 | int ret; | |
97 | connection_info_t info; | |
98 | char buf[BUF_SIZE]; | |
f3543e69 | 99 | struct legacy_img_hdr *ih = NULL; |
24de357a MP |
100 | ulong addr = 0; |
101 | ||
102 | info.mode = xyzModem_ymodem; | |
103 | ret = xyzModem_stream_open(&info, &err); | |
fa715193 LV |
104 | if (ret) { |
105 | printf("spl: ymodem err - %s\n", xyzModem_error(err)); | |
106 | return ret; | |
107 | } | |
108 | ||
109 | res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
110 | if (res <= 0) | |
111 | goto end_stream; | |
112 | ||
792dd570 | 113 | if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) && |
f3543e69 | 114 | image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) { |
792dd570 | 115 | addr = CONFIG_SYS_LOAD_ADDR; |
f3543e69 | 116 | ih = (struct legacy_img_hdr *)addr; |
792dd570 MV |
117 | |
118 | memcpy((void *)addr, buf, res); | |
119 | size += res; | |
120 | addr += res; | |
121 | ||
122 | while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) { | |
123 | memcpy((void *)addr, buf, res); | |
124 | size += res; | |
125 | addr += res; | |
126 | } | |
127 | ||
2e0429bc | 128 | ret = spl_parse_image_header(spl_image, bootdev, ih); |
792dd570 MV |
129 | if (ret) |
130 | return ret; | |
131 | } else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && | |
f3543e69 | 132 | image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) { |
fa715193 LV |
133 | struct spl_load_info load; |
134 | struct ymodem_fit_info info; | |
135 | ||
136 | debug("Found FIT\n"); | |
137 | load.dev = NULL; | |
138 | load.priv = (void *)&info; | |
139 | load.filename = NULL; | |
140 | load.bl_len = 1; | |
141 | info.buf = buf; | |
142 | info.image_read = BUF_SIZE; | |
143 | load.read = ymodem_read_fit; | |
f4d7d859 | 144 | ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf); |
fa715193 | 145 | size = info.image_read; |
24de357a | 146 | |
fa715193 LV |
147 | while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) |
148 | size += res; | |
149 | } else { | |
f3543e69 | 150 | ih = (struct legacy_img_hdr *)buf; |
2e0429bc | 151 | ret = spl_parse_image_header(spl_image, bootdev, ih); |
fa715193 | 152 | if (ret) |
6d8dbe48 | 153 | goto end_stream; |
92e5cb80 MV |
154 | #ifdef CONFIG_SPL_GZIP |
155 | if (ih->ih_comp == IH_COMP_GZIP) | |
156 | addr = CONFIG_SYS_LOAD_ADDR; | |
157 | else | |
158 | #endif | |
159 | addr = spl_image->load_addr; | |
fa715193 | 160 | memcpy((void *)addr, buf, res); |
f3543e69 | 161 | ih = (struct legacy_img_hdr *)addr; |
fa715193 LV |
162 | size += res; |
163 | addr += res; | |
164 | ||
165 | while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) { | |
166 | memcpy((void *)addr, buf, res); | |
24de357a MP |
167 | size += res; |
168 | addr += res; | |
24de357a | 169 | } |
24de357a MP |
170 | } |
171 | ||
fa715193 | 172 | end_stream: |
24de357a MP |
173 | xyzModem_stream_close(&err); |
174 | xyzModem_stream_terminate(false, &getcymodem); | |
175 | ||
92e5cb80 | 176 | printf("Loaded %lu bytes\n", size); |
6d8dbe48 | 177 | |
d574c19b MV |
178 | #ifdef CONFIG_SPL_GZIP |
179 | if (!(IS_ENABLED(CONFIG_SPL_LOAD_FIT) && | |
f3543e69 | 180 | image_get_magic((struct legacy_img_hdr *)buf) == FDT_MAGIC) && |
d574c19b MV |
181 | (ih->ih_comp == IH_COMP_GZIP)) { |
182 | if (gunzip((void *)(spl_image->load_addr + sizeof(*ih)), | |
183 | CONFIG_SYS_BOOTM_LEN, | |
184 | (void *)(CONFIG_SYS_LOAD_ADDR + sizeof(*ih)), | |
185 | &size)) { | |
186 | puts("Uncompressing error\n"); | |
187 | return -EIO; | |
188 | } | |
189 | } | |
190 | #endif | |
191 | ||
6d8dbe48 | 192 | return ret; |
24de357a | 193 | } |
ebc4ef61 | 194 | SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image); |