]>
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
;
79 static int blk_rsp_timeo
= KWBOOT_BLK_RSP_TIMEO
;
82 kwboot_printv(const char *fmt
, ...)
97 const char seq
[] = { '-', '\\', '|', '/' };
101 if (state
% div
== 0) {
103 fputc(seq
[state
/ div
% sizeof(seq
)], stdout
);
119 __progress(int pct
, char c
)
121 const int width
= 70;
122 static const char *nl
= "";
125 if (pos
% width
== 0)
126 printf("%s%3d %% [", nl
, pct
);
134 while (pos
++ < width
)
144 kwboot_progress(int _pct
, char c
)
156 kwboot_tty_recv(int fd
, void *buf
, size_t len
, int timeo
)
169 tv
.tv_usec
= timeo
* 1000;
170 if (tv
.tv_usec
> 1000000) {
171 tv
.tv_sec
+= tv
.tv_usec
/ 1000000;
172 tv
.tv_usec
%= 1000000;
176 nfds
= select(fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
184 n
= read(fd
, buf
, len
);
188 buf
= (char *)buf
+ n
;
198 kwboot_tty_send(int fd
, const void *buf
, size_t len
)
209 n
= write(fd
, buf
, len
);
213 buf
= (char *)buf
+ n
;
223 kwboot_tty_send_char(int fd
, unsigned char c
)
225 return kwboot_tty_send(fd
, &c
, 1);
229 kwboot_tty_speed(int baudrate
)
248 kwboot_open_tty(const char *path
, speed_t speed
)
255 fd
= open(path
, O_RDWR
|O_NOCTTY
|O_NDELAY
);
259 memset(&tio
, 0, sizeof(tio
));
262 tio
.c_cflag
= CREAD
|CLOCAL
|CS8
;
265 tio
.c_cc
[VTIME
] = 10;
267 cfsetospeed(&tio
, speed
);
268 cfsetispeed(&tio
, speed
);
270 rc
= tcsetattr(fd
, TCSANOW
, &tio
);
285 kwboot_bootmsg(int tty
, void *msg
)
291 kwboot_printv("Please reboot the target into UART boot mode...");
293 kwboot_printv("Sending boot message. Please reboot the target...");
296 rc
= tcflush(tty
, TCIOFLUSH
);
300 rc
= kwboot_tty_send(tty
, msg
, 8);
302 usleep(msg_req_delay
* 1000);
306 rc
= kwboot_tty_recv(tty
, &c
, 1, msg_rsp_timeo
);
310 } while (rc
|| c
!= NAK
);
318 kwboot_debugmsg(int tty
, void *msg
)
322 kwboot_printv("Sending debug message. Please reboot the target...");
327 rc
= tcflush(tty
, TCIOFLUSH
);
331 rc
= kwboot_tty_send(tty
, msg
, 8);
333 usleep(msg_req_delay
* 1000);
337 rc
= kwboot_tty_recv(tty
, buf
, 16, msg_rsp_timeo
);
349 kwboot_xm_makeblock(struct kwboot_block
*block
, const void *data
,
350 size_t size
, int pnum
)
352 const size_t blksz
= sizeof(block
->data
);
358 block
->_pnum
= ~block
->pnum
;
360 n
= size
< blksz
? size
: blksz
;
361 memcpy(&block
->data
[0], data
, n
);
362 memset(&block
->data
[n
], 0, blksz
- n
);
365 for (i
= 0; i
< n
; i
++)
366 block
->csum
+= block
->data
[i
];
372 kwboot_xm_sendblock(int fd
, struct kwboot_block
*block
)
379 rc
= kwboot_tty_send(fd
, block
, sizeof(*block
));
384 rc
= kwboot_tty_recv(fd
, &c
, 1, blk_rsp_timeo
);
388 if (c
!= ACK
&& c
!= NAK
&& c
!= CAN
)
391 } while (c
!= ACK
&& c
!= NAK
&& c
!= CAN
);
394 kwboot_progress(-1, '+');
396 } while (c
== NAK
&& retries
-- > 0);
419 kwboot_xmodem(int tty
, const void *_data
, size_t size
)
421 const uint8_t *data
= _data
;
422 int rc
, pnum
, N
, err
;
427 kwboot_printv("Sending boot image...\n");
430 struct kwboot_block block
;
433 n
= kwboot_xm_makeblock(&block
,
442 rc
= kwboot_xm_sendblock(tty
, &block
);
447 kwboot_progress(N
* 100 / size
, '.');
450 rc
= kwboot_tty_send_char(tty
, EOT
);
457 kwboot_tty_send_char(tty
, CAN
);
463 kwboot_term_pipe(int in
, int out
, char *quit
, int *s
)
466 char _buf
[128], *buf
= _buf
;
468 nin
= read(in
, buf
, sizeof(buf
));
475 for (i
= 0; i
< nin
; i
++) {
476 if (*buf
== quit
[*s
]) {
484 nout
= write(out
, quit
, *s
);
493 nout
= write(out
, buf
, nin
);
503 kwboot_terminal(int tty
)
507 struct termios otio
, tio
;
513 rc
= tcgetattr(in
, &otio
);
517 rc
= tcsetattr(in
, TCSANOW
, &tio
);
524 kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
525 quit
[0]|0100, quit
[1]);
537 nfds
= nfds
< tty
? tty
: nfds
;
541 nfds
= nfds
< in
? in
: nfds
;
544 nfds
= select(nfds
+ 1, &rfds
, NULL
, NULL
, NULL
);
548 if (FD_ISSET(tty
, &rfds
)) {
549 rc
= kwboot_term_pipe(tty
, STDOUT_FILENO
, NULL
, NULL
);
554 if (FD_ISSET(in
, &rfds
)) {
555 rc
= kwboot_term_pipe(in
, tty
, quit
, &s
);
559 } while (quit
[s
] != 0);
561 tcsetattr(in
, TCSANOW
, &otio
);
567 kwboot_mmap_image(const char *path
, size_t *size
, int prot
)
576 fd
= open(path
, O_RDONLY
);
584 flags
= (prot
& PROT_WRITE
) ? MAP_PRIVATE
: MAP_SHARED
;
586 img
= mmap(NULL
, st
.st_size
, prot
, flags
, fd
, 0);
587 if (img
== MAP_FAILED
) {
596 munmap(img
, st
.st_size
);
606 kwboot_img_csum8(void *_data
, size_t size
)
608 uint8_t *data
= _data
, csum
;
610 for (csum
= 0; size
-- > 0; data
++)
617 kwboot_img_patch_hdr(void *img
, size_t size
)
620 struct main_hdr_v1
*hdr
;
622 size_t hdrsz
= sizeof(*hdr
);
633 image_ver
= image_version(img
);
635 fprintf(stderr
, "Invalid image header version\n");
641 hdrsz
= sizeof(*hdr
);
643 hdrsz
= KWBHEADER_V1_SIZE(hdr
);
645 csum
= kwboot_img_csum8(hdr
, hdrsz
) - hdr
->checksum
;
646 if (csum
!= hdr
->checksum
) {
651 if (hdr
->blockid
== IBR_HDR_UART_ID
) {
656 hdr
->blockid
= IBR_HDR_UART_ID
;
658 if (image_ver
== 0) {
659 struct main_hdr_v0
*hdr_v0
= img
;
661 hdr_v0
->nandeccmode
= IBR_HDR_ECC_DISABLED
;
662 hdr_v0
->nandpagesize
= 0;
664 hdr_v0
->srcaddr
= hdr_v0
->ext
665 ? sizeof(struct kwb_header
)
669 hdr
->checksum
= kwboot_img_csum8(hdr
, hdrsz
) - csum
;
677 kwboot_usage(FILE *stream
, char *progname
)
680 "Usage: %s [OPTIONS] [-b <image> | -D <image> ] [-B <baud> ] <TTY>\n",
682 fprintf(stream
, "\n");
684 " -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
685 fprintf(stream
, " -p: patch <image> to type 0x69 (uart boot)\n");
687 " -D <image>: boot <image> without preamble (Dove)\n");
688 fprintf(stream
, " -d: enter debug mode\n");
689 fprintf(stream
, " -a: use timings for Armada XP\n");
690 fprintf(stream
, " -q <req-delay>: use specific request-delay\n");
691 fprintf(stream
, " -s <resp-timeo>: use specific response-timeout\n");
693 " -o <block-timeo>: use specific xmodem block timeout\n");
694 fprintf(stream
, "\n");
695 fprintf(stream
, " -t: mini terminal\n");
696 fprintf(stream
, "\n");
697 fprintf(stream
, " -B <baud>: set baud rate\n");
698 fprintf(stream
, "\n");
702 main(int argc
, char **argv
)
704 const char *ttypath
, *imgpath
;
705 int rv
, rc
, tty
, term
, prot
, patch
;
723 kwboot_verbose
= isatty(STDOUT_FILENO
);
726 int c
= getopt(argc
, argv
, "hb:ptaB:dD:q:s:o:");
732 bootmsg
= kwboot_msg_boot
;
742 debugmsg
= kwboot_msg_debug
;
754 msg_req_delay
= KWBOOT_MSG_REQ_DELAY_AXP
;
755 msg_rsp_timeo
= KWBOOT_MSG_RSP_TIMEO_AXP
;
759 msg_req_delay
= atoi(optarg
);
763 msg_rsp_timeo
= atoi(optarg
);
767 blk_rsp_timeo
= atoi(optarg
);
771 speed
= kwboot_tty_speed(atoi(optarg
));
783 if (!bootmsg
&& !term
&& !debugmsg
)
786 if (patch
&& !imgpath
)
789 if (argc
- optind
< 1)
792 ttypath
= argv
[optind
++];
794 tty
= kwboot_open_tty(ttypath
, speed
);
801 prot
= PROT_READ
| (patch
? PROT_WRITE
: 0);
803 img
= kwboot_mmap_image(imgpath
, &size
, prot
);
811 rc
= kwboot_img_patch_hdr(img
, size
);
813 fprintf(stderr
, "%s: Invalid image.\n", imgpath
);
819 rc
= kwboot_debugmsg(tty
, debugmsg
);
825 rc
= kwboot_bootmsg(tty
, bootmsg
);
833 rc
= kwboot_xmodem(tty
, img
, size
);
841 rc
= kwboot_terminal(tty
);
842 if (rc
&& !(errno
== EINTR
)) {
859 kwboot_usage(rv
? stderr
: stdout
, basename(argv
[0]));