FreeCalypso > hg > freecalypso-tools
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e7502631a0f9 |
---|---|
1 /* | |
2 * This module implements the communication protocol for pushing our | |
3 * IRAM-loadable code to the Calypso ROM bootloader. | |
4 */ | |
5 | |
6 #include <sys/types.h> | |
7 #include <sys/ioctl.h> | |
8 #include <sys/time.h> | |
9 #include <sys/errno.h> | |
10 #include <stdint.h> | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <strings.h> | |
14 #include <termios.h> | |
15 #include <unistd.h> | |
16 #include "baudrate.h" | |
17 #include "srecreader.h" | |
18 | |
19 extern int errno; | |
20 | |
21 extern char *target_ttydev; | |
22 extern int target_fd; | |
23 extern struct baudrate baud_rate_table[]; | |
24 extern struct baudrate *find_baudrate_by_name(); | |
25 | |
26 struct srecreader iramimage; | |
27 struct baudrate *romload_baud_rate = baud_rate_table; /* 1st entry default */ | |
28 | |
29 /* global var always defined, but does anything only for GTA0x_AP_BUILD */ | |
30 int gta_modem_poweron = 1; | |
31 | |
32 static int beacon_interval = 13; /* in milliseconds */ | |
33 | |
34 static u_char beacon_cmd[2] = {'<', 'i'}; | |
35 | |
36 static u_char param_cmd[11] = {'<', 'p', | |
37 0x00, /* baud rate select code (115200) */ | |
38 0x00, /* DPLL setup: leave it off like on power-up, */ | |
39 /* OsmocomBB does the same thing */ | |
40 0x00, 0x04, /* chip select timing (WS) settings */ | |
41 /* our setting matches both OsmocomBB */ | |
42 /* and what the ROM runs with */ | |
43 /* before receiving this command */ | |
44 0x22, /* FFFF:F900 register config, low byte */ | |
45 /* OsmocomBB sends 0x00 here, but I've chosen */ | |
46 /* 0x22 to match the setting of this register */ | |
47 /* used by the boot ROM before this command. */ | |
48 0x00, 0x01, 0xD4, 0xC0 /* UART timeout */ | |
49 /* I've chosen the same value as what the */ | |
50 /* boot ROM runs with before getting this cmd */ | |
51 }; | |
52 | |
53 static u_char write_cmd[10] = {'<', 'w', 0x01, 0x01, 0x00}; | |
54 static u_char cksum_cmd[3] = {'<', 'c'}; | |
55 static u_char branch_cmd[6] = {'<', 'b'}; | |
56 | |
57 #define INTERMEDIATE_TIMEOUT 500 /* ms to wait for responses */ | |
58 #define SERIAL_FLUSH_DELAY 200 /* also in ms */ | |
59 | |
60 /* | |
61 * The following function should be called by command line option | |
62 * parsers upon encountering the -i option. | |
63 */ | |
64 set_beacon_interval(arg) | |
65 char *arg; | |
66 { | |
67 int i; | |
68 | |
69 i = atoi(arg); | |
70 if (i < 2 || i > 500) { | |
71 fprintf(stderr, "invalid -i argument specified\n"); | |
72 exit(1); | |
73 } | |
74 beacon_interval = i; | |
75 } | |
76 | |
77 /* | |
78 * The following function should be called by command line option | |
79 * parsers upon encountering the -b option. | |
80 */ | |
81 set_romload_baudrate(arg) | |
82 char *arg; | |
83 { | |
84 struct baudrate *br; | |
85 | |
86 br = find_baudrate_by_name(arg); | |
87 if (!br) | |
88 exit(1); /* error msg already printed */ | |
89 if (br->bootrom_code < 0) { | |
90 fprintf(stderr, | |
91 "baud rate of %s is not supported by the Calypso boot ROM\n", | |
92 br->name); | |
93 exit(1); | |
94 } | |
95 romload_baud_rate = br; | |
96 } | |
97 | |
98 /* | |
99 * The following functions alter some of the parameters sent to the | |
100 * boot ROM in the <p command. | |
101 */ | |
102 set_romload_pll_conf(byte) | |
103 { | |
104 param_cmd[3] = byte; | |
105 } | |
106 | |
107 set_romload_rhea_cntl(byte) | |
108 { | |
109 param_cmd[6] = byte; | |
110 } | |
111 | |
112 static int | |
113 expect_response(timeout) | |
114 { | |
115 char buf[2]; | |
116 fd_set fds; | |
117 struct timeval tv; | |
118 int pass, cc; | |
119 | |
120 for (pass = 0; pass < 2; ) { | |
121 FD_ZERO(&fds); | |
122 FD_SET(target_fd, &fds); | |
123 tv.tv_sec = 0; | |
124 tv.tv_usec = timeout * 1000; | |
125 cc = select(target_fd+1, &fds, NULL, NULL, &tv); | |
126 if (cc < 0) { | |
127 if (errno == EINTR) | |
128 continue; | |
129 perror("select"); | |
130 exit(1); | |
131 } | |
132 if (cc < 1) | |
133 return(-1); | |
134 cc = read(target_fd, buf + pass, 2 - pass); | |
135 if (cc <= 0) { | |
136 perror("read after successful select"); | |
137 exit(1); | |
138 } | |
139 if (pass == 0 && buf[0] != '>') | |
140 continue; | |
141 pass += cc; | |
142 } | |
143 return(buf[1]); | |
144 } | |
145 | |
146 static | |
147 send_beacons() | |
148 { | |
149 printf("Sending beacons to %s\n", target_ttydev); | |
150 #ifdef GTA0x_AP_BUILD | |
151 if (gta_modem_poweron) | |
152 fork_gta_modem_poweron(); | |
153 #endif | |
154 do | |
155 write(target_fd, beacon_cmd, sizeof beacon_cmd); | |
156 while (expect_response(beacon_interval) != 'i'); | |
157 return 0; | |
158 } | |
159 | |
160 static uint32_t | |
161 compute_block_cksum() | |
162 { | |
163 uint32_t sum; | |
164 int i, llen; | |
165 | |
166 sum = iramimage.datalen + 5; | |
167 llen = iramimage.datalen + 4; | |
168 for (i = 0; i < llen; i++) | |
169 sum += iramimage.record[i+1]; | |
170 return sum; | |
171 } | |
172 | |
173 perform_romload() | |
174 { | |
175 int resp; | |
176 uint16_t image_cksum; | |
177 unsigned long rec_count; | |
178 static int zero = 0; | |
179 | |
180 if (open_srec_file(&iramimage) < 0) | |
181 exit(1); | |
182 ioctl(target_fd, FIONBIO, &zero); | |
183 send_beacons(); | |
184 printf("Got beacon response, attempting download\n"); | |
185 | |
186 usleep(SERIAL_FLUSH_DELAY * 1000); | |
187 tcflush(target_fd, TCIFLUSH); | |
188 param_cmd[2] = romload_baud_rate->bootrom_code; | |
189 write(target_fd, param_cmd, sizeof param_cmd); | |
190 resp = expect_response(INTERMEDIATE_TIMEOUT); | |
191 if (resp != 'p') { | |
192 if (resp < 0) | |
193 fprintf(stderr, "No response to <p command\n"); | |
194 else if (isprint(resp)) | |
195 fprintf(stderr, | |
196 "Got >%c in response to <p command; expected >p\n", | |
197 resp); | |
198 else | |
199 fprintf(stderr, | |
200 "Got > %02X in response to <p command; expected >p\n", | |
201 resp); | |
202 exit(1); | |
203 } | |
204 printf("<p command successful, switching to %s baud\n", | |
205 romload_baud_rate->name); | |
206 switch_baud_rate(romload_baud_rate); | |
207 usleep(SERIAL_FLUSH_DELAY * 1000); | |
208 tcflush(target_fd, TCIFLUSH); | |
209 | |
210 image_cksum = 0; | |
211 for (rec_count = 0; ; ) { | |
212 if (read_s_record(&iramimage) < 0) | |
213 exit(1); | |
214 switch (iramimage.record_type) { | |
215 case '0': | |
216 if (iramimage.lineno == 1) | |
217 continue; | |
218 fprintf(stderr, | |
219 "%s: S0 record found in line %d (expected in line 1 only)\n", | |
220 iramimage.filename, iramimage.lineno); | |
221 exit(1); | |
222 case '3': | |
223 case '7': | |
224 if (s3s7_get_addr_data(&iramimage) < 0) | |
225 exit(1); | |
226 break; | |
227 default: | |
228 fprintf(stderr, | |
229 "%s line %d: S%c record type not supported\n", | |
230 iramimage.filename, iramimage.lineno, | |
231 iramimage.record_type); | |
232 exit(1); | |
233 } | |
234 if (iramimage.record_type == '7') | |
235 break; | |
236 /* must be S3 */ | |
237 if (iramimage.datalen < 1) { | |
238 fprintf(stderr, | |
239 "%s line %d: S3 record has zero data length\n", | |
240 iramimage.filename, iramimage.lineno); | |
241 exit(1); | |
242 } | |
243 /* form <w command */ | |
244 if (!rec_count) | |
245 printf("Sending image payload\n"); | |
246 write_cmd[5] = iramimage.datalen; | |
247 bcopy(iramimage.record + 1, write_cmd + 6, 4); | |
248 write(target_fd, write_cmd, sizeof write_cmd); | |
249 write(target_fd, iramimage.record + 5, iramimage.datalen); | |
250 /* update our checksum accumulator */ | |
251 image_cksum += ~compute_block_cksum() & 0xFF; | |
252 /* collect response */ | |
253 resp = expect_response(INTERMEDIATE_TIMEOUT); | |
254 if (resp != 'w') { | |
255 fprintf(stderr, "Block #%lu: ", rec_count); | |
256 if (resp < 0) | |
257 fprintf(stderr, "No response to <w command\n"); | |
258 else if (isprint(resp)) | |
259 fprintf(stderr, | |
260 "Got >%c in response to <w command; expected >w\n", | |
261 resp); | |
262 else | |
263 fprintf(stderr, | |
264 "Got > %02X in response to <w command; expected >w\n", | |
265 resp); | |
266 exit(1); | |
267 } | |
268 putchar('.'); | |
269 fflush(stdout); | |
270 rec_count++; | |
271 } | |
272 /* got S7 */ | |
273 fclose(iramimage.openfile); | |
274 if (!rec_count) { | |
275 fprintf(stderr, | |
276 "%s line %d: S7 without any preceding S3 data records\n", | |
277 iramimage.filename, iramimage.lineno); | |
278 exit(1); | |
279 } | |
280 | |
281 /* send <c */ | |
282 printf("Sending checksum\n"); | |
283 cksum_cmd[2] = ~image_cksum & 0xFF; | |
284 write(target_fd, cksum_cmd, sizeof cksum_cmd); | |
285 resp = expect_response(INTERMEDIATE_TIMEOUT); | |
286 if (resp != 'c') { | |
287 if (resp < 0) | |
288 fprintf(stderr, "No response to <c command\n"); | |
289 else if (isprint(resp)) | |
290 fprintf(stderr, | |
291 "Got >%c in response to <c command; expected >c\n", | |
292 resp); | |
293 else | |
294 fprintf(stderr, | |
295 "Got > %02X in response to <c command; expected >c\n", | |
296 resp); | |
297 exit(1); | |
298 } | |
299 printf("<c command successful, sending <b\n"); | |
300 | |
301 bcopy(iramimage.record + 1, branch_cmd + 2, 4); | |
302 write(target_fd, branch_cmd, sizeof branch_cmd); | |
303 resp = expect_response(INTERMEDIATE_TIMEOUT); | |
304 if (resp != 'b') { | |
305 if (resp < 0) | |
306 fprintf(stderr, "No response to <b command\n"); | |
307 else if (isprint(resp)) | |
308 fprintf(stderr, | |
309 "Got >%c in response to <b command; expected >b\n", | |
310 resp); | |
311 else | |
312 fprintf(stderr, | |
313 "Got > %02X in response to <b command; expected >b\n", | |
314 resp); | |
315 exit(1); | |
316 } | |
317 printf("<b command successful: downloaded image should now be running!\n"); | |
318 return(0); | |
319 } |