• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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