1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <signal.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 /* From Nugget OS */
32 #include <application.h>
33 #include <app_nugget.h>
34
35 #include <nos/device.h>
36 #include <nos/transport.h>
37
38 /* Our connection to Citadel */
39 static struct nos_device dev;
40
41 /* Our big transfer buffer. Apps may have smaller size limits. */
42 static uint8_t buf[0x4000];
43
44 enum {
45 BOARD_BINDER,
46 BOARD_PROTO1,
47 BOARD_EVT,
48 };
49
50 /* Global options */
51 static struct option_s {
52 /* program-specific options */
53 uint8_t app_id;
54 uint16_t param;
55 int more;
56 int ascii;
57 int binary;
58 int verbose;
59 int buttons;
60 int board;
61 /* generic connection options */
62 const char *device;
63 } option = {
64 .board = BOARD_EVT,
65 };
66
67 enum no_short_opts_for_these {
68 OPT_DEVICE = 1000,
69 OPT_BUTTONS,
70 OPT_BINDER,
71 OPT_PROTO1,
72 OPT_EVT,
73 };
74
75 static char *short_opts = ":hi:p:m:abv";
76 static const struct option long_opts[] = {
77 /* name hasarg *flag val */
78 {"id", 1, NULL, 'i'},
79 {"param", 1, NULL, 'p'},
80 {"more", 1, NULL, 'm'},
81 {"ascii", 0, NULL, 'a'},
82 {"binary", 0, NULL, 'b'},
83 {"verbose", 0, NULL, 'v'},
84 {"buttons", 0, NULL, OPT_BUTTONS},
85 {"binder", 0, &option.board, BOARD_BINDER},
86 {"proto1", 0, &option.board, BOARD_PROTO1},
87 {"evt", 0, &option.board, BOARD_EVT},
88 {"device", 1, NULL, OPT_DEVICE},
89 {"help", 0, NULL, 'h'},
90 {NULL, 0, NULL, 0},
91 };
92
usage(const char * progname)93 static void usage(const char *progname)
94 {
95 fprintf(stderr, "\n");
96 fprintf(stderr, "Usage: %s\n"
97 "Usage: %s test\n\n"
98 " Quick test to see if Citadel is responsive\n"
99 "\n"
100 " Options:\n"
101 " --buttons Prompt to press buttons\n"
102 " --binder | --proto1 | --evt Specify the board\n\n",
103 progname, progname);
104 fprintf(stderr, "Usage: %s tpm COMMAND [BYTE ...]\n"
105 "\n"
106 " Transmit the COMMAND and possibly any BYTEs using the\n"
107 " TPM Wait mode driver. COMMAND and BYTEs are hex values.\n"
108 "\n"
109 " Options:\n"
110 " -m, --more NUM Exchange NUM additional bytes\n\n",
111 progname);
112 fprintf(stderr, "Usage: %s app [BYTE [BYTE...]]\n"
113 "\n"
114 " Call an application function, passing any BYTEs as args\n"
115 "\n"
116 " Options:\n"
117 " -i --id HEX App ID (default 0x00)\n"
118 " -p, --param HEX Set the command Param field to HEX"
119 " (default 0x0000)\n\n",
120 progname);
121 fprintf(stderr, "Usage: %s rw ADDRESS [VALUE]\n"
122 "\n"
123 " Read or write a memory address on Citadel. Both ADDRESS\n"
124 " and VALUE are 32-bit hex numbers.\n\n",
125 progname);
126 fprintf(stderr, "Common options:\n\n"
127 " -a, --ascii Print response as ASCII string\n"
128 " -b, --binary Dump binary response to stdout\n"
129 " -v, --verbose Increase verbosity. More is noisier\n"
130 " --device PATH spidev device file to open\n"
131 " -h, --help Show this message\n"
132 "\n\n");
133 }
134
135 /****************************************************************************/
136 /* Handy stuff */
137
138 #ifndef MIN
139 #define MIN(a, b) ((a) < (b) ? (a) : (b))
140 #endif
141
142 static int errorcnt;
Error(const char * format,...)143 static void Error(const char *format, ...)
144 {
145 va_list ap;
146
147 va_start(ap, format);
148 fprintf(stderr, "ERROR: ");
149 vfprintf(stderr, format, ap);
150 fprintf(stderr, "\n");
151 va_end(ap);
152
153 errorcnt++;
154 }
155
debug(int lvl,const char * format,...)156 static void debug(int lvl, const char *format, ...)
157 {
158 va_list ap;
159
160 if (lvl > option.verbose)
161 return;
162
163 va_start(ap, format);
164 vfprintf(stderr, format, ap);
165 va_end(ap);
166 }
167
debug_buf(int lvl,uint8_t * buf,int bufsize)168 static void debug_buf(int lvl, uint8_t *buf, int bufsize)
169 {
170 int i;
171
172 if (lvl > option.verbose)
173 return;
174
175 if (bufsize <= 0)
176 return;
177
178 if (option.binary) {
179 fwrite(buf, bufsize, 1, stdout);
180 return;
181 }
182
183 if (option.ascii) {
184 for (i = 0; i < bufsize; i++)
185 printf("%c", isprint(buf[i]) ? buf[i] : '.');
186 printf("\n");
187 return;
188 }
189
190 for (i = 0; i < bufsize;) {
191 if (!(i % 16))
192 printf("0x%06x: ", i);
193 printf(" %02x", buf[i]);
194 i++;
195 if (!(i % 16))
196 printf("\n");
197 }
198 if (i % 16)
199 printf("\n");
200 }
201
debug_retval(int lvl,uint32_t retval,uint32_t replycount)202 static void debug_retval(int lvl, uint32_t retval, uint32_t replycount)
203 {
204 if (lvl > option.verbose)
205 return;
206
207 printf("retval 0x%08x (", retval);
208 switch (retval) {
209 case APP_SUCCESS:
210 printf("success");
211 break;
212 case APP_ERROR_BOGUS_ARGS:
213 printf("bogus args");
214 break;
215 case APP_ERROR_INTERNAL:
216 printf("app is being stupid");
217 break;
218 case APP_ERROR_TOO_MUCH:
219 printf("caller sent too much data");
220 break;
221 default:
222 if (retval >= APP_SPECIFIC_ERROR && retval < APP_LINE_NUMBER_BASE)
223 printf("app-specific error #%d", retval - APP_SPECIFIC_ERROR);
224 else if (retval >= APP_LINE_NUMBER_BASE)
225 printf("error at line %d", retval - APP_LINE_NUMBER_BASE);
226 else
227 printf("unknown");
228 }
229 printf("), replycount 0x%x (%d)\n", replycount, replycount);
230 }
231
232 /****************************************************************************/
233 /* Functionality */
234
do_tpm(int argc,char * argv[])235 static void do_tpm(int argc, char *argv[])
236 {
237 char *e = 0;
238 int i, rv, argcount, optind = 1;
239 uint32_t command, buflen;
240
241 /* Must have a command */
242 if (optind < argc) {
243 command = strtoul(argv[optind], &e, 16);
244 if (e && *e)
245 Error("%s: Invalid COMMAND: \"%s\"", argv[0], argv[optind]);
246 optind++;
247 } else {
248 Error("%s: Missing required COMMAND", argv[0]);
249 return;
250 }
251
252 /* how many bytes to exchange? */
253 argcount = argc - optind;
254
255 buflen = option.more + argcount;
256 if (buflen > MAX_DEVICE_TRANSFER) {
257 Error("%s: Too much to send", argv[0]);
258 return;
259 }
260
261 /* preload BYTEs from command line */
262 for (i = 0; i < argcount; i++) {
263 buf[i] = 0xff & strtoul(argv[optind], &e, 16);
264 if (e && *e) {
265 Error("%s: Invalid byte value: \"%s\"", argv[0], argv[optind]);
266 return;
267 }
268 optind++;
269 }
270
271 /* Okay, let's do something */
272 debug(1, "Command 0x%08x, buflen 0x%x\n", command, buflen);
273
274 if (command & 0x80000000)
275 rv = dev.ops.read(dev.ctx, command, buf, buflen);
276 else
277 rv = dev.ops.write(dev.ctx, command, buf, buflen);
278
279 if (rv != 0)
280 Error("%s: nuts", argv[0]);
281 else if (command & 0x80000000)
282 debug_buf(0, buf, buflen);
283 }
284
do_app(int argc,char * argv[])285 static void do_app(int argc, char *argv[])
286 {
287 char *e = 0;
288 int optind = 1;
289 uint32_t i, buflen, replycount, retval;
290
291 /* preload BYTEs from command line */
292 buflen = argc - optind;
293 for (i = 0; i < buflen; i++) {
294 buf[i] = 0xff & strtoul(argv[optind], &e, 16);
295 if (e && *e) {
296 Error("%s: Invalid byte value: \"%s\"", argv[0], argv[optind]);
297 return;
298 }
299 optind++;
300 }
301
302 debug(1, "AppID 0x%02x, App param 0x%04x, buflen 0x%x\n",
303 option.app_id, option.param, buflen);
304
305 replycount = sizeof(buf);
306 retval = nos_call_application(&dev, option.app_id, option.param,
307 buf, buflen, buf, &replycount);
308 debug_retval(1, retval, replycount);
309 debug_buf(0, buf, replycount);
310 }
311
312 /****************************************************************************/
313 /* Available for bringup/debug only. See b/65067435 */
314
read32(uint32_t address,uint32_t * valptr)315 static uint32_t read32(uint32_t address, uint32_t *valptr)
316 {
317 uint32_t buflen, replycount, retval;
318
319 debug(2, "read from 0x%08x\n", address);
320 buflen = sizeof(address);
321 memcpy(buf, &address, buflen);
322 replycount = sizeof(buf);
323 retval = nos_call_application(&dev, APP_ID_NUGGET, NUGGET_PARAM_READ32,
324 buf, buflen, buf, &replycount);
325 debug_retval(2, retval, replycount);
326 if (replycount == sizeof(*valptr)) {
327 memcpy(valptr, buf, sizeof(*valptr));
328 debug(2, "value is 0x%08x\n", *valptr);
329 }
330
331 return retval;
332 }
333
write32(uint32_t address,uint32_t value)334 static uint32_t write32(uint32_t address, uint32_t value)
335 {
336 uint32_t buflen, replycount, retval;
337 struct nugget_app_write32 w32;
338
339 /* Writing to address */
340 debug(2, "write to 0x%08x with value 0x%08x\n", address, value);
341 w32.address = address;
342 w32.value = value;
343 buflen = sizeof(w32);
344 memcpy(buf, &w32, buflen);
345 replycount = sizeof(buf);
346 retval = nos_call_application(&dev, APP_ID_NUGGET, NUGGET_PARAM_WRITE32,
347 buf, buflen, buf, &replycount);
348 debug_retval(2, retval, replycount);
349
350 return retval;
351 }
352
do_rw(int argc,char * argv[])353 static void do_rw(int argc, char *argv[])
354 {
355 char *e = 0;
356 uint32_t retval, address, value;
357
358 argc = MIN(argc, 3); /* ignore any extra args */
359 switch (argc) {
360 case 3:
361 value = strtoul(argv[2], &e, 16);
362 if (e && *e) {
363 Error("%s: Invalid value: \"%s\"", argv[0], argv[2]);
364 return;
365 }
366 /* fall through */
367 case 2:
368 address = strtoul(argv[1], &e, 16);
369 if (e && *e) {
370 Error("%s: Invalid address: \"%s\"", argv[0], argv[1]);
371 return;
372 }
373 break;
374 default:
375 Error("%s: Missing required address", argv[0]);
376 return;
377 }
378
379 if (argc == 2) {
380 retval = read32(address, &value);
381 if (APP_SUCCESS != retval)
382 Error("%s: Read failed", argv[0]);
383 else
384 printf("0x%08x\n", value);
385 } else {
386 retval = write32(address, value);
387 if (APP_SUCCESS != retval)
388 Error("%s: Write failed", argv[0]);
389 }
390 }
391
392 /****************************************************************************/
393 /*
394 * This stuff is a quick dead-or-alive test for SMT. We assume that the Citadel
395 * chip itself will work because it's passed its own manufacturing tests, but
396 * we need to know that the chip is powered up and the SPI bus and GPIOs are
397 * working. UART passthrough will have to be tested externally.
398 */
399
400 /* ARM GPIO config registers */
401 #define GPIO_DATA 0x40550000
402 #define GPIO_DATAOUT 0x40550004
403 #define GPIO_OUTENSET 0x40550010
404
405 /* Return true on success */
write_to_file(const char * filename,const char * string)406 static int write_to_file(const char *filename, const char *string)
407 {
408 int fd, rv;
409 ssize_t len, num;
410
411 /* Assume valid input */
412 len = strlen(string);
413
414 fd = open(filename, O_WRONLY | O_SYNC);
415 if (fd < 0) {
416 debug(1, "can't open %s for writing: %s", filename, strerror(errno));
417 return 0;
418 }
419
420 num = write(fd, string, len);
421
422 debug(2, "%s(%s, %s) wrote %d / %d\n", __func__, filename, string, num, len);
423
424 if (len != num) {
425 debug(1, "can't write %d bytes to %s: %s", len, filename,
426 strerror(errno));
427 rv = close(fd);
428 if (rv)
429 debug(1, "can't close the file descriptor either: %s",
430 strerror(errno));
431 return 0;
432 }
433
434 rv = close(fd);
435 if (rv) {
436 debug(1, "can't close the file descriptor for %s: %s",
437 filename, strerror(errno));
438 return 0;
439 }
440
441 return 1;
442 }
443
444 /* Return true on success */
read_from_file(const char * filename,char * buf,ssize_t bufsize)445 static int read_from_file(const char *filename, char *buf, ssize_t bufsize)
446 {
447 int fd, rv;
448 ssize_t num;
449
450 fd = open(filename, O_RDONLY);
451 if (fd < 0) {
452 debug(2, "can't open %s for reading: %s", filename, strerror(errno));
453 return 0;
454 }
455
456 num = read(fd, buf, bufsize - 1); /* leave room for '\0' */
457
458 debug(2, "%s(%s) read %d bytes\n", __func__, filename, num);
459
460 if (num < 0) {
461 debug(1, "can't read from %s: %s", filename, strerror(errno));
462 rv = close(fd);
463 if (rv)
464 debug(1, "can't close the file descriptor either: %s",
465 strerror(errno));
466 return 0;
467 }
468
469 if (num == 0) {
470 debug(1, "file %s contains no data", filename);
471 rv = close(fd);
472 if (rv)
473 debug(1, "can't close the file descriptor either: %s",
474 strerror(errno));
475 return 0;
476
477 }
478
479 debug_buf(2, (unsigned char *)buf, num);
480
481 rv = close(fd);
482 if (rv)
483 debug(1, "can't close the file descriptor for %s: %s",
484 filename, strerror(errno));
485
486 return 1;
487 }
488
489 /* Returns true if we're able to export this gpio */
is_ap_exported(uint32_t num)490 static int is_ap_exported(uint32_t num)
491 {
492 char filename[80];
493 char buf[80];
494
495 debug(1, "%s(%d)\n", __func__, num);
496
497 /* It might already be exported. Try to read the value to see. */
498 sprintf(filename, "/sys/class/gpio/gpio%d/value", num);
499 memset(buf, 0, sizeof(buf));
500 if (read_from_file(filename, buf, sizeof(buf)))
501 return 1; /* yep */
502
503 /* Request it */
504 sprintf(buf, "%d", num);
505 if (!write_to_file("/sys/class/gpio/export", buf)) {
506 Error("%s: Can't request export of gpio %d", __func__, num);
507 return 0;
508 }
509
510 /* Try reading the value again */
511 memset(buf, 0, sizeof(buf));
512 if (read_from_file(filename, buf, sizeof(buf)))
513 return 1; /* yep */
514
515 Error("%s: Nuts. Can't get export of gpio %d", __func__, num);
516 return 0;
517 }
518
519 /* Returns true if we're able to set this gpio to an output */
is_ap_output(uint32_t num)520 static int is_ap_output(uint32_t num)
521 {
522 char filename[80];
523 char buf[80];
524
525 debug(1, "%s(%d)\n", __func__, num);
526
527 /* It might already be an output. Let's see. */
528 sprintf(filename, "/sys/class/gpio/gpio%d/direction", num);
529 memset(buf, 0, sizeof(buf));
530 if (!read_from_file(filename, buf, sizeof(buf))) {
531 debug(1, "Can't determine the direction of gpio %d", num);
532 return 0;
533 }
534 if (!strncmp("out", buf, 3))
535 return 1; /* already an output */
536
537 /* Set the direction */
538 sprintf(buf, "%s", "out");
539 if (!write_to_file(filename, buf)) {
540 Error("%s: Can't set the direction of gpio %d", __func__, num);
541 return 0;
542 }
543
544 /* Check again */
545 memset(buf, 0, sizeof(buf));
546 if (!read_from_file(filename, buf, sizeof(buf))) {
547 Error("%s: Can't determine the direction of gpio %d", __func__, num);
548 return 0;
549 }
550 if (!strncmp("out", buf, 3))
551 return 1; /* yep, it's an output */
552
553 Error("%s: Nuts. Can't set the direction of gpio %d", __func__, num);
554 return 0;
555 }
556
557 /* Return true on success */
set_ap_value(uint32_t num,int val)558 static int set_ap_value(uint32_t num, int val)
559 {
560 char filename[80];
561 char buf[80];
562
563 debug(1, "%s(%d, %d)\n", __func__, num, val);
564
565 sprintf(filename, "/sys/class/gpio/gpio%d/value", num);
566 sprintf(buf, "%d", val);
567 if (!write_to_file(filename, buf)) {
568 Error("%s: can't set gpio %d to %d", __func__, num, val);
569 return 0;
570 }
571
572 return 1;
573 }
574
575 /* This wiggles a GPIO on the AP and checks to make sure Citadel saw it */
ap_wiggle(const char * name,uint32_t cit_gpio,uint32_t ap_gpio)576 static void ap_wiggle(const char *name, uint32_t cit_gpio, uint32_t ap_gpio)
577 {
578 uint32_t prev, curr;
579 uint32_t cit_bit;
580
581 cit_bit = (1 << cit_gpio);
582
583 printf("Test %s AP gpio %d => Citadel gpio %d\n", name, ap_gpio, cit_gpio);
584
585 /* Configure AP for output */
586 if (!is_ap_exported(ap_gpio))
587 return;
588 if (!is_ap_output(ap_gpio))
589 return;
590
591 debug(1, "cit_bit 0x%08x\n", cit_bit);
592
593 /* drive low, confirm low */
594 if (!set_ap_value(ap_gpio, 0))
595 return;
596 if (0 != read32(GPIO_DATA, &curr)) {
597 Error("%s: can't read Citadel GPIOs", __func__);
598 return;
599 }
600 debug(1, "citadel 0x%08x\n", curr);
601 if (curr & cit_bit)
602 Error("%s: expected cit_gpio %d low, was high", __func__, cit_gpio);
603 prev = curr;
604
605 /* Drive high, confirm high, no other bits changed */
606 if (!set_ap_value(ap_gpio, 1))
607 return;
608 if (0 != read32(GPIO_DATA, &curr)) {
609 Error("%s: can't read Citadel GPIOs", __func__);
610 return;
611 }
612 debug(1, "citadel 0x%08x\n", curr);
613 if (!(curr & cit_bit))
614 Error("expected cit_gpio %d high, was low", cit_gpio);
615 if (prev != curr && (prev ^ curr) != cit_bit)
616 Error("unexpected GPIO change: prev 0x%08x cur 0x%08x", prev, curr);
617 prev = curr;
618
619 /* Drive Low, confirm low again, no other bits changed */
620 if (!set_ap_value(ap_gpio, 0))
621 return;
622 if (0 != read32(GPIO_DATA, &curr)) {
623 Error("%s: can't read Citadel GPIOs", __func__);
624 return;
625 }
626 debug(1, "citadel 0x%08x\n", curr);
627 if (curr & cit_bit)
628 Error("expected cit_gpio %d low, was high", cit_gpio);
629 if (prev != curr && (prev ^ curr) != cit_bit)
630 Error("unexpected GPIO change: prev 0x%08x cur 0x%08x", prev, curr);
631 }
632
633 static int stopped;
sig_handler(int sig)634 static void sig_handler(int sig)
635 {
636 stopped = 1;
637 printf("Signal %d recognized\n", sig);
638 }
639
640 /* This prompts the user to push a button and waits for Citadel to see it */
phys_wiggle(uint32_t cit_gpio,const char * button)641 static void phys_wiggle(uint32_t cit_gpio, const char *button)
642 {
643 uint32_t prev, curr;
644 uint32_t cit_bit;
645
646 stopped = 0;
647 signal(SIGINT, sig_handler);
648
649 cit_bit = (1 << cit_gpio);
650
651 debug(1, "%s(%d) cit_bit 0x%08x\n", __func__, cit_gpio, cit_bit);
652
653 /* read initial value */
654 if (0 != read32(GPIO_DATA, &curr)) {
655 Error("%s: can't read Citadel GPIOs", __func__);
656 return;
657 }
658 debug(1, "initial value 0x%08x\n", curr);
659 prev = curr;
660
661 printf("\nPlease PRESS the %s button...\n", button);
662 do {
663 usleep(100 * 1000);
664 if (0 != read32(GPIO_DATA, &curr)) {
665 Error("%s: can't read Citadel GPIOs", __func__);
666 return;
667 }
668 } while (prev == curr && !stopped);
669 debug(1, "new value 0x%08x\n", curr);
670 if ((prev ^ curr) != cit_bit)
671 Error("%s: multiple cit_gpios changed: prev 0x%08x cur 0x%08x",
672 __func__, prev, curr);
673 prev = curr;
674
675 printf("Please RELEASE the %s button...\n", button);
676 do {
677 usleep(100 * 1000);
678 if (0 != read32(GPIO_DATA, &curr)) {
679 Error("%s: can't read Citadel GPIOs", __func__);
680 return;
681 }
682 } while (prev == curr && !stopped);
683 debug(1, "new value 0x%08x\n", curr);
684 if ((prev ^ curr) != cit_bit)
685 Error("%s: multiple cit_gpios changed: prev 0x%08x cur 0x%08x",
686 __func__, prev, curr);
687
688 signal(SIGINT, SIG_DFL);
689 }
690
691 /* How long to wait for an interrupt to trigger (msecs) */
692 #define INTERRUPT_TIMEOUT 100
693
694 /* Make Citadel wiggle its CTDL_AP_IRQ output, which we should notice */
cit_interrupt(const char * name,uint32_t cit_gpio)695 static void cit_interrupt(const char *name, uint32_t cit_gpio)
696 {
697 uint32_t curr;
698 uint32_t cit_bit;
699 int rv;
700
701 printf("Test %s Citadel gpio %d => AP kernel driver\n", name, cit_gpio);
702
703 cit_bit = (1 << cit_gpio);
704
705 debug(1, "%s(%s, %d) cit_bit 0x%08x\n", __func__, name, cit_gpio, cit_bit);
706
707 /* First, let's see what Citadel is driving */
708 if (0 != read32(GPIO_DATAOUT, &curr)) {
709 Error("%s: can't read Citadel GPIOs", __func__);
710 return;
711 }
712
713 debug(1, "initial value 0x%08x\n", curr);
714 if (curr & cit_bit) {
715 /* Citadel is already driving it, so we should see it immediately */
716 rv = dev.ops.wait_for_interrupt(dev.ctx, INTERRUPT_TIMEOUT);
717 if (rv > 1) {
718 debug(2, "CTDL_AP_IRQ is already asserted\n");
719 } else {
720 Error("%s: CTDL_AP_IRQ is 1, but wait_for_interrupt() returned %d",
721 __func__, rv);
722 return;
723 }
724
725 /* Tell Citadel to stop driving it */
726 if (0 != write32(GPIO_DATAOUT, curr & (~cit_bit))) {
727 Error("%s: can't write Citadel GPIOs", __func__);
728 return;
729 }
730
731 /* Make sure it obeyed */
732 if (0 != read32(GPIO_DATAOUT, &curr)) {
733 Error("%s: can't read Citadel GPIOs", __func__);
734 return;
735 }
736 if (curr & cit_bit) {
737 Error("%s: Citadel isn't changing its GPIOs", __func__);
738 return;
739 }
740 }
741
742 debug(1, "there should be no immediate interrupt\n");
743 rv = dev.ops.wait_for_interrupt(dev.ctx, INTERRUPT_TIMEOUT);
744 if (rv == 0) {
745 debug(2, "CTDL_AP_IRQ not asserted and not triggered\n");
746 } else {
747 Error("%s: CTDL_AP_IRQ is 0, but wait_for_interrupt() returned %d",
748 __func__, rv);
749 return;
750 }
751
752 debug(1, "tell Citadel to trigger an interrupt\n");
753 if (0 != write32(GPIO_DATAOUT, curr | cit_bit)) {
754 Error("%s: can't write Citadel GPIOs", __func__);
755 return;
756 }
757
758 rv = dev.ops.wait_for_interrupt(dev.ctx, INTERRUPT_TIMEOUT);
759 if (rv > 0) {
760 debug(2, "CTDL_AP_IRQ is asserted and triggered\n");
761 } else {
762 Error("%s: CTDL_AP_IRQ is 1, but wait_for_interrupt() returned %d",
763 __func__, rv);
764 return;
765 }
766
767 /* Tell Citadel to stop driving it */
768 if (0 != write32(GPIO_DATAOUT, curr & (~cit_bit))) {
769 Error("%s: can't write Citadel GPIOs", __func__);
770 return;
771 }
772 }
773
do_test(void)774 static void do_test(void)
775 {
776 uint32_t retval, replycount, value;
777 int ctdl_ap_irq_is_driven = 0;
778
779 /* Using the Transport API only. Nugget OS doesn't have any Datagram apps. */
780 printf("Get version string...\n");
781 replycount = sizeof(buf);
782 retval = nos_call_application(&dev, APP_ID_NUGGET, NUGGET_PARAM_VERSION,
783 buf, 0, buf, &replycount);
784 if (retval != 0) {
785 Error("Get version failed with 0x%08x", retval);
786 debug_retval(0, retval, replycount);
787 goto done;
788 }
789 if (replycount < 4 || replycount > 1024)
790 Error("Get version returned %d bytes, which seems wrong", replycount);
791 /* might be okay, though */
792 debug_buf(1, buf, replycount);
793
794 /*
795 * We want to drive each GPIO from the AP side and just check that
796 * Citadel can see it wiggle. Citadel treats them all as inputs for
797 * now. We'll have to update our tests when that changes, of course.
798 */
799
800 printf("Read GPIO direction\n");
801 retval = read32(GPIO_OUTENSET, &value);
802 if (retval != 0) {
803 Error("Reading GPIO direction failed with 0x%08x", retval);
804 goto done;
805 }
806 switch (value) {
807 case 0x00000000:
808 debug(1, "Citadel's GPIOs are all inputs\n");
809 break;
810 case 0x00000080:
811 debug(1, "Citadel is driving CTDL_AP_IRQ\n");
812 ctdl_ap_irq_is_driven = 1;
813 break;
814 default:
815 /* This is unexpected, but keep going */
816 Error("GPIO direction = 0x%08x\n", value);
817 }
818
819 /*
820 * The MSM GPIOs have moved all around with each revision.
821 *
822 * Net Name Citadel Pin BINDER B1PROTO1 B1EVT1
823 *
824 * CTDL_AP_IRQ DIOA5 7 96 96 129
825 * AP_CTDL_IRQ DIOA11 6 94 94 135
826 * AP_SEC_STATE DIOB7 4 76 76 76
827 * AP_PWR_STATE DIOB8 5 69 69 69
828 * CCD_CABLE_DET DIOA6 8 127 126 126
829 */
830
831 if (ctdl_ap_irq_is_driven) {
832 /* Citadel should interrupt us */
833 cit_interrupt("CTDL_AP_IRQ", 7);
834 } else {
835 /* We'll wiggle the AP's GPIO and make sure Citadel sees it */
836 if (option.board == BOARD_EVT)
837 ap_wiggle("CTDL_AP_IRQ", 7, 129);
838 else
839 ap_wiggle("CTDL_AP_IRQ", 7, 96);
840 }
841
842 if (option.board == BOARD_EVT)
843 ap_wiggle("AP_CTDL_IRQ", 6, 135);
844 else
845 ap_wiggle("AP_CTDL_IRQ", 6, 94);
846
847 ap_wiggle("AP_SEC_STATE", 4, 76);
848 ap_wiggle("AP_PWR_STATE", 5, 69);
849
850 if (option.board == BOARD_BINDER)
851 ap_wiggle("CCD_CABLE_DET", 8, 127);
852 else
853 ap_wiggle("CCD_CABLE_DET", 8, 126);
854
855 /*
856 * Citadel should be able to drive all the physical buttons under
857 * certain circumstances, but I don't know how to confirm whether the
858 * AP sees them change. We'll have to prompt the user to poke them to
859 * verify the connectivity. That's probably tested elsewhere, though.
860 */
861 if (option.buttons) {
862
863 if (option.board != BOARD_PROTO1)
864 /* We had to cut this trace on proto1 (b/66976641) */
865 phys_wiggle(0, "Power");
866
867 phys_wiggle(1, "Volume Down");
868 phys_wiggle(2, "Volume Up");
869
870 if (option.board == BOARD_BINDER)
871 /* There's only a button on the binder board */
872 phys_wiggle(10, "Forced USB Boot");
873 }
874
875 /*
876 * These are harder to test. We'll have to change the UART passthrough
877 * to access the Citadel console and do these manually:
878 *
879 * Citadel GPIO 3 MSM_RST_OUT_L should wiggle when the phone reboots
880 * Citadel GPIO 9 PM_MSM_RST_L should force the AP to reboot
881 */
882
883 done:
884 if (errorcnt)
885 printf("\nFAIL FAIL FAIL\n\n");
886 else
887 printf("\nPASS PASS PASS\n\n");
888 }
889
890 /****************************************************************************/
891
892 /*
893 * Any SPI bus activity will wake Citadel from deep sleep, so we'll just send
894 * it a single bogus command. If Citadel's already awake, it will ignore it.
895 * We don't bother tracking or reporting errors. The test will report any real
896 * errors.
897 */
898 #define IGNORED_COMMAND (CMD_ID(APP_ID_TEST) | CMD_PARAM(0xffff))
poke_citadel(void)899 static void poke_citadel(void)
900 {
901 int rv;
902
903 rv = dev.ops.write(dev.ctx, IGNORED_COMMAND, 0, 0);
904
905 /* If Citadel was asleep, give it some time to wake up */
906 if (rv == -EAGAIN)
907 usleep(50000);
908 }
909
910
911 static int stopping_citadeld_fixed_it;
connect_to_citadel(void)912 static int connect_to_citadel(void)
913 {
914 int rv = nos_device_open(option.device, &dev);
915
916 if (rv == -EBUSY) {
917 /* Try stopping citadeld */
918 debug(1, "citadel device is busy, stopping citadeld...\n");
919 if (system("setprop ctl.stop vendor.citadeld") == 0) {
920 /* See if that helped */
921 rv = nos_device_open(option.device, &dev);
922 if (rv == 0) {
923 debug(1, " okay, that worked\n");
924 stopping_citadeld_fixed_it = 1;
925 return rv;
926 } else {
927 debug(1, " nope, didn't help\n");
928 }
929 } else {
930 debug(1, " huh. couldn't stop it\n");
931 }
932 }
933
934 if (rv)
935 Error("Unable to connect to Citadel: %s", strerror(-rv));
936
937 return rv;
938 }
939
disconnect_from_citadel(void)940 static void disconnect_from_citadel(void)
941 {
942 dev.ops.close(dev.ctx);
943 if (stopping_citadeld_fixed_it) {
944 debug(1, "We stopped citadeld earlier, so start it up again\n");
945 (void)system("setprop ctl.start vendor.citadeld");
946 }
947 }
948
main(int argc,char * argv[])949 int main(int argc, char *argv[])
950 {
951 int i;
952 int idx = 0;
953 char *e = 0;
954 char *this_prog;
955
956 this_prog= strrchr(argv[0], '/');
957 if (this_prog)
958 this_prog++;
959 else
960 this_prog = argv[0];
961
962 opterr = 0; /* quiet, you */
963 while ((i = getopt_long(argc, argv, short_opts, long_opts, &idx)) != -1) {
964 switch (i) {
965 /* program-specific options */
966 case 'i':
967 option.app_id = (uint8_t)strtoul(optarg, &e, 16);
968 if (!*optarg || (e && *e))
969 Error("Invalid argument: \"%s\"", optarg);
970 break;
971 case 'p':
972 option.param = (uint16_t)strtoul(optarg, &e, 16);
973 if (!*optarg || (e && *e))
974 Error("Invalid argument: \"%s\"", optarg);
975 break;
976 case 'm':
977 option.more = (uint32_t)strtoul(optarg, &e, 0);
978 if (!*optarg || (e && *e) || option.more < 0)
979 Error("Invalid argument: \"%s\"", optarg);
980 break;
981 case 'a':
982 option.ascii = 1;
983 option.binary = 0;
984 break;
985 case 'b':
986 option.ascii = 0;
987 option.binary = 1;
988 break;
989 case 'v':
990 option.verbose++;
991 break;
992 case OPT_BUTTONS:
993 option.buttons = 1;
994 break;
995
996 /* generic options below */
997 case OPT_DEVICE:
998 option.device = optarg;
999 break;
1000 case 'h':
1001 usage(this_prog);
1002 return 0;
1003 case 0:
1004 break;
1005 case '?':
1006 if (optopt)
1007 Error("Unrecognized option: -%c", optopt);
1008 else
1009 Error("Unrecognized option: %s", argv[optind - 1]);
1010 usage(this_prog);
1011 break;
1012 case ':':
1013 Error("Missing argument to %s", argv[optind - 1]);
1014 break;
1015 default:
1016 Error("Internal error at %s:%d", __FILE__, __LINE__);
1017 exit(1);
1018 }
1019 }
1020
1021 if (errorcnt)
1022 return !!errorcnt;
1023
1024 if (connect_to_citadel() != 0)
1025 return !!errorcnt;
1026
1027 /* Wake Citadel from deep sleep */
1028 poke_citadel();
1029
1030 /*
1031 * We can freely intermingle options and args, so the function should
1032 * be the first non-option. Try to pick it out if it exists.
1033 */
1034 if (argc > optind) {
1035 if (!strcmp("tpm", argv[optind]))
1036 do_tpm(argc - optind, argv + optind);
1037 else if (!strcmp("app", argv[optind]))
1038 do_app(argc - optind, argv + optind);
1039 else if (!strcmp("rw", argv[optind]))
1040 do_rw(argc - optind, argv + optind);
1041 else
1042 do_test();
1043 /*
1044 * "test" is the default function, but it doesn't take any args
1045 * so anything not listed is just silently ignored. Too bad.
1046 */
1047 } else {
1048 do_test();
1049 }
1050
1051 disconnect_from_citadel();
1052 return !!errorcnt;
1053 }
1054