| /* | |
| * (C) Copyright 2000-2004 | |
| * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
| * | |
| * (C) Copyright 2011 | |
| * Texas Instruments, <www.ti.com> | |
| * | |
| * Matt Porter <mporter@ti.com> | |
| * | |
| * SPDX-License-Identifier: GPL-2.0+ | |
| */ | |
| #include <common.h> | |
| #include <spl.h> | |
| #include <xyzModem.h> | |
| #include <asm/u-boot.h> | |
| #include <asm/utils.h> | |
| #include <libfdt.h> | |
| #define BUF_SIZE 1024 | |
| /* | |
| * Information required to load image using ymodem. | |
| * | |
| * @image_read: Now of bytes read from the image. | |
| * @buf: pointer to the previous read block. | |
| */ | |
| struct ymodem_fit_info { | |
| int image_read; | |
| char *buf; | |
| }; | |
| static int getcymodem(void) { | |
| if (tstc()) | |
| return (getc()); | |
| return -1; | |
| } | |
| static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, | |
| ulong size, void *addr) | |
| { | |
| int res, err; | |
| struct ymodem_fit_info *info = load->priv; | |
| char *buf = info->buf; | |
| while (info->image_read < offset) { | |
| res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
| if (res <= 0) | |
| return res; | |
| info->image_read += res; | |
| } | |
| if (info->image_read > offset) { | |
| res = info->image_read - offset; | |
| memcpy(addr, &buf[BUF_SIZE - res], res); | |
| addr = addr + res; | |
| } | |
| while (info->image_read < offset + size) { | |
| res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
| if (res <= 0) | |
| return res; | |
| memcpy(addr, buf, res); | |
| info->image_read += res; | |
| addr += res; | |
| } | |
| return size; | |
| } | |
| static int spl_ymodem_load_image(struct spl_image_info *spl_image, | |
| struct spl_boot_device *bootdev) | |
| { | |
| int size = 0; | |
| int err; | |
| int res; | |
| int ret; | |
| connection_info_t info; | |
| char buf[BUF_SIZE]; | |
| ulong addr = 0; | |
| info.mode = xyzModem_ymodem; | |
| ret = xyzModem_stream_open(&info, &err); | |
| if (ret) { | |
| printf("spl: ymodem err - %s\n", xyzModem_error(err)); | |
| return ret; | |
| } | |
| res = xyzModem_stream_read(buf, BUF_SIZE, &err); | |
| if (res <= 0) | |
| goto end_stream; | |
| if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && | |
| image_get_magic((struct image_header *)buf) == FDT_MAGIC) { | |
| struct spl_load_info load; | |
| struct ymodem_fit_info info; | |
| debug("Found FIT\n"); | |
| load.dev = NULL; | |
| load.priv = (void *)&info; | |
| load.filename = NULL; | |
| load.bl_len = 1; | |
| info.buf = buf; | |
| info.image_read = BUF_SIZE; | |
| load.read = ymodem_read_fit; | |
| ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf); | |
| size = info.image_read; | |
| while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) | |
| size += res; | |
| } else { | |
| ret = spl_parse_image_header(spl_image, | |
| (struct image_header *)buf); | |
| if (ret) | |
| return ret; | |
| addr = spl_image->load_addr; | |
| memcpy((void *)addr, buf, res); | |
| size += res; | |
| addr += res; | |
| while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) { | |
| memcpy((void *)addr, buf, res); | |
| size += res; | |
| addr += res; | |
| } | |
| } | |
| end_stream: | |
| xyzModem_stream_close(&err); | |
| xyzModem_stream_terminate(false, &getcymodem); | |
| printf("Loaded %d bytes\n", size); | |
| return 0; | |
| } | |
| SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image); |