1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 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> 10 */ 11 #include <common.h> 12 #include <spl.h> 13 #include <xyzModem.h> 14 #include <asm/u-boot.h> 15 #include <linux/libfdt.h> 16 17 #define BUF_SIZE 1024 18 19 /* 20 * Information required to load image using ymodem. 21 * 22 * @image_read: Now of bytes read from the image. 23 * @buf: pointer to the previous read block. 24 */ 25 struct ymodem_fit_info { 26 int image_read; 27 char *buf; 28 }; 29 30 static int getcymodem(void) { 31 if (tstc()) 32 return (getc()); 33 return -1; 34 } 35 36 static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, 37 ulong size, void *addr) 38 { 39 int res, err; 40 struct ymodem_fit_info *info = load->priv; 41 char *buf = info->buf; 42 43 while (info->image_read < offset) { 44 res = xyzModem_stream_read(buf, BUF_SIZE, &err); 45 if (res <= 0) 46 return res; 47 info->image_read += res; 48 } 49 50 if (info->image_read > offset) { 51 res = info->image_read - offset; 52 memcpy(addr, &buf[BUF_SIZE - res], res); 53 addr = addr + res; 54 } 55 56 while (info->image_read < offset + size) { 57 res = xyzModem_stream_read(buf, BUF_SIZE, &err); 58 if (res <= 0) 59 return res; 60 61 memcpy(addr, buf, res); 62 info->image_read += res; 63 addr += res; 64 } 65 66 return size; 67 } 68 69 static int spl_ymodem_load_image(struct spl_image_info *spl_image, 70 struct spl_boot_device *bootdev) 71 { 72 int size = 0; 73 int err; 74 int res; 75 int ret; 76 connection_info_t info; 77 char buf[BUF_SIZE]; 78 ulong addr = 0; 79 80 info.mode = xyzModem_ymodem; 81 ret = xyzModem_stream_open(&info, &err); 82 if (ret) { 83 printf("spl: ymodem err - %s\n", xyzModem_error(err)); 84 return ret; 85 } 86 87 res = xyzModem_stream_read(buf, BUF_SIZE, &err); 88 if (res <= 0) 89 goto end_stream; 90 91 if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && 92 image_get_magic((struct image_header *)buf) == FDT_MAGIC) { 93 struct spl_load_info load; 94 struct ymodem_fit_info info; 95 96 debug("Found FIT\n"); 97 load.dev = NULL; 98 load.priv = (void *)&info; 99 load.filename = NULL; 100 load.bl_len = 1; 101 info.buf = buf; 102 info.image_read = BUF_SIZE; 103 load.read = ymodem_read_fit; 104 ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf); 105 size = info.image_read; 106 107 while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) 108 size += res; 109 } else { 110 ret = spl_parse_image_header(spl_image, 111 (struct image_header *)buf); 112 if (ret) 113 return ret; 114 addr = spl_image->load_addr; 115 memcpy((void *)addr, buf, res); 116 size += res; 117 addr += res; 118 119 while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) { 120 memcpy((void *)addr, buf, res); 121 size += res; 122 addr += res; 123 } 124 } 125 126 end_stream: 127 xyzModem_stream_close(&err); 128 xyzModem_stream_terminate(false, &getcymodem); 129 130 printf("Loaded %d bytes\n", size); 131 return 0; 132 } 133 SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image); 134