FreeCalypso > hg > freecalypso-sw
diff loadtools/romload.c @ 9:fea204bc7674
fc-sertool compiles
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Wed, 01 May 2013 02:43:17 +0000 |
parents | |
children | e2e80a09338e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/romload.c Wed May 01 02:43:17 2013 +0000 @@ -0,0 +1,269 @@ +/* + * This module implements the communication protocol for pushing our + * IRAM-loadable code to the Calypso ROM bootloader. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <termios.h> +#include <unistd.h> +#include "srecreader.h" + +extern int errno; + +extern char *target_ttydev; +extern int target_fd; + +struct srecreader iramimage; + +static int beacon_interval = 13; /* in milliseconds */ + +static u_char beacon_cmd[2] = {'<', 'i'}; + +static u_char param_cmd[11] = {'<', 'p', + 0x00, /* baud rate select code (115200) */ + 0x00, /* DPLL setup: leave it off like on power-up, */ + /* OsmocomBB does the same thing */ + 0x00, 0x04, /* chip select timing (WS) settings */ + /* our setting matches both OsmocomBB */ + /* and what the ROM runs with */ + /* before receiving this command */ + 0x22, /* FFFF:F900 register config, low byte */ + /* OsmocomBB sends 0x00 here, but I've chosen */ + /* 0x22 to match the setting of this register */ + /* used by the boot ROM before this command. */ + 0x00, 0x01, 0xD4, 0xC0 /* UART timeout */ + /* I've chosen the same value as what the */ + /* boot ROM runs with before getting this cmd */ +}; + +static u_char write_cmd[10] = {'<', 'w', 0x01, 0x01, 0x00}; +static u_char cksum_cmd[3] = {'<', 'c'}; +static u_char branch_cmd[6] = {'<', 'b'}; + +#define INTERMEDIATE_TIMEOUT 500 /* ms to wait for responses */ +#define SERIAL_FLUSH_DELAY 200 /* also in ms */ + +/* + * The following function should be called by command line option + * parsers upon encountering the -i option. + */ +set_beacon_interval(arg) + char *arg; +{ + int i; + + i = atoi(arg); + if (i < 2 || i > 500) { + fprintf(stderr, "invalid -i argument specified\n"); + exit(1); + } + beacon_interval = i; +} + +static int +expect_response(timeout) +{ + char buf[2]; + fd_set fds; + struct timeval tv; + int pass, cc; + + for (pass = 0; pass < 2; ) { + FD_ZERO(&fds); + FD_SET(target_fd, &fds); + tv.tv_sec = 0; + tv.tv_usec = timeout * 1000; + cc = select(target_fd+1, &fds, NULL, NULL, &tv); + if (cc < 0) { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + if (cc < 1) + return(-1); + cc = read(target_fd, buf + pass, 2 - pass); + if (cc <= 0) { + perror("read after successful select"); + exit(1); + } + if (pass == 0 && buf[0] != '>') + continue; + pass += cc; + } + return(buf[1]); +} + +static +send_beacons() +{ + printf("Sending beacons to %s\n", target_ttydev); + do + write(target_fd, beacon_cmd, sizeof beacon_cmd); + while (expect_response(beacon_interval) != 'i'); + return 0; +} + +static uint32_t +compute_block_cksum() +{ + uint32_t sum; + int i, llen; + + sum = iramimage.datalen + 5; + llen = iramimage.datalen + 4; + for (i = 0; i < llen; i++) + sum = iramimage.record[i+1]; + return sum; +} + +perform_romload() +{ + int resp; + uint16_t image_cksum; + unsigned long rec_count; + static int zero = 0; + + if (open_srec_file(&iramimage) < 0) + exit(1); + ioctl(target_fd, FIONBIO, &zero); + send_beacons(); + printf("Got beacon response, attempting download\n"); + + usleep(SERIAL_FLUSH_DELAY * 1000); + tcflush(target_fd, TCIFLUSH); + write(target_fd, param_cmd, sizeof param_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'p') { + if (resp < 0) + fprintf(stderr, "No response to <p command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <p command; expected >p\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <p command; expected >p\n", + resp); + exit(1); + } + printf("<p command successful, switching to 115200 baud\n"); + switch_baud_rate(B115200); + usleep(SERIAL_FLUSH_DELAY * 1000); + tcflush(target_fd, TCIFLUSH); + + image_cksum = 0; + for (rec_count = 0; ; rec_count++) { + if (read_s_record(&iramimage) < 0) + exit(1); + switch (iramimage.record_type) { + case '0': + if (iramimage.lineno == 1) + continue; + fprintf(stderr, + "%s: S0 record found in line %d (expected in line 1 only)\n", + iramimage.filename, iramimage.lineno); + exit(1); + case '3': + case '7': + if (s3s7_get_addr_data(&iramimage) < 0) + exit(1); + break; + default: + fprintf(stderr, + "%s line %d: S%c record type not supported\n", + iramimage.filename, iramimage.lineno, + iramimage.record_type); + exit(1); + } + if (iramimage.record_type == '7') + break; + /* must be S3 */ + if (iramimage.datalen < 1) { + fprintf(stderr, + "%s line %d: S3 record has zero data length\n", + iramimage.filename, iramimage.lineno); + exit(1); + } + /* form <w command */ + if (!rec_count) + printf("Sending image payload\n"); + write_cmd[5] = iramimage.datalen; + bcopy(iramimage.record + 1, write_cmd + 6, 4); + write(target_fd, write_cmd, sizeof write_cmd); + write(target_fd, iramimage.record + 5, iramimage.datalen); + /* update our checksum accumulator */ + image_cksum += ~(compute_block_cksum() & 0xFF); + /* collect response */ + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'w') { + fprintf(stderr, "Block #%lu: ", rec_count); + if (resp < 0) + fprintf(stderr, "No response to <w command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <w command; expected >w\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <w command; expected >w\n", + resp); + exit(1); + } + /* on to the next record! */ + } + /* got S7 */ + fclose(iramimage.openfile); + if (!rec_count) { + fprintf(stderr, + "%s line %d: S7 without any preceding S3 data records\n", + iramimage.filename, iramimage.lineno); + exit(1); + } + + /* send <c */ + printf("Sending checksum\n"); + cksum_cmd[2] = ~(image_cksum & 0xFF); + write(target_fd, cksum_cmd, sizeof cksum_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'c') { + if (resp < 0) + fprintf(stderr, "No response to <c command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <c command; expected >c\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <c command; expected >c\n", + resp); + exit(1); + } + printf("<c command successful, sending <b\n"); + + bcopy(iramimage.record + 1, branch_cmd + 2, 4); + write(target_fd, branch_cmd, sizeof branch_cmd); + resp = expect_response(INTERMEDIATE_TIMEOUT); + if (resp != 'b') { + if (resp < 0) + fprintf(stderr, "No response to <b command\n"); + else if (isprint(resp)) + fprintf(stderr, + "Got >%c in response to <b command; expected >b\n", + resp); + else + fprintf(stderr, + "Got > %02X in response to <b command; expected >b\n", + resp); + exit(1); + } + printf("<b command successful: downloaded image should now be running!\n"); + return(0); +}