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