FreeCalypso > hg > freecalypso-tools
diff loadtools/romload.c @ 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 11 Jun 2016 00:13:35 +0000 |
parents | |
children | 8c011177adb9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/romload.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,319 @@ +/* + * 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 "baudrate.h" +#include "srecreader.h" + +extern int errno; + +extern char *target_ttydev; +extern int target_fd; +extern struct baudrate baud_rate_table[]; +extern struct baudrate *find_baudrate_by_name(); + +struct srecreader iramimage; +struct baudrate *romload_baud_rate = baud_rate_table; /* 1st entry default */ + +/* global var always defined, but does anything only for GTA0x_AP_BUILD */ +int gta_modem_poweron = 1; + +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; +} + +/* + * The following function should be called by command line option + * parsers upon encountering the -b option. + */ +set_romload_baudrate(arg) + char *arg; +{ + struct baudrate *br; + + br = find_baudrate_by_name(arg); + if (!br) + exit(1); /* error msg already printed */ + if (br->bootrom_code < 0) { + fprintf(stderr, + "baud rate of %s is not supported by the Calypso boot ROM\n", + br->name); + exit(1); + } + romload_baud_rate = br; +} + +/* + * The following functions alter some of the parameters sent to the + * boot ROM in the <p command. + */ +set_romload_pll_conf(byte) +{ + param_cmd[3] = byte; +} + +set_romload_rhea_cntl(byte) +{ + param_cmd[6] = byte; +} + +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); +#ifdef GTA0x_AP_BUILD + if (gta_modem_poweron) + fork_gta_modem_poweron(); +#endif + 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); + param_cmd[2] = romload_baud_rate->bootrom_code; + 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 %s baud\n", + romload_baud_rate->name); + switch_baud_rate(romload_baud_rate); + usleep(SERIAL_FLUSH_DELAY * 1000); + tcflush(target_fd, TCIFLUSH); + + image_cksum = 0; + for (rec_count = 0; ; ) { + 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); + } + putchar('.'); + fflush(stdout); + rec_count++; + } + /* 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); +}