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 <asm/utils.h> 16 #include <linux/libfdt.h> 17 18 #define BUF_SIZE 1024 19 20 /* 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 */ 26 struct ymodem_fit_info { 27 int image_read; 28 char *buf; 29 }; 30 31 static int getcymodem(void) { 32 if (tstc()) 33 return (getc()); 34 return -1; 35 } 36 37 static 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 70 static int spl_ymodem_load_image(struct spl_image_info *spl_image, 71 struct spl_boot_device *bootdev) 72 { 73 int size = 0; 74 int err; 75 int res; 76 int ret; 77 connection_info_t info; 78 char buf[BUF_SIZE]; 79 ulong addr = 0; 80 81 info.mode = xyzModem_ymodem; 82 ret = xyzModem_stream_open(&info, &err); 83 if (ret) { 84 printf("spl: ymodem err - %s\n", xyzModem_error(err)); 85 return ret; 86 } 87 88 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; 105 ret = spl_load_simple_fit(spl_image, &load, 0, (void *)buf); 106 size = info.image_read; 107 108 while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) 109 size += res; 110 } else { 111 ret = spl_parse_image_header(spl_image, 112 (struct image_header *)buf); 113 if (ret) 114 return ret; 115 addr = spl_image->load_addr; 116 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 127 end_stream: 128 xyzModem_stream_close(&err); 129 xyzModem_stream_terminate(false, &getcymodem); 130 131 printf("Loaded %d bytes\n", size); 132 return 0; 133 } 134 SPL_LOAD_IMAGE_METHOD("UART", 0, BOOT_DEVICE_UART, spl_ymodem_load_image); 135