147f7bcaeSTom Rini /* 247f7bcaeSTom Rini * (C) Copyright 2000-2004 347f7bcaeSTom Rini * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 447f7bcaeSTom Rini * 547f7bcaeSTom Rini * (C) Copyright 2011 647f7bcaeSTom Rini * Texas Instruments, <www.ti.com> 747f7bcaeSTom Rini * 847f7bcaeSTom Rini * Matt Porter <mporter@ti.com> 947f7bcaeSTom Rini * 101a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 1147f7bcaeSTom Rini */ 1247f7bcaeSTom Rini #include <common.h> 1347f7bcaeSTom Rini #include <spl.h> 1447f7bcaeSTom Rini #include <xyzModem.h> 1547f7bcaeSTom Rini #include <asm/u-boot.h> 1647f7bcaeSTom Rini #include <asm/utils.h> 17*fa715193SLokesh Vutla #include <libfdt.h> 1847f7bcaeSTom Rini 1947f7bcaeSTom Rini #define BUF_SIZE 1024 2047f7bcaeSTom Rini 21*fa715193SLokesh Vutla /* 22*fa715193SLokesh Vutla * Information required to load image using ymodem. 23*fa715193SLokesh Vutla * 24*fa715193SLokesh Vutla * @image_read: Now of bytes read from the image. 25*fa715193SLokesh Vutla * @buf: pointer to the previous read block. 26*fa715193SLokesh Vutla */ 27*fa715193SLokesh Vutla struct ymodem_fit_info { 28*fa715193SLokesh Vutla int image_read; 29*fa715193SLokesh Vutla char *buf; 30*fa715193SLokesh Vutla }; 31*fa715193SLokesh Vutla 3247f7bcaeSTom Rini static int getcymodem(void) { 3347f7bcaeSTom Rini if (tstc()) 3447f7bcaeSTom Rini return (getc()); 3547f7bcaeSTom Rini return -1; 3647f7bcaeSTom Rini } 3747f7bcaeSTom Rini 38*fa715193SLokesh Vutla static ulong ymodem_read_fit(struct spl_load_info *load, ulong offset, 39*fa715193SLokesh Vutla ulong size, void *addr) 40*fa715193SLokesh Vutla { 41*fa715193SLokesh Vutla int res, err; 42*fa715193SLokesh Vutla struct ymodem_fit_info *info = load->priv; 43*fa715193SLokesh Vutla char *buf = info->buf; 44*fa715193SLokesh Vutla 45*fa715193SLokesh Vutla while (info->image_read < offset) { 46*fa715193SLokesh Vutla res = xyzModem_stream_read(buf, BUF_SIZE, &err); 47*fa715193SLokesh Vutla if (res <= 0) 48*fa715193SLokesh Vutla return res; 49*fa715193SLokesh Vutla info->image_read += res; 50*fa715193SLokesh Vutla } 51*fa715193SLokesh Vutla 52*fa715193SLokesh Vutla if (info->image_read > offset) { 53*fa715193SLokesh Vutla res = info->image_read - offset; 54*fa715193SLokesh Vutla memcpy(addr, &buf[BUF_SIZE - res], res); 55*fa715193SLokesh Vutla addr = addr + res; 56*fa715193SLokesh Vutla } 57*fa715193SLokesh Vutla 58*fa715193SLokesh Vutla while (info->image_read < offset + size) { 59*fa715193SLokesh Vutla res = xyzModem_stream_read(buf, BUF_SIZE, &err); 60*fa715193SLokesh Vutla if (res <= 0) 61*fa715193SLokesh Vutla return res; 62*fa715193SLokesh Vutla 63*fa715193SLokesh Vutla memcpy(addr, buf, res); 64*fa715193SLokesh Vutla info->image_read += res; 65*fa715193SLokesh Vutla addr += res; 66*fa715193SLokesh Vutla } 67*fa715193SLokesh Vutla 68*fa715193SLokesh Vutla return size; 69*fa715193SLokesh Vutla } 70*fa715193SLokesh Vutla 7136afd451SNikita Kiryanov int spl_ymodem_load_image(void) 7247f7bcaeSTom Rini { 7347f7bcaeSTom Rini int size = 0; 7447f7bcaeSTom Rini int err; 7547f7bcaeSTom Rini int res; 7647f7bcaeSTom Rini int ret; 7747f7bcaeSTom Rini connection_info_t info; 7847f7bcaeSTom Rini char buf[BUF_SIZE]; 7947f7bcaeSTom Rini ulong addr = 0; 8047f7bcaeSTom Rini 8147f7bcaeSTom Rini info.mode = xyzModem_ymodem; 8247f7bcaeSTom Rini ret = xyzModem_stream_open(&info, &err); 83*fa715193SLokesh Vutla if (ret) { 8447f7bcaeSTom Rini printf("spl: ymodem err - %s\n", xyzModem_error(err)); 8536afd451SNikita Kiryanov return ret; 8647f7bcaeSTom Rini } 8747f7bcaeSTom Rini 88*fa715193SLokesh Vutla res = xyzModem_stream_read(buf, BUF_SIZE, &err); 89*fa715193SLokesh Vutla if (res <= 0) 90*fa715193SLokesh Vutla goto end_stream; 91*fa715193SLokesh Vutla 92*fa715193SLokesh Vutla if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && 93*fa715193SLokesh Vutla image_get_magic((struct image_header *)buf) == FDT_MAGIC) { 94*fa715193SLokesh Vutla struct spl_load_info load; 95*fa715193SLokesh Vutla struct ymodem_fit_info info; 96*fa715193SLokesh Vutla 97*fa715193SLokesh Vutla debug("Found FIT\n"); 98*fa715193SLokesh Vutla load.dev = NULL; 99*fa715193SLokesh Vutla load.priv = (void *)&info; 100*fa715193SLokesh Vutla load.filename = NULL; 101*fa715193SLokesh Vutla load.bl_len = 1; 102*fa715193SLokesh Vutla info.buf = buf; 103*fa715193SLokesh Vutla info.image_read = BUF_SIZE; 104*fa715193SLokesh Vutla load.read = ymodem_read_fit; 105*fa715193SLokesh Vutla ret = spl_load_simple_fit(&load, 0, (void *)buf); 106*fa715193SLokesh Vutla size = info.image_read; 107*fa715193SLokesh Vutla 108*fa715193SLokesh Vutla while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) 109*fa715193SLokesh Vutla size += res; 110*fa715193SLokesh Vutla } else { 111*fa715193SLokesh Vutla spl_parse_image_header((struct image_header *)buf); 112*fa715193SLokesh Vutla ret = spl_parse_image_header((struct image_header *)buf); 113*fa715193SLokesh Vutla if (ret) 114*fa715193SLokesh Vutla return ret; 115*fa715193SLokesh Vutla addr = spl_image.load_addr; 116*fa715193SLokesh Vutla memcpy((void *)addr, buf, res); 117*fa715193SLokesh Vutla size += res; 118*fa715193SLokesh Vutla addr += res; 119*fa715193SLokesh Vutla 120*fa715193SLokesh Vutla while ((res = xyzModem_stream_read(buf, BUF_SIZE, &err)) > 0) { 121*fa715193SLokesh Vutla memcpy((void *)addr, buf, res); 122*fa715193SLokesh Vutla size += res; 123*fa715193SLokesh Vutla addr += res; 124*fa715193SLokesh Vutla } 125*fa715193SLokesh Vutla } 126*fa715193SLokesh Vutla 127*fa715193SLokesh Vutla end_stream: 12847f7bcaeSTom Rini xyzModem_stream_close(&err); 12947f7bcaeSTom Rini xyzModem_stream_terminate(false, &getcymodem); 13047f7bcaeSTom Rini 13147f7bcaeSTom Rini printf("Loaded %d bytes\n", size); 13236afd451SNikita Kiryanov return 0; 13347f7bcaeSTom Rini } 134