servo: Use ec reboot wait-ext for power_state:rec

EC_IN_RW signal is used to determine if the switch to dev mode can be
safely made. However, EC_IN_RW needs the EC_RST_L line driven low in
order to be reset. In faft tests that utilize crosEcSoftrecPower
method, EC_RST_L is not being driven by servo to fix other test
failures related to keeping EC and AC reboots in sync.

This CL modifies crosEcSoftrecPower to use the wait-ext option when
initializing an EC reset to to enter recovery mode. If the wait-ext
option fails, then the command 'reboot ap-off' will be issued.

BUG=b:64603944
BRANCH=coral
CQ-DEPEND=I614f9156066d5719601ee43e29c7a064f9bba6e2
TEST=Ran "/usr/bin/test_that --board=coral <ip addr> firmware_DevMode"
mutliple times and verified that it passes. Previoulsy, this test
always fails when the EC is in RW before it starts. Also verified
platform_ServoPowerStateController_USBPluggedin passed.

Change-Id: I086687c3dd7591460099267880d56ab8265d2e4b
Signed-off-by: Scott Collyer <scollyer@google.com>
Reviewed-on: https://chromium-review.googlesource.com/738634
Commit-Ready: Scott Collyer <scollyer@chromium.org>
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
diff --git a/servo/drv/cros_ec_softrec_power.py b/servo/drv/cros_ec_softrec_power.py
index d2038d3..b357096 100644
--- a/servo/drv/cros_ec_softrec_power.py
+++ b/servo/drv/cros_ec_softrec_power.py
@@ -55,14 +55,30 @@
     self._interface.set('ec_uart_cmd', '\r')
     if rec_mode == self.REC_ON:
       try:
+        # Hold warm reset so the AP doesn't boot when EC reboots.
+        # Note that this only seems to work reliably for ARM devices.
+        self._interface.set('warm_reset', 'on')
         # Before proceeding, we should really check that the EC has reset from
         # our command.  Pexpect is minimally greedy so we won't be able to match
         # the exact reset cause string.  But, this should be good enough.
-        self._interface.set('ec_uart_regexp', '["Reset cause:"]')
+        self._interface.set('ec_uart_regexp', '["Waiting"]')
+        self._interface.set('ec_uart_cmd', 'reboot wait-ext ap-off')
+        # Reset the EC to force it back into RO code; this clears
+        # the EC_IN_RW signal, so the system CPU will trust the
+        # upcoming recovery mode request.
+        self._cold_reset()
+      except:
+        # If the EC doesn't support wait-ext, then resend reboot with only the
+        # ap-off argument. This will still prevent a race condition between the
+        # EC and AP when rebooting. However, the reboot will be triggered
+        # internally by the EC watchdog, and there is no external reset signal.
+        self._interface.set('ec_uart_regexp', '["Rebooting!"]')
         self._interface.set('ec_uart_cmd', 'reboot ap-off')
       finally:
         self._interface.set('ec_uart_regexp', 'None')
       time.sleep(self._reset_recovery_time)
+      # Release warm reset
+      self._interface.set('warm_reset', 'off')
     else:
       # Need to clear the flag in secondary (B) copy of the host events if
       # we're in non-recovery mode.