futility: updater: Add '--servo' for updating via Servo-V2 and ServoMicro

Flashing via Servo V2 and Servo Micro was known to be a complicated.
With the new virtual control 'cpu_fw_spi' we have a better way to
prepare servo in an unified way.

The new '--servo' will detect servo type and pick up the right params
(for servo v2, servo micro, servo v4 with ccd, or servo v4 + micro)
for programming.

BRANCH=None
BUG=None
TEST=make runtest; sudo futility update --servo -i image.bin

Cq-Depend: chromium:1966176
Change-Id: Ia14288b1bd5f24acfc4fb85ba64c2c445152a3a7
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1966872
Reviewed-by: Joel Kitching <kitching@chromium.org>
Reviewed-by: Wai-Hong Tam <waihong@google.com>
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index fef24c6..70e699a 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -29,6 +29,7 @@
 	OPT_QUIRKS,
 	OPT_QUIRKS_LIST,
 	OPT_REPACK,
+	OPT_SERVO,
 	OPT_SIGNATURE,
 	OPT_SYS_PROPS,
 	OPT_UNPACK,
@@ -50,6 +51,7 @@
 	{"mode", 1, NULL, 'm'},
 
 	{"ccd", 0, NULL, OPT_CCD},
+	{"servo", 0, NULL, OPT_SERVO},
 	{"emulate", 1, NULL, OPT_EMULATE},
 	{"factory", 0, NULL, OPT_FACTORY},
 	{"fast", 0, NULL, OPT_FAST},
@@ -111,6 +113,7 @@
 		"    --emulate=FILE  \tEmulate system firmware using file\n"
 		"    --model=MODEL   \tOverride system model for images\n"
 		"    --ccd           \tDo fast,force,wp=0,p=raiden_debug_spi\n"
+		"    --servo         \tFlash using Servo (v2, v4, micro, ...)\n"
 		"    --signature_id=S\tOverride signature ID for key files\n"
 		"    --sys_props=LIST\tList of system properties to override\n"
 		"-d, --debug         \tPrint debugging messages\n"
@@ -124,6 +127,7 @@
 	struct updater_config *cfg;
 	struct updater_config_arguments args = {0};
 	int i, errorcnt = 0, do_update = 1;
+	int detect_servo = 0, do_servo_cpu_fw_spi = 0;
 
 	cfg = updater_new_config();
 	assert(cfg);
@@ -216,6 +220,13 @@
 			args.write_protection = "0";
 			args.programmer = "raiden_debug_spi:target=AP";
 			break;
+		case OPT_SERVO:
+			args.fast_update = 1;
+			args.force_update = 1;
+			args.write_protection = "0";
+			args.host_only = 1;
+			detect_servo = 1;
+			break;
 
 		case OPT_DUMMY:
 			break;
@@ -239,6 +250,18 @@
 		errorcnt++;
 		ERROR("Unexpected arguments.\n");
 	}
+
+	if (!errorcnt && detect_servo)
+		errorcnt += host_detect_servo(&args.programmer,
+					      &do_servo_cpu_fw_spi);
+	/*
+	 * Some boards may need to fetch firmware before starting to
+	 * update (i.e., in updater_setup_config) so we want to turn on
+	 * cpu_fw_spi mode now.
+	 */
+	if (do_servo_cpu_fw_spi)
+		free(host_shell("dut-control cpu_fw_spi:on"));
+
 	if (!errorcnt)
 		errorcnt += updater_setup_config(cfg, &args, &do_update);
 	if (!errorcnt && do_update) {
@@ -256,6 +279,9 @@
 			errorcnt ? "aborted" : "exits successfully");
 	}
 
+	if (do_servo_cpu_fw_spi)
+		free(host_shell("dut-control cpu_fw_spi:off"));
+
 	updater_delete_config(cfg);
 	return !!errorcnt;
 }
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 3807fbb..4a91a05 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -436,6 +436,42 @@
 }
 
 /*
+ * Helper function to detect type of Servo board attached to host,
+ * and store the right programmer / prepare settings to arguments.
+ * Returns 0 if success, non-zero if error.
+ */
+int host_detect_servo(const char **programmer_ptr, int *need_prepare_ptr)
+{
+	int ret = 0;
+	char *servo_type = host_shell("dut-control -o servo_type 2>/dev/null");
+	const char *programmer = NULL;
+	int need_prepare = 0;  /* To prepare by dut-control cpu_fw_spi:on */
+
+	if (!*servo_type) {
+		ERROR("Failed to get servo type. Check servod.\n");
+		ret = 1;
+	} else if (strstr(servo_type, "servo_micro")) {
+		VB2_DEBUG("Selected Servo Micro.\n");
+		programmer = "raiden_debug_spi";
+		need_prepare = 1;
+	} else if (strstr(servo_type, "ccd_cr50")) {
+		VB2_DEBUG("Selected CCD CR50.\n");
+		programmer = "raiden_debug_spi:target=AP";
+	} else {
+		VB2_DEBUG("Selected Servo V2.\n");
+		programmer = "ft2232_spi:type=servo-v2";
+		need_prepare = 1;
+	}
+
+	free(servo_type);
+	if (programmer && !*programmer_ptr)
+		*programmer_ptr = programmer;
+	*need_prepare_ptr = need_prepare;
+
+	return ret;
+}
+
+/*
  * A helper function to invoke flashrom(8) command.
  * Returns 0 if success, non-zero if error.
  */
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index f5248f8..5e6e99c 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -171,6 +171,13 @@
 enum wp_state host_get_wp(const char *programmer);
 
 /*
+ * Helper function to detect type of Servo board attached to host,
+ * and store the right programmer / prepare settings to arguments.
+ * Returns 0 if success, non-zero if error.
+ */
+int host_detect_servo(const char **programmer_ptr, int *need_prepare_ptr);
+
+/*
  * Returns 1 if a given file (cbfs_entry_name) exists inside a particular CBFS
  * section of an image file, otherwise 0.
  */