diff options
-rw-r--r-- | util/ectool.c | 143 |
1 files changed, 122 insertions, 21 deletions
diff --git a/util/ectool.c b/util/ectool.c index e78ef5d65f..28c2258af1 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -98,7 +98,7 @@ const char help_str[] = " Erases EC flash\n" " flashinfo\n" " Prints information on the EC flash\n" - " flashpd\n" + " flashpd <dev_id> <port> <filename>\n" " Flash commands over PD\n" " flashprotect [now] [enable | disable]\n" " Prints or sets EC flash protection state\n" @@ -836,10 +836,86 @@ int cmd_rw_hash_pd(int argc, char *argv[]) return rv; } +/** + * determine if in GFU mode or not. + * + * NOTE, Sends HOST commands that modify ec_outbuf contents. + * + * @opos return value of GFU mode object position or zero if not found + * @port port number to query + * @return 1 if in GFU mode, 0 if not, -1 if error + */ +static int in_gfu_mode(int *opos, int port) +{ + int i; + struct ec_params_usb_pd_get_mode_request *p = + (struct ec_params_usb_pd_get_mode_request *)ec_outbuf; + struct ec_params_usb_pd_get_mode_response *r = + (struct ec_params_usb_pd_get_mode_response *)ec_inbuf; + p->port = port; + p->svid_idx = 0; + do { + ec_command(EC_CMD_USB_PD_GET_AMODE, 0, p, sizeof(*p), + ec_inbuf, ec_max_insize); + if (!r->svid || (r->svid == USB_VID_GOOGLE)) + break; + p->svid_idx++; + } while (p->svid_idx < SVID_DISCOVERY_MAX); + + if (r->svid != USB_VID_GOOGLE) { + fprintf(stderr, "Google VID not returned\n"); + return -1; + } + + *opos = 0; /* invalid ... must be 1 thru 6 */ + for (i = 0; i < PDO_MODES; i++) { + if (r->vdo[i] == MODE_GOOGLE_FU) { + *opos = i + 1; + break; + } + } + + return r->active && ((r->idx + 1) == *opos); +} + +/** + * Enter GFU mode. + * + * NOTE, Sends HOST commands that modify ec_outbuf contents. + * + * @port port number to enter GFU on. + * @return 1 if entered GFU mode, 0 if not, -1 if error + */ +static int enter_gfu_mode(int port) +{ + int opos; + struct ec_params_usb_pd_set_mode_request *p = + (struct ec_params_usb_pd_set_mode_request *)ec_outbuf; + int gfu_mode = in_gfu_mode(&opos, port); + + if (gfu_mode < 0) { + fprintf(stderr, "Failed to query GFU mode support\n"); + return 0; + } else if (!gfu_mode) { + if (!opos) { + fprintf(stderr, "Invalid object position %d\n", opos); + return 0; + } + p->port = port; + p->svid = USB_VID_GOOGLE; + p->opos = opos; + + ec_command(EC_CMD_USB_PD_SET_AMODE, 0, p, sizeof(*p), + NULL, 0); + usleep(500000); /* sleep to allow time for set mode */ + gfu_mode = in_gfu_mode(&opos, port); + } + return gfu_mode; +} int cmd_pd_device_info(int argc, char *argv[]) { - int i, rv; + int i, rv, port; char *e; struct ec_params_usb_pd_info_request *p = (struct ec_params_usb_pd_info_request *)ec_outbuf; @@ -852,22 +928,41 @@ int cmd_pd_device_info(int argc, char *argv[]) return -1; } - p->port = strtol(argv[1], &e, 0); + port = strtol(argv[1], &e, 0); if (e && *e) { fprintf(stderr, "Bad port\n"); return -1; } + r1 = (struct ec_params_usb_pd_discovery_entry *)ec_inbuf; + rv = ec_command(EC_CMD_USB_PD_DISCOVERY, 0, p, sizeof(*p), + ec_inbuf, ec_max_insize); + if (rv < 0) + return rv; + + if (!r1->vid) + printf("Port:%d has no discovered device\n", port); + else { + printf("Port:%d ptype:%d vid:0x%04x pid:0x%04x\n", port, + r1->ptype, r1->vid, r1->pid); + } + + if (enter_gfu_mode(port) != 1) { + fprintf(stderr, "Failed to enter GFU mode\n"); + return -1; + } + + p->port = port; rv = ec_command(EC_CMD_USB_PD_DEV_INFO, 0, p, sizeof(*p), ec_inbuf, ec_max_insize); if (rv < 0) return rv; if (!r0->dev_id) - printf("Port:%d has no valid device\n", p->port); + printf("Port:%d has no valid device\n", port); else { uint8_t *rwp = r0->dev_rw_hash; - printf("Port:%d DevId:%d.%d Hash:", p->port, + printf("Port:%d DevId:%d.%d Hash:", port, HW_DEV_ID_MAJ(r0->dev_id), HW_DEV_ID_MIN(r0->dev_id)); for (i = 0; i < 5; i++) { printf(" 0x%02x%02x%02x%02x", rwp[3], rwp[2], rwp[1], @@ -877,19 +972,6 @@ int cmd_pd_device_info(int argc, char *argv[]) printf(" CurImg:%s\n", image_names[r0->current_image]); } - r1 = (struct ec_params_usb_pd_discovery_entry *)ec_inbuf; - rv = ec_command(EC_CMD_USB_PD_DISCOVERY, 0, p, sizeof(*p), - ec_inbuf, ec_max_insize); - if (rv < 0) - return rv; - - if (!r1->vid) - printf("Port:%d has no discovered device\n", p->port); - else { - printf("Port:%d ptype:%d vid:0x%04x pid:0x%04x\n", p->port, - r1->ptype, r1->vid, r1->pid); - } - return rv; } @@ -897,7 +979,7 @@ int cmd_flash_pd(int argc, char *argv[]) { struct ec_params_usb_pd_fw_update *p = (struct ec_params_usb_pd_fw_update *)ec_outbuf; - int i; + int i, dev_id, port; int rv, fsize, step = 96; char *e; char *buf; @@ -909,18 +991,23 @@ int cmd_flash_pd(int argc, char *argv[]) return -1; } - p->dev_id = strtol(argv[1], &e, 0); + dev_id = strtol(argv[1], &e, 0); if (e && *e) { fprintf(stderr, "Bad device ID\n"); return -1; } - p->port = strtol(argv[2], &e, 0); + port = strtol(argv[2], &e, 0); if (e && *e) { fprintf(stderr, "Bad port\n"); return -1; } + if (enter_gfu_mode(port) != 1) { + fprintf(stderr, "Failed to enter GFU mode\n"); + return -1; + } + /* Read the input file */ buf = read_file(argv[3], &fsize); if (!buf) @@ -928,6 +1015,8 @@ int cmd_flash_pd(int argc, char *argv[]) /* Erase the current RW RSA signature */ fprintf(stderr, "Erasing expected RW hash\n"); + p->dev_id = dev_id; + p->port = port; p->cmd = USB_PD_FW_ERASE_SIG; p->size = 0; rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, @@ -938,6 +1027,8 @@ int cmd_flash_pd(int argc, char *argv[]) /* Reboot */ fprintf(stderr, "Rebooting\n"); + p->dev_id = dev_id; + p->port = port; p->cmd = USB_PD_FW_REBOOT; p->size = 0; rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, @@ -948,8 +1039,16 @@ int cmd_flash_pd(int argc, char *argv[]) usleep(3000000); /* 3sec to reboot and get CC line idle */ + /* re-enter GFU after reboot */ + if (enter_gfu_mode(port) != 1) { + fprintf(stderr, "Failed to enter GFU mode\n"); + goto pd_flash_error; + } + /* Erase RW flash */ fprintf(stderr, "Erasing RW flash\n"); + p->dev_id = dev_id; + p->port = port; p->cmd = USB_PD_FW_FLASH_ERASE; p->size = 0; rv = ec_command(EC_CMD_USB_PD_FW_UPDATE, 0, @@ -963,6 +1062,8 @@ int cmd_flash_pd(int argc, char *argv[]) /* Write RW flash */ fprintf(stderr, "Writing RW flash\n"); + p->dev_id = dev_id; + p->port = port; p->cmd = USB_PD_FW_FLASH_WRITE; p->size = step; |