]>
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".
28 #define PACKED __attribute((packed))
34 * Marvell BootROM UART Sensing
37 static unsigned char kwboot_msg_boot
[] = {
38 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
41 static unsigned char kwboot_msg_debug
[] = {
42 0xDD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
45 /* Defines known to work on Kirkwood */
46 #define KWBOOT_MSG_REQ_DELAY 10 /* ms */
47 #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */
49 /* Defines known to work on Armada XP */
50 #define KWBOOT_MSG_REQ_DELAY_AXP 1000 /* ms */
51 #define KWBOOT_MSG_RSP_TIMEO_AXP 1000 /* ms */
57 #define SOH 1 /* sender start of block header */
58 #define EOT 4 /* sender end of block transfer */
59 #define ACK 6 /* target block ack */
60 #define NAK 21 /* target block negative ack */
61 #define CAN 24 /* target/sender transfer cancellation */
71 #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
73 static int kwboot_verbose
;
75 static int msg_req_delay
= KWBOOT_MSG_REQ_DELAY
;
76 static int msg_rsp_timeo
= KWBOOT_MSG_RSP_TIMEO
;
79 kwboot_printv(const char *fmt
, ...)
94 const char seq
[] = { '-', '\\', '|', '/' };
98 if (state
% div
== 0) {
100 fputc(seq
[state
/ div
% sizeof(seq
)], stdout
);
116 __progress(int pct
, char c
)
118 const int width
= 70;
119 static const char *nl
= "";
122 if (pos
% width
== 0)
123 printf("%s%3d %% [", nl
, pct
);
131 while (pos
++ < width
)
141 kwboot_progress(int _pct
, char c
)
153 kwboot_tty_recv(int fd
, void *buf
, size_t len
, int timeo
)
166 tv
.tv_usec
= timeo
* 1000;
167 if (tv
.tv_usec
> 1000000) {
168 tv
.tv_sec
+= tv
.tv_usec
/ 1000000;
169 tv
.tv_usec
%= 1000000;
173 nfds
= select(fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
181 n
= read(fd
, buf
, len
);
185 buf
= (char *)buf
+ n
;
195 kwboot_tty_send(int fd
, const void *buf
, size_t len
)
206 n
= write(fd
, buf
, len
);
210 buf
= (char *)buf
+ n
;
220 kwboot_tty_send_char(int fd
, unsigned char c
)
222 return kwboot_tty_send(fd
, &c
, 1);
226 kwboot_tty_speed(int baudrate
)
245 kwboot_open_tty(const char *path
, speed_t speed
)
252 fd
= open(path
, O_RDWR
|O_NOCTTY
|O_NDELAY
);
256 memset(&tio
, 0, sizeof(tio
));
259 tio
.c_cflag
= CREAD
|CLOCAL
|CS8
;
262 tio
.c_cc
[VTIME
] = 10;
264 cfsetospeed(&tio
, speed
);
265 cfsetispeed(&tio
, speed
);
267 rc
= tcsetattr(fd
, TCSANOW
, &tio
);
282 kwboot_bootmsg(int tty
, void *msg
)
288 kwboot_printv("Please reboot the target into UART boot mode...");
290 kwboot_printv("Sending boot message. Please reboot the target...");
293 rc
= tcflush(tty
, TCIOFLUSH
);
297 rc
= kwboot_tty_send(tty
, msg
, 8);
299 usleep(msg_req_delay
* 1000);
303 rc
= kwboot_tty_recv(tty
, &c
, 1, msg_rsp_timeo
);
307 } while (rc
|| c
!= NAK
);
315 kwboot_debugmsg(int tty
, void *msg
)
319 kwboot_printv("Sending debug message. Please reboot the target...");
324 rc
= tcflush(tty
, TCIOFLUSH
);
328 rc
= kwboot_tty_send(tty
, msg
, 8);
330 usleep(msg_req_delay
* 1000);
334 rc
= kwboot_tty_recv(tty
, buf
, 16, msg_rsp_timeo
);
346 kwboot_xm_makeblock(struct kwboot_block
*block
, const void *data
,
347 size_t size
, int pnum
)
349 const size_t blksz
= sizeof(block
->data
);
355 block
->_pnum
= ~block
->pnum
;
357 n
= size
< blksz
? size
: blksz
;
358 memcpy(&block
->data
[0], data
, n
);
359 memset(&block
->data
[n
], 0, blksz
- n
);
362 for (i
= 0; i
< n
; i
++)
363 block
->csum
+= block
->data
[i
];
369 kwboot_xm_sendblock(int fd
, struct kwboot_block
*block
)
376 rc
= kwboot_tty_send(fd
, block
, sizeof(*block
));
381 rc
= kwboot_tty_recv(fd
, &c
, 1, KWBOOT_BLK_RSP_TIMEO
);
385 if (c
!= ACK
&& c
!= NAK
&& c
!= CAN
)
388 } while (c
!= ACK
&& c
!= NAK
&& c
!= CAN
);
391 kwboot_progress(-1, '+');
393 } while (c
== NAK
&& retries
-- > 0);
416 kwboot_xmodem(int tty
, const void *_data
, size_t size
)
418 const uint8_t *data
= _data
;
419 int rc
, pnum
, N
, err
;
424 kwboot_printv("Sending boot image...\n");
427 struct kwboot_block block
;
430 n
= kwboot_xm_makeblock(&block
,
439 rc
= kwboot_xm_sendblock(tty
, &block
);
444 kwboot_progress(N
* 100 / size
, '.');
447 rc
= kwboot_tty_send_char(tty
, EOT
);
454 kwboot_tty_send_char(tty
, CAN
);
460 kwboot_term_pipe(int in
, int out
, char *quit
, int *s
)
463 char _buf
[128], *buf
= _buf
;
465 nin
= read(in
, buf
, sizeof(buf
));
472 for (i
= 0; i
< nin
; i
++) {
473 if (*buf
== quit
[*s
]) {
481 nout
= write(out
, quit
, *s
);
490 nout
= write(out
, buf
, nin
);
500 kwboot_terminal(int tty
)
504 struct termios otio
, tio
;
510 rc
= tcgetattr(in
, &otio
);
514 rc
= tcsetattr(in
, TCSANOW
, &tio
);
521 kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
522 quit
[0]|0100, quit
[1]);
534 nfds
= nfds
< tty
? tty
: nfds
;
538 nfds
= nfds
< in
? in
: nfds
;
541 nfds
= select(nfds
+ 1, &rfds
, NULL
, NULL
, NULL
);
545 if (FD_ISSET(tty
, &rfds
)) {
546 rc
= kwboot_term_pipe(tty
, STDOUT_FILENO
, NULL
, NULL
);
551 if (FD_ISSET(in
, &rfds
)) {
552 rc
= kwboot_term_pipe(in
, tty
, quit
, &s
);
556 } while (quit
[s
] != 0);
558 tcsetattr(in
, TCSANOW
, &otio
);
564 kwboot_mmap_image(const char *path
, size_t *size
, int prot
)
573 fd
= open(path
, O_RDONLY
);
581 flags
= (prot
& PROT_WRITE
) ? MAP_PRIVATE
: MAP_SHARED
;
583 img
= mmap(NULL
, st
.st_size
, prot
, flags
, fd
, 0);
584 if (img
== MAP_FAILED
) {
593 munmap(img
, st
.st_size
);
603 kwboot_img_csum8(void *_data
, size_t size
)
605 uint8_t *data
= _data
, csum
;
607 for (csum
= 0; size
-- > 0; data
++)
614 kwboot_img_patch_hdr(void *img
, size_t size
)
619 const size_t hdrsz
= sizeof(*hdr
);
629 csum
= kwboot_img_csum8(hdr
, hdrsz
) - hdr
->checkSum
;
630 if (csum
!= hdr
->checkSum
) {
635 if (hdr
->blockid
== IBR_HDR_UART_ID
) {
640 hdr
->blockid
= IBR_HDR_UART_ID
;
642 hdr
->nandeccmode
= IBR_HDR_ECC_DISABLED
;
643 hdr
->nandpagesize
= 0;
645 hdr
->srcaddr
= hdr
->ext
646 ? sizeof(struct kwb_header
)
649 hdr
->checkSum
= kwboot_img_csum8(hdr
, hdrsz
) - csum
;
657 kwboot_usage(FILE *stream
, char *progname
)
660 "Usage: %s [-d | -a | -b <image> | -D <image> ] [ -t ] [-B <baud> ] <TTY>\n",
662 fprintf(stream
, "\n");
664 " -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
665 fprintf(stream
, " -p: patch <image> to type 0x69 (uart boot)\n");
667 " -D <image>: boot <image> without preamble (Dove)\n");
668 fprintf(stream
, " -d: enter debug mode\n");
669 fprintf(stream
, " -a: use timings for Armada XP\n");
670 fprintf(stream
, "\n");
671 fprintf(stream
, " -t: mini terminal\n");
672 fprintf(stream
, "\n");
673 fprintf(stream
, " -B <baud>: set baud rate\n");
674 fprintf(stream
, "\n");
678 main(int argc
, char **argv
)
680 const char *ttypath
, *imgpath
;
681 int rv
, rc
, tty
, term
, prot
, patch
;
699 kwboot_verbose
= isatty(STDOUT_FILENO
);
702 int c
= getopt(argc
, argv
, "hb:ptaB:dD:");
708 bootmsg
= kwboot_msg_boot
;
718 debugmsg
= kwboot_msg_debug
;
730 msg_req_delay
= KWBOOT_MSG_REQ_DELAY_AXP
;
731 msg_rsp_timeo
= KWBOOT_MSG_RSP_TIMEO_AXP
;
735 speed
= kwboot_tty_speed(atoi(optarg
));
747 if (!bootmsg
&& !term
&& !debugmsg
)
750 if (patch
&& !imgpath
)
753 if (argc
- optind
< 1)
756 ttypath
= argv
[optind
++];
758 tty
= kwboot_open_tty(ttypath
, speed
);
765 prot
= PROT_READ
| (patch
? PROT_WRITE
: 0);
767 img
= kwboot_mmap_image(imgpath
, &size
, prot
);
775 rc
= kwboot_img_patch_hdr(img
, size
);
777 fprintf(stderr
, "%s: Invalid image.\n", imgpath
);
783 rc
= kwboot_debugmsg(tty
, debugmsg
);
789 rc
= kwboot_bootmsg(tty
, bootmsg
);
797 rc
= kwboot_xmodem(tty
, img
, size
);
805 rc
= kwboot_terminal(tty
);
806 if (rc
&& !(errno
== EINTR
)) {
823 kwboot_usage(rv
? stderr
: stdout
, basename(argv
[0]));