]>
git.ipfire.org Git - people/ms/u-boot.git/blob - tools/kwboot.c
2 * Boot a Marvell SoC, with Xmodem over UART0.
3 * supports Kirkwood, Dove, Armada 370, Armada XP
5 * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
7 * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
8 * Integrated Controller: Functional Specifications" December 2,
9 * 2008. Chapter 24.2 "BootROM Firmware".
30 #define PACKED __attribute((packed))
36 * Marvell BootROM UART Sensing
39 static unsigned char kwboot_msg_boot
[] = {
40 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
43 static unsigned char kwboot_msg_debug
[] = {
44 0xDD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
47 /* Defines known to work on Kirkwood */
48 #define KWBOOT_MSG_REQ_DELAY 10 /* ms */
49 #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */
51 /* Defines known to work on Armada XP */
52 #define KWBOOT_MSG_REQ_DELAY_AXP 1000 /* ms */
53 #define KWBOOT_MSG_RSP_TIMEO_AXP 1000 /* ms */
59 #define SOH 1 /* sender start of block header */
60 #define EOT 4 /* sender end of block transfer */
61 #define ACK 6 /* target block ack */
62 #define NAK 21 /* target block negative ack */
63 #define CAN 24 /* target/sender transfer cancellation */
73 #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
75 static int kwboot_verbose
;
77 static int msg_req_delay
= KWBOOT_MSG_REQ_DELAY
;
78 static int msg_rsp_timeo
= KWBOOT_MSG_RSP_TIMEO
;
81 kwboot_printv(const char *fmt
, ...)
96 const char seq
[] = { '-', '\\', '|', '/' };
100 if (state
% div
== 0) {
102 fputc(seq
[state
/ div
% sizeof(seq
)], stdout
);
118 __progress(int pct
, char c
)
120 const int width
= 70;
121 static const char *nl
= "";
124 if (pos
% width
== 0)
125 printf("%s%3d %% [", nl
, pct
);
133 while (pos
++ < width
)
143 kwboot_progress(int _pct
, char c
)
155 kwboot_tty_recv(int fd
, void *buf
, size_t len
, int timeo
)
168 tv
.tv_usec
= timeo
* 1000;
169 if (tv
.tv_usec
> 1000000) {
170 tv
.tv_sec
+= tv
.tv_usec
/ 1000000;
171 tv
.tv_usec
%= 1000000;
175 nfds
= select(fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
183 n
= read(fd
, buf
, len
);
187 buf
= (char *)buf
+ n
;
197 kwboot_tty_send(int fd
, const void *buf
, size_t len
)
208 n
= write(fd
, buf
, len
);
212 buf
= (char *)buf
+ n
;
222 kwboot_tty_send_char(int fd
, unsigned char c
)
224 return kwboot_tty_send(fd
, &c
, 1);
228 kwboot_tty_speed(int baudrate
)
247 kwboot_open_tty(const char *path
, speed_t speed
)
254 fd
= open(path
, O_RDWR
|O_NOCTTY
|O_NDELAY
);
258 memset(&tio
, 0, sizeof(tio
));
261 tio
.c_cflag
= CREAD
|CLOCAL
|CS8
;
264 tio
.c_cc
[VTIME
] = 10;
266 cfsetospeed(&tio
, speed
);
267 cfsetispeed(&tio
, speed
);
269 rc
= tcsetattr(fd
, TCSANOW
, &tio
);
284 kwboot_bootmsg(int tty
, void *msg
)
290 kwboot_printv("Please reboot the target into UART boot mode...");
292 kwboot_printv("Sending boot message. Please reboot the target...");
295 rc
= tcflush(tty
, TCIOFLUSH
);
299 rc
= kwboot_tty_send(tty
, msg
, 8);
301 usleep(msg_req_delay
* 1000);
305 rc
= kwboot_tty_recv(tty
, &c
, 1, msg_rsp_timeo
);
309 } while (rc
|| c
!= NAK
);
317 kwboot_debugmsg(int tty
, void *msg
)
321 kwboot_printv("Sending debug message. Please reboot the target...");
326 rc
= tcflush(tty
, TCIOFLUSH
);
330 rc
= kwboot_tty_send(tty
, msg
, 8);
332 usleep(msg_req_delay
* 1000);
336 rc
= kwboot_tty_recv(tty
, buf
, 16, msg_rsp_timeo
);
348 kwboot_xm_makeblock(struct kwboot_block
*block
, const void *data
,
349 size_t size
, int pnum
)
351 const size_t blksz
= sizeof(block
->data
);
357 block
->_pnum
= ~block
->pnum
;
359 n
= size
< blksz
? size
: blksz
;
360 memcpy(&block
->data
[0], data
, n
);
361 memset(&block
->data
[n
], 0, blksz
- n
);
364 for (i
= 0; i
< n
; i
++)
365 block
->csum
+= block
->data
[i
];
371 kwboot_xm_sendblock(int fd
, struct kwboot_block
*block
)
378 rc
= kwboot_tty_send(fd
, block
, sizeof(*block
));
383 rc
= kwboot_tty_recv(fd
, &c
, 1, KWBOOT_BLK_RSP_TIMEO
);
387 if (c
!= ACK
&& c
!= NAK
&& c
!= CAN
)
390 } while (c
!= ACK
&& c
!= NAK
&& c
!= CAN
);
393 kwboot_progress(-1, '+');
395 } while (c
== NAK
&& retries
-- > 0);
418 kwboot_xmodem(int tty
, const void *_data
, size_t size
)
420 const uint8_t *data
= _data
;
421 int rc
, pnum
, N
, err
;
426 kwboot_printv("Sending boot image...\n");
429 struct kwboot_block block
;
432 n
= kwboot_xm_makeblock(&block
,
441 rc
= kwboot_xm_sendblock(tty
, &block
);
446 kwboot_progress(N
* 100 / size
, '.');
449 rc
= kwboot_tty_send_char(tty
, EOT
);
456 kwboot_tty_send_char(tty
, CAN
);
462 kwboot_term_pipe(int in
, int out
, char *quit
, int *s
)
465 char _buf
[128], *buf
= _buf
;
467 nin
= read(in
, buf
, sizeof(buf
));
474 for (i
= 0; i
< nin
; i
++) {
475 if (*buf
== quit
[*s
]) {
483 nout
= write(out
, quit
, *s
);
492 nout
= write(out
, buf
, nin
);
502 kwboot_terminal(int tty
)
506 struct termios otio
, tio
;
512 rc
= tcgetattr(in
, &otio
);
516 rc
= tcsetattr(in
, TCSANOW
, &tio
);
523 kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
524 quit
[0]|0100, quit
[1]);
536 nfds
= nfds
< tty
? tty
: nfds
;
540 nfds
= nfds
< in
? in
: nfds
;
543 nfds
= select(nfds
+ 1, &rfds
, NULL
, NULL
, NULL
);
547 if (FD_ISSET(tty
, &rfds
)) {
548 rc
= kwboot_term_pipe(tty
, STDOUT_FILENO
, NULL
, NULL
);
553 if (FD_ISSET(in
, &rfds
)) {
554 rc
= kwboot_term_pipe(in
, tty
, quit
, &s
);
558 } while (quit
[s
] != 0);
560 tcsetattr(in
, TCSANOW
, &otio
);
566 kwboot_mmap_image(const char *path
, size_t *size
, int prot
)
575 fd
= open(path
, O_RDONLY
);
583 flags
= (prot
& PROT_WRITE
) ? MAP_PRIVATE
: MAP_SHARED
;
585 img
= mmap(NULL
, st
.st_size
, prot
, flags
, fd
, 0);
586 if (img
== MAP_FAILED
) {
595 munmap(img
, st
.st_size
);
605 kwboot_img_csum8(void *_data
, size_t size
)
607 uint8_t *data
= _data
, csum
;
609 for (csum
= 0; size
-- > 0; data
++)
616 kwboot_img_patch_hdr(void *img
, size_t size
)
619 struct main_hdr_v1
*hdr
;
621 size_t hdrsz
= sizeof(*hdr
);
632 image_ver
= image_version(img
);
634 fprintf(stderr
, "Invalid image header version\n");
640 hdrsz
= sizeof(*hdr
);
642 hdrsz
= KWBHEADER_V1_SIZE(hdr
);
644 csum
= kwboot_img_csum8(hdr
, hdrsz
) - hdr
->checksum
;
645 if (csum
!= hdr
->checksum
) {
650 if (hdr
->blockid
== IBR_HDR_UART_ID
) {
655 hdr
->blockid
= IBR_HDR_UART_ID
;
658 * Subtract mkimage header size from destination address
659 * as this header is not expected by the Marvell BootROM.
660 * This way, the execution address is identical to the
661 * one the image is compiled for (TEXT_BASE).
663 hdr
->destaddr
= hdr
->destaddr
- sizeof(struct image_header
);
665 if (image_ver
== 0) {
666 struct main_hdr_v0
*hdr_v0
= img
;
668 hdr_v0
->nandeccmode
= IBR_HDR_ECC_DISABLED
;
669 hdr_v0
->nandpagesize
= 0;
671 hdr_v0
->srcaddr
= hdr_v0
->ext
672 ? sizeof(struct kwb_header
)
676 hdr
->checksum
= kwboot_img_csum8(hdr
, hdrsz
) - csum
;
684 kwboot_usage(FILE *stream
, char *progname
)
687 "Usage: %s [-d | -a | -q <req-delay> | -s <resp-timeo> | -b <image> | -D <image> ] [ -t ] [-B <baud> ] <TTY>\n",
689 fprintf(stream
, "\n");
691 " -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
692 fprintf(stream
, " -p: patch <image> to type 0x69 (uart boot)\n");
694 " -D <image>: boot <image> without preamble (Dove)\n");
695 fprintf(stream
, " -d: enter debug mode\n");
696 fprintf(stream
, " -a: use timings for Armada XP\n");
697 fprintf(stream
, " -q <req-delay>: use specific request-delay\n");
698 fprintf(stream
, " -s <resp-timeo>: use specific response-timeout\n");
699 fprintf(stream
, "\n");
700 fprintf(stream
, " -t: mini terminal\n");
701 fprintf(stream
, "\n");
702 fprintf(stream
, " -B <baud>: set baud rate\n");
703 fprintf(stream
, "\n");
707 main(int argc
, char **argv
)
709 const char *ttypath
, *imgpath
;
710 int rv
, rc
, tty
, term
, prot
, patch
;
728 kwboot_verbose
= isatty(STDOUT_FILENO
);
731 int c
= getopt(argc
, argv
, "hb:ptaB:dD:q:s:");
737 bootmsg
= kwboot_msg_boot
;
747 debugmsg
= kwboot_msg_debug
;
759 msg_req_delay
= KWBOOT_MSG_REQ_DELAY_AXP
;
760 msg_rsp_timeo
= KWBOOT_MSG_RSP_TIMEO_AXP
;
764 msg_req_delay
= atoi(optarg
);
768 msg_rsp_timeo
= atoi(optarg
);
772 speed
= kwboot_tty_speed(atoi(optarg
));
784 if (!bootmsg
&& !term
&& !debugmsg
)
787 if (patch
&& !imgpath
)
790 if (argc
- optind
< 1)
793 ttypath
= argv
[optind
++];
795 tty
= kwboot_open_tty(ttypath
, speed
);
802 prot
= PROT_READ
| (patch
? PROT_WRITE
: 0);
804 img
= kwboot_mmap_image(imgpath
, &size
, prot
);
812 rc
= kwboot_img_patch_hdr(img
, size
);
814 fprintf(stderr
, "%s: Invalid image.\n", imgpath
);
820 rc
= kwboot_debugmsg(tty
, debugmsg
);
826 rc
= kwboot_bootmsg(tty
, bootmsg
);
834 rc
= kwboot_xmodem(tty
, img
, size
);
842 rc
= kwboot_terminal(tty
);
843 if (rc
&& !(errno
== EINTR
)) {
860 kwboot_usage(rv
? stderr
: stdout
, basename(argv
[0]));