blob: 4385f4d8f2b53fc7e39fb3960d3a1a83dea900c9 [file] [log] [blame]
# Copyright 2019 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import re
import time
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.faft.cr50_test import Cr50Test
class firmware_Cr50WPG3(Cr50Test):
"""Verify WP in G3."""
version = 1
WAIT_FOR_STATE = 20
CMD_FIND_WP_GPIO = 'ectool gpioget | grep -i wp | grep -vi cbi'
WP_REGEX = r'WP status: ((en|dis)abled)'
STATUS_CMD = '--wp-status --ignore-hw'
WP_ENABLE_CMD = '--wp-enable'
WP_DISABLE_CMD = '--wp-disable'
DISABLED = 'disabled'
ENABLED = 'enabled'
CUSTOM_RST = ',custom_rst=true'
def cleanup(self):
"""Reenable servo wp."""
self.gsc.send_command('ccd testlab open')
try:
# Reset the WP state.
if hasattr(self, '_start_fw_wp_vref'):
self.set_gsc_hw_wp('disable atboot')
self.ccd_set_sw_wp(self.WP_DISABLE_CMD)
self.set_gsc_hw_wp('follow_batt_pres atboot')
self.servo.set_nocheck('fw_wp_state', self._start_fw_wp_state)
if self._start_fw_wp_vref:
self.servo.set_nocheck('fw_wp_vref', self._start_fw_wp_vref)
self.gsc.send_command('rddkeepalive disable')
self.enable_servo_ec_uart()
finally:
super(firmware_Cr50WPG3, self).cleanup()
def generate_futility_wp_cmd(self):
"""Use the cr50 serialname to generate the futility command."""
self._futility_cmd = (
'sudo futility flash -p raiden_debug_spi:target=AP,serial=%s%s '
% (self.gsc.get_serial(),
self.CUSTOM_RST if self._use_custom_rst else ''))
def ccd_get_sw_wp(self):
"""Returns 'on' if write protect is enabled. 'off' if it's disabled."""
output = self.servo.system_output(self._futility_cmd + self.STATUS_CMD)
m = re.search(self.WP_REGEX, output)
logging.info('SW WP is %s', m.group(1) if m else 'UKNOWN')
logging.info('futility output\n%s', output)
if not m:
raise error.TestError(
'Unable to find WP status in futility output')
return m.group(1)
def ccd_set_sw_wp(self, cmd):
"""Set SW WP."""
self.enable_ccd_spi()
time.sleep(self.gsc.SHORT_WAIT)
output = self.servo.system_output(self._futility_cmd + cmd,
ignore_status=True)
logging.debug('SW WP output: %r', output)
time.sleep(self.gsc.SHORT_WAIT)
sw_wp = self.ccd_get_sw_wp()
# Done with ccd spi access. Reenable servo ec uart access.
self.enable_servo_ec_uart()
return sw_wp
def find_ec_wp_gpio_name(self):
"""Find the EC WP gpio name from ectool gpioget."""
self.wp_gpio = None
result = self.host.run(self.CMD_FIND_WP_GPIO).stdout.strip()
logging.info('WP gpio output: %s', result)
if len(result.splitlines()) > 1:
logging.info('Too many wp lines.')
return
self.wp_gpio = result.split()[1]
logging.info('WP GPIO: %s', self.wp_gpio)
def get_ec_hw_wp(self):
"""Check the WP GPIO from the EC console."""
if not self.wp_gpio:
return
for i in range(3):
try:
rv = self.ec.send_command_get_output(
'gpioget %s' % self.wp_gpio,
['gpioget.*([01]).*%s.*>' % self.wp_gpio])[0][1]
logging.info('EC %s: %s', self.wp_gpio, rv)
return
except Exception as e:
logging.info('Issue getting ec wp: %s', e)
def set_ccd_cpu_fw_spi(self, state):
"""Set ccd_cpu_fw_spi if the board uses custom reset."""
if not self._use_custom_rst:
return
logging.info('Setting ccd_cpu_fw_spi %s', state)
logging.info('%s is active', self.servo.get('active_dut_controller'))
self.servo.set_nocheck('ccd_cpu_fw_spi', state)
time.sleep(2)
logging.info('Set ccd_cpu_fw_spi %s', state)
logging.info('%s is active', self.servo.get('active_dut_controller'))
self.gsc.get_ccdstate()
def enable_ccd_spi(self):
"""Enable ccd spi access.
Make GSC ignore servo, so it can enable CCD SPI access.
"""
# There's no need to switch servo control if the main device is ccd.
if self.servo.main_device_is_ccd():
self.set_ccd_cpu_fw_spi('on')
return
self.gsc.send_command('rddkeepalive enable')
# Setup the AP flash access. This could require EC uart access. It
# has to be done before making ccd active.
self.servo.enable_main_servo_device()
self.set_ccd_cpu_fw_spi('on')
# Enable the CCD servo device.
self.servo.enable_ccd_servo_device()
time.sleep(2)
def enable_servo_ec_uart(self):
"""Enable servo control of ec uart."""
# There's no need to switch servo control if the main device is ccd.
if self.servo.main_device_is_ccd():
self.set_ccd_cpu_fw_spi('off')
return
self.servo.set('ec_uart_en', 'on')
self.servo.enable_main_servo_device()
self.set_ccd_cpu_fw_spi('off')
time.sleep(2)
self.gsc.get_ccdstate()
def check_state_from_consoles(self):
"""Log device state from EC and GSC consoles."""
self.gsc.get_ccdstate()
logging.info('EC Power State: %s', self.get_power_state())
self.get_ec_hw_wp()
self.gsc.get_wp_state()
def set_gsc_hw_wp(self, state):
"""Open GSC. Set GSC wp."""
logging.info('Set GSC WP: %s', state)
self.gsc.set_wp_state(state)
def run_once(self):
"""Verify WP in G3."""
self._use_custom_rst = self.servo.has_control('ccd_cpu_fw_spi')
if not self.servo.get_ccd_servo_device():
raise error.TestNAError('Only supported with dual-v4')
if not self.check_ec_capability(suppress_warning=True):
raise error.TestNAError('Only supported on boards with ECs')
if self.check_cr50_capability(['wp_on_in_g3'], suppress_warning=True):
raise error.TestNAError('config: WP not pulled up in G3')
try:
self.gsc.ccd_enable(True)
except:
raise error.TestNAError('CCD required to check wp.')
self.find_ec_wp_gpio_name()
self.generate_futility_wp_cmd()
self.fast_ccd_open(enable_testlab=True)
self.gsc.send_command('ccd set OverrideWP Always')
self.gsc.send_command('ccd set FlashAP Always')
if self.servo.has_control('cold_reset_select'):
self.servo.set_nocheck('cold_reset_select', 'gsc_ec_reset')
if self.servo.main_device_is_flex():
self._start_fw_wp_state = self.servo.get('fw_wp_state')
# If nothing is forcing write protect, then the initial state is
# "reset".
if "force" not in self._start_fw_wp_state:
self._start_fw_wp_state = "reset"
self._start_fw_wp_vref = (self.servo.get('fw_wp_vref') if
self.servo.has_control('fw_wp_vref') else None)
# Stop forcing wp using servo, so we can set it with ccd.
self.servo.set_nocheck('fw_wp_state', 'reset')
if self._start_fw_wp_vref:
self.servo.set_nocheck('fw_wp_vref', 'off')
# Disable HW WP.
self.set_gsc_hw_wp('disable atboot')
# Disable SW WP.
wp_state = self.ccd_set_sw_wp(self.WP_DISABLE_CMD)
# Bring the DUT up since futility commands put the EC in reset.
self._try_to_bring_dut_up()
if wp_state != self.DISABLED:
raise error.TestFail('Unable to disable SW WP with HW WP enabled')
# Verify we can see it's disabled. This should always work. If it
# doesn't, it may be a setup issue.
logging.info('Checking WP from DUT')
self.check_state_from_consoles()
if not self.checkers.crossystem_checker({'wpsw_cur': '0'}):
raise error.TestError("HW WP isn't disabled in S0")
# Enable HW WP.
self.set_gsc_hw_wp('enable atboot')
self.check_state_from_consoles()
if not self.checkers.crossystem_checker({'wpsw_cur': '1'}):
raise error.TestError("HW WP isn't enabled in S0")
self.faft_client.system.run_shell_command('poweroff')
time.sleep(self.WAIT_FOR_STATE)
self.check_state_from_consoles()
# SW WP can be enabled at any time.
logging.info('Check enabling SW WP with HW WP enabled')
if self.ccd_set_sw_wp(self.WP_ENABLE_CMD) != self.ENABLED:
self.gsc.reboot()
self._try_to_bring_dut_up()
raise error.TestFail('Unable to enable SW WP in G3')
# It shouldn't be possible to disable SW WP with HW WP enabled.
logging.info('Check disabling SW WP with HW WP enabled')
self.check_state_from_consoles()
if self.ccd_set_sw_wp(self.WP_DISABLE_CMD) == self.DISABLED:
self.gsc.reboot()
self._try_to_bring_dut_up()
raise error.TestFail('Disabled SW WP with HW WP enabled')
# It should be possible to disable SW WP after HW WP is disabled.
logging.info('Check disabling SW WP with HW WP disabled')
# Disable HW WP.
self.set_gsc_hw_wp('disable atboot')
self.check_state_from_consoles()
# Verify setting SW WP.
if self.ccd_set_sw_wp(self.WP_DISABLE_CMD) != self.DISABLED:
self.gsc.reboot()
self._try_to_bring_dut_up()
raise error.TestFail('Disabled SW WP with HW WP enabled')
self._try_to_bring_dut_up()