rockchip: Enable PCIe/M.2 and NVMe on Firefly RK3399
[oweals/u-boot.git] / tools / kwboot.c
index e773f01df3f626b337c8c44390303b677feb46d0..4be094c9c8d81ebca06170a386718527880a587e 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Boot a Marvell Kirkwood SoC, with Xmodem over UART0.
+ * Boot a Marvell SoC, with Xmodem over UART0.
+ *  supports Kirkwood, Dove, Armada 370, Armada XP
  *
  * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
  *
@@ -8,10 +9,14 @@
  *   2008. Chapter 24.2 "BootROM Firmware".
  */
 
+#include "kwbimage.h"
+#include "mkimage.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include <image.h>
 #include <libgen.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -21,8 +26,6 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 
-#include "kwbimage.h"
-
 #ifdef __GNUC__
 #define PACKED __attribute((packed))
 #else
@@ -37,9 +40,18 @@ static unsigned char kwboot_msg_boot[] = {
        0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
 };
 
+static unsigned char kwboot_msg_debug[] = {
+       0xDD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
+};
+
+/* Defines known to work on Kirkwood */
 #define KWBOOT_MSG_REQ_DELAY   10 /* ms */
 #define KWBOOT_MSG_RSP_TIMEO   50 /* ms */
 
+/* Defines known to work on Armada XP */
+#define KWBOOT_MSG_REQ_DELAY_AXP       1000 /* ms */
+#define KWBOOT_MSG_RSP_TIMEO_AXP       1000 /* ms */
+
 /*
  * Xmodem Transfers
  */
@@ -62,6 +74,10 @@ struct kwboot_block {
 
 static int kwboot_verbose;
 
+static int msg_req_delay = KWBOOT_MSG_REQ_DELAY;
+static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO;
+static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO;
+
 static void
 kwboot_printv(const char *fmt, ...)
 {
@@ -166,7 +182,7 @@ kwboot_tty_recv(int fd, void *buf, size_t len, int timeo)
                }
 
                n = read(fd, buf, len);
-               if (n < 0)
+               if (n <= 0)
                        goto out;
 
                buf = (char *)buf + n;
@@ -184,6 +200,9 @@ kwboot_tty_send(int fd, const void *buf, size_t len)
        int rc;
        ssize_t n;
 
+       if (!buf)
+               return 0;
+
        rc = -1;
 
        do {
@@ -267,25 +286,62 @@ kwboot_bootmsg(int tty, void *msg)
 {
        int rc;
        char c;
+       int count;
+
+       if (msg == NULL)
+               kwboot_printv("Please reboot the target into UART boot mode...");
+       else
+               kwboot_printv("Sending boot message. Please reboot the target...");
+
+       do {
+               rc = tcflush(tty, TCIOFLUSH);
+               if (rc)
+                       break;
+
+               for (count = 0; count < 128; count++) {
+                       rc = kwboot_tty_send(tty, msg, 8);
+                       if (rc) {
+                               usleep(msg_req_delay * 1000);
+                               continue;
+                       }
+               }
+
+               rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
 
-       kwboot_printv("Sending boot message. Please reboot the target...");
+               kwboot_spinner();
+
+       } while (rc || c != NAK);
+
+       kwboot_printv("\n");
+
+       return rc;
+}
+
+static int
+kwboot_debugmsg(int tty, void *msg)
+{
+       int rc;
+
+       kwboot_printv("Sending debug message. Please reboot the target...");
 
        do {
+               char buf[16];
+
                rc = tcflush(tty, TCIOFLUSH);
                if (rc)
                        break;
 
                rc = kwboot_tty_send(tty, msg, 8);
                if (rc) {
-                       usleep(KWBOOT_MSG_REQ_DELAY * 1000);
+                       usleep(msg_req_delay * 1000);
                        continue;
                }
 
-               rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO);
+               rc = kwboot_tty_recv(tty, buf, 16, msg_rsp_timeo);
 
                kwboot_spinner();
 
-       } while (rc || c != NAK);
+       } while (rc);
 
        kwboot_printv("\n");
 
@@ -300,6 +356,7 @@ kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
        size_t n;
        int i;
 
+       block->soh = SOH;
        block->pnum = pnum;
        block->_pnum = ~block->pnum;
 
@@ -326,9 +383,15 @@ kwboot_xm_sendblock(int fd, struct kwboot_block *block)
                if (rc)
                        break;
 
-               rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO);
-               if (rc)
-                       break;
+               do {
+                       rc = kwboot_tty_recv(fd, &c, 1, blk_rsp_timeo);
+                       if (rc)
+                               break;
+
+                       if (c != ACK && c != NAK && c != CAN)
+                               printf("%c", c);
+
+               } while (c != ACK && c != NAK && c != CAN);
 
                if (c != ACK)
                        kwboot_progress(-1, '+');
@@ -366,6 +429,9 @@ kwboot_xmodem(int tty, const void *_data, size_t size)
 
        kwboot_printv("Sending boot image...\n");
 
+       sleep(2); /* flush isn't effective without it */
+       tcflush(tty, TCIOFLUSH);
+
        do {
                struct kwboot_block block;
                int n;
@@ -406,7 +472,7 @@ kwboot_term_pipe(int in, int out, char *quit, int *s)
        char _buf[128], *buf = _buf;
 
        nin = read(in, buf, sizeof(buf));
-       if (nin < 0)
+       if (nin <= 0)
                return -1;
 
        if (quit) {
@@ -511,7 +577,6 @@ kwboot_mmap_image(const char *path, size_t *size, int prot)
        void *img;
 
        rc = -1;
-       fd = -1;
        img = NULL;
 
        fd = open(path, O_RDONLY);
@@ -558,9 +623,10 @@ static int
 kwboot_img_patch_hdr(void *img, size_t size)
 {
        int rc;
-       bhr_t *hdr;
+       struct main_hdr_v1 *hdr;
        uint8_t csum;
-       const size_t hdrsz = sizeof(*hdr);
+       size_t hdrsz = sizeof(*hdr);
+       int image_ver;
 
        rc = -1;
        hdr = img;
@@ -570,8 +636,20 @@ kwboot_img_patch_hdr(void *img, size_t size)
                goto out;
        }
 
-       csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checkSum;
-       if (csum != hdr->checkSum) {
+       image_ver = image_version(img);
+       if (image_ver < 0) {
+               fprintf(stderr, "Invalid image header version\n");
+               errno = EINVAL;
+               goto out;
+       }
+
+       if (image_ver == 0)
+               hdrsz = sizeof(*hdr);
+       else
+               hdrsz = KWBHEADER_V1_SIZE(hdr);
+
+       csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checksum;
+       if (csum != hdr->checksum) {
                errno = EINVAL;
                goto out;
        }
@@ -583,14 +661,18 @@ kwboot_img_patch_hdr(void *img, size_t size)
 
        hdr->blockid = IBR_HDR_UART_ID;
 
-       hdr->nandeccmode = IBR_HDR_ECC_DISABLED;
-       hdr->nandpagesize = 0;
+       if (image_ver == 0) {
+               struct main_hdr_v0 *hdr_v0 = img;
+
+               hdr_v0->nandeccmode = IBR_HDR_ECC_DISABLED;
+               hdr_v0->nandpagesize = 0;
 
-       hdr->srcaddr = hdr->ext
-               ? sizeof(struct kwb_header)
-               : sizeof(*hdr);
+               hdr_v0->srcaddr = hdr_v0->ext
+                       ? sizeof(struct kwb_header)
+                       : sizeof(*hdr_v0);
+       }
 
-       hdr->checkSum = kwboot_img_csum8(hdr, hdrsz) - csum;
+       hdr->checksum = kwboot_img_csum8(hdr, hdrsz) - csum;
 
        rc = 0;
 out:
@@ -601,11 +683,20 @@ static void
 kwboot_usage(FILE *stream, char *progname)
 {
        fprintf(stream,
-               "Usage: %s -b <image> [ -p ] [ -t ] "
-               "[-B <baud> ] <TTY>\n", progname);
+               "Usage: %s [OPTIONS] [-b <image> | -D <image> ] [-B <baud> ] <TTY>\n",
+               progname);
        fprintf(stream, "\n");
-       fprintf(stream, "  -b <image>: boot <image>\n");
+       fprintf(stream,
+               "  -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
        fprintf(stream, "  -p: patch <image> to type 0x69 (uart boot)\n");
+       fprintf(stream,
+               "  -D <image>: boot <image> without preamble (Dove)\n");
+       fprintf(stream, "  -d: enter debug mode\n");
+       fprintf(stream, "  -a: use timings for Armada XP\n");
+       fprintf(stream, "  -q <req-delay>:  use specific request-delay\n");
+       fprintf(stream, "  -s <resp-timeo>: use specific response-timeout\n");
+       fprintf(stream,
+               "  -o <block-timeo>: use specific xmodem block timeout\n");
        fprintf(stream, "\n");
        fprintf(stream, "  -t: mini terminal\n");
        fprintf(stream, "\n");
@@ -619,6 +710,7 @@ main(int argc, char **argv)
        const char *ttypath, *imgpath;
        int rv, rc, tty, term, prot, patch;
        void *bootmsg;
+       void *debugmsg;
        void *img;
        size_t size;
        speed_t speed;
@@ -626,6 +718,7 @@ main(int argc, char **argv)
        rv = 1;
        tty = -1;
        bootmsg = NULL;
+       debugmsg = NULL;
        imgpath = NULL;
        img = NULL;
        term = 0;
@@ -636,7 +729,7 @@ main(int argc, char **argv)
        kwboot_verbose = isatty(STDOUT_FILENO);
 
        do {
-               int c = getopt(argc, argv, "hb:ptB:");
+               int c = getopt(argc, argv, "hb:ptaB:dD:q:s:o:");
                if (c < 0)
                        break;
 
@@ -646,6 +739,15 @@ main(int argc, char **argv)
                        imgpath = optarg;
                        break;
 
+               case 'D':
+                       bootmsg = NULL;
+                       imgpath = optarg;
+                       break;
+
+               case 'd':
+                       debugmsg = kwboot_msg_debug;
+                       break;
+
                case 'p':
                        patch = 1;
                        break;
@@ -654,6 +756,23 @@ main(int argc, char **argv)
                        term = 1;
                        break;
 
+               case 'a':
+                       msg_req_delay = KWBOOT_MSG_REQ_DELAY_AXP;
+                       msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO_AXP;
+                       break;
+
+               case 'q':
+                       msg_req_delay = atoi(optarg);
+                       break;
+
+               case 's':
+                       msg_rsp_timeo = atoi(optarg);
+                       break;
+
+               case 'o':
+                       blk_rsp_timeo = atoi(optarg);
+                       break;
+
                case 'B':
                        speed = kwboot_tty_speed(atoi(optarg));
                        if (speed == -1)
@@ -667,7 +786,7 @@ main(int argc, char **argv)
                }
        } while (1);
 
-       if (!bootmsg && !term)
+       if (!bootmsg && !term && !debugmsg)
                goto usage;
 
        if (patch && !imgpath)
@@ -702,7 +821,13 @@ main(int argc, char **argv)
                }
        }
 
-       if (bootmsg) {
+       if (debugmsg) {
+               rc = kwboot_debugmsg(tty, debugmsg);
+               if (rc) {
+                       perror("debugmsg");
+                       goto out;
+               }
+       } else if (bootmsg) {
                rc = kwboot_bootmsg(tty, bootmsg);
                if (rc) {
                        perror("bootmsg");