Modify cros_write_firmware to control servo when programming Tegra targets
When flashing a Tegra based DUT, cros_write_firmware does not set the
target into a proper state, expecting the operator to run dut-control
to set the target into a programming state and then to take it back to
normal.
Modify the utility to have it issue the required dit-control commands
(the way Exynos flasher does). Also correct the doc string and in case
the servo is used suppress the request to connect the A-A cable and
restart the DUT.
Refactor the code which preserves the dut_hub_sel control state
BUG=none
TEST=manual
. disconnect the DUT console port on the host and run the following commands
$ emerge-nyan chromeos-bootimage
$ emerge-peach_pit chromeos-bootimage
$ cros_write_firmware -b nyan -d /build/nyan/firmware/dtb/tegra124-venice2.dtb \
-i /build/nyan/firmware/nv_image-venice2.bin -F spi:1
$ cros_write_firmware -b peach_pit \
-d /build/peach_pit/firmware/dtb/exynos5420-peach-pit.dtb \
-i /build/peach_pit/firmware/image-peach-pit.bin -F spi
. observe both cros_write_firmware invocations succeed
. repeat the above firmware write attempts with dut_hub_sel set to
'dut_sees_servo' and 'dut_sees_hub'. Observe that the control
state is preserved over the programming session.
Cannot find /iram, using default
Missing properties in /config, using defaults
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Change-Id: Iabc5a4e6789a4ff02c5978c3e7b5e0798e87205f
Reviewed-on: https://chromium-review.googlesource.com/175505
Tested-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Vadim Bendebury <vbendeb@chromium.org>
diff --git a/host/lib/write_firmware.py b/host/lib/write_firmware.py
index d4197e2..0158c51 100644
--- a/host/lib/write_firmware.py
+++ b/host/lib/write_firmware.py
@@ -26,7 +26,7 @@
class WriteFirmware:
- """Write firmware to a Tegra 2 board using USB A-A cable.
+ """Write firmware to a Chrome OS device using USB A-A cable or servo board
This class handles re-reflashing a board with new firmware using the Tegra's
built-in boot ROM feature. This works by putting the chip into a special mode
@@ -44,6 +44,8 @@
None: servo is not available.
0: any servo will do.
+ _preserved_dut_hub_sel: a string, preserved state of the dut_hub_sel
+ control
"""
_DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
@@ -67,6 +69,7 @@
self._out = output
self._bundle = bundle
self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
+ self._preserved_dut_hub_sel = ''
# For speed, use the 'update' algorithm and don't verify
self.update = update
@@ -78,6 +81,55 @@
# By default, no early firmware selection.
self.use_efs = False
+ def EnableUsbProgramming(self, args):
+ """Save dut_hub_sel control if necessary, and set it for programming
+
+ For successful A-A USB programming the dut_hub_sel control must be set to
+ 'dut_sees_servo'. This function preserves the state of this control, if it
+ is set to anything else, and then sets it as required. After that the
+ function passes its args to dut-control, which is supposed to restart the
+ DUT in USB booting mode.
+
+ Args:
+ args - a list of strings in <control>:<value> format to be passed to
+ servo to restart the DUT in USB booting mode.
+ """
+
+ if self._servo_port is None:
+ return
+
+ # Preserve and configure dut_hub_sel state.
+ self._out.Progress('Reseting board via servo')
+
+ required_dut_hub_sel = 'dut_sees_servo'
+ preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
+ ).strip().split(':')[-1]
+ if required_dut_hub_sel != preserved_dut_hub_sel:
+ args += ['dut_hub_sel:%s' % required_dut_hub_sel,]
+ self._preserved_dut_hub_sel = preserved_dut_hub_sel
+
+ self.DutControl(args)
+
+ def DisableUsbProgramming(self, args):
+ """Save dut_hub_sel control if necessary, and set it for programming
+
+ Restore dut_hub_sel control setting if it was changed, and take the DUT
+ out of USB booting mode.
+
+ Args:
+ args - a list of strings in <control>:<value> format to be passed to
+ servo to take the DUT out of USB booting mode.
+ """
+
+ if self._servo_port is None:
+ return
+
+ if self._preserved_dut_hub_sel:
+ args += ['dut_hub_sel:%s' % self._preserved_dut_hub_sel,]
+ self._preserved_dut_hub_sel = ''
+
+ self.DutControl(args)
+
def SelectServo(self, servo):
"""Select the servo to use for writing firmware.
@@ -397,31 +449,47 @@
# TODO(sjg): Check for existence of board - but chroot has no lsusb!
last_err = None
- for _ in range(10):
- try:
- # TODO(sjg): Use Chromite library so we can monitor output
- self._tools.Run('tegrarcm', args, sudo=True)
- self._out.Notice('Flasher downloaded - please see serial output '
- 'for progress.')
- return True
- except CmdError as err:
- if not self._out.stdout_is_tty:
- return False
+ try:
+ # Set DUT into programmable state
+ self.EnableUsbProgramming(['t20_rec:on',
+ 'warm_reset:on',
+ 'sleep:.1',
+ 'warm_reset:off',
+ 'sleep:.5'])
+ for _ in range(10):
+ try:
+ # TODO(sjg): Use Chromite library so we can monitor output
+ self._tools.Run('tegrarcm', args, sudo=True)
+ self._out.Notice('Flasher downloaded - please see serial output '
+ 'for progress.')
+ return True
- # Only show the error output once unless it changes.
- err = str(err)
- if not 'could not open USB device' in err:
- raise CmdError('tegrarcm failed: %s' % err)
+ except CmdError as err:
+ if not self._out.stdout_is_tty:
+ return False
- if err != last_err:
- self._out.Notice(err)
- last_err = err
- self._out.Progress('Please connect USB A-A cable and do a '
- 'recovery-reset', True)
- time.sleep(1)
+ # Only show the error output once unless it changes.
+ err = str(err)
+ if not 'could not open USB device' in err:
+ raise CmdError('tegrarcm failed: %s' % err)
- return False
+ if err != last_err:
+ self._out.Notice(err)
+ last_err = err
+ if self._servo_port is None:
+ self._out.Progress('Please connect USB A-A cable and do a '
+ 'recovery-reset', True)
+ time.sleep(1)
+
+ return False
+
+ finally:
+ # Restore servo state
+ self.DisableUsbProgramming(['t20_rec:off',
+ 'spi2_buf_en:off',
+ 'spi2_buf_on_flex_en:off',
+ 'spi2_vref:off'])
def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
"""Wait until we see a device on the USB bus.
@@ -661,18 +729,11 @@
vendor_id = 0x04e8
product_id = 0x1234
- # Preserve dut_hub_sel state.
- preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
- ).strip().split(':')[-1]
- required_dut_hub_sel = 'dut_sees_servo'
- args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
- 'warm_reset:off']
- if preserved_dut_hub_sel != required_dut_hub_sel:
- # Need to set it to get the port properly powered up.
- args += ['dut_hub_sel:%s' % required_dut_hub_sel]
- if self._servo_port is not None:
- self._out.Progress('Reseting board via servo')
- self.DutControl(args)
+ self.EnableUsbProgramming(['warm_reset:on',
+ 'fw_up:on',
+ 'pwr_button:press',
+ 'sleep:.2',
+ 'warm_reset:off'])
# If we have a kernel to write, create a new image with that added.
if kernel:
@@ -740,10 +801,7 @@
finally:
# Make sure that the power button is released and dut_sel_hub state is
# restored, whatever happens
- args = ['fw_up:off', 'pwr_button:release']
- if preserved_dut_hub_sel != required_dut_hub_sel:
- args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
- self.DutControl(args)
+ self.DisableUsbProgramming(['fw_up:off', 'pwr_button:release'])
if flash_dest is None:
self._out.Notice('Image downloaded - please see serial output '