# Copyright 2019 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import time from autotest_lib.client.common_lib import error from autotest_lib.server.cros.faft.cr50_test import Cr50Test from autotest_lib.server.cros.servo import servo class firmware_Cr50DeferredECReset(Cr50Test): """Verify EC_RST_L stays asserted only if all conditions below are True. (1) System got 'Power-On reset'. (2) RDD cable is connected. (3) The power button is held. After this, EC_RST_L should be deasserted as soon as the power button gets released. Attributes version: test version number CUTOFF_DELAY: duration in second to keep cr50 powered off, PD_SETTLE_TIME: duration in second to wait PD to be stable HAS_CR50_RESET_ODL: boolean if 'cr50_reset_odl' control is available """ version = 1 CUTOFF_DELAY = 10 PD_SETTLE_TIME = 3 HAS_CR50_RESET_ODL = False def cr50_power_on_reset(self): """Perform a power-on-reset on cr50. If cr50_reset_odl control is available, then use it. Otherwise, disconnect and reconnect battery and power source. """ if self.HAS_CR50_RESET_ODL: self.servo.set('cr50_reset_odl', 'on') time.sleep(self.CUTOFF_DELAY) self.servo.set('cr50_reset_odl', 'off') else: # Stop power delivery to dut logging.info('Stop charging') self.servo.set('servo_v4_role', 'snk') # Battery Cutoff logging.info('Cut battery off') self.ec.send_command('cutoff') time.sleep(self.CUTOFF_DELAY) # Enable power delivery to dut logging.info('Start charging') self.servo.set('servo_v4_role', 'src') time.sleep(self.PD_SETTLE_TIME) def ac_is_plugged_in(self): """Check if AC is plugged. Returns: True if AC is plugged, or False otherwise. """ rv = self.ec.send_command_get_output('chgstate', [r'ac\s*=\s*(0|1)\s*'])[0][1] return rv == '1' def initialize(self, host, cmdline_args, full_args): """Initialize the test and check if cr50 exists, DTS is controllable, and power delivery mode and power button is adjustable. Raises: TestFail: If test initialization setup fails. TestNAError: If the dut is not proper for this test for its RDD recognition problem. """ super(firmware_Cr50DeferredECReset, self).initialize(host, cmdline_args, full_args) if not hasattr(self, 'cr50'): raise error.TestNAError('Test can only be run on devices with ' 'access to the Cr50 console') if not self.cr50.servo_dts_mode_is_valid(): raise error.TestNAError('Need working servo v4 DTS control') self.dts_restore = self.servo.get_dts_mode() # Fast open cr50 and check if testlab is enabled. self.fast_ccd_open(enable_testlab=True) if not self.cr50.testlab_is_on(): raise error.TestNAError('Cr50 testlab mode is not enabled') # Check 'rdd_leakage' is marked in cr50 capability. if self.check_cr50_capability(['rdd_leakage']): self.rdd_leakage = True logging.warn('RDD leakage is marked in cr50 cap config') else: self.rdd_leakage = False # Test if the power button is adjustable. self.servo.set('pwr_button', 'press') self.servo.set('pwr_button', 'release') # Check if 'cr50_reset_odl' controlis available. try: self.servo.get('cr50_reset_odl') self.HAS_CR50_RESET_ODL = True except error.TestFail: self.HAS_CR50_RESET_ODL = False # Test the external power delivery self.servo.set('servo_v4_role', 'snk') time.sleep(self.PD_SETTLE_TIME) if self.ac_is_plugged_in(): raise error.TestFail('Failed to set servo_v4_role sink') # Test stopping the external power delivery self.servo.set('servo_v4_role', 'src') time.sleep(self.PD_SETTLE_TIME) if not self.ac_is_plugged_in(): raise error.TestFail('Failed to set servo_v4_role source') # Check if the dut has any RDD recognition issue. # First, cut off power source and hold the power button. # disable RDD connection. self.servo.set_dts_mode('off') self.servo.set('pwr_button', 'press') self.cr50_power_on_reset() try: # Third, check if the rdd status is disconnected. # If not, terminate the test. ccdstate = self.cr50.get_ccdstate() if (ccdstate['Rdd'].lower() != 'disconnected') != self.rdd_leakage: raise error.TestError('RDD leakage does not match capability' ' configuration.') finally: self.servo.set_dts_mode(self.dts_restore) self.servo.set_nocheck('pwr_button', 'release') time.sleep(self.PD_SETTLE_TIME) self.servo.power_short_press() # Wake up AP logging.info('Initialization is done') def check_ecrst_asserted(self, expect_assert): """Ask CR50 whether EC_RST_L is asserted or deasserted. Args: expect_assert: True if it is expected asserted. False otherwise. Raises: TestFail: if ecrst value is not as expected. """ # If the console is responsive, then the EC is awake. expected_txt = 'asserted' if expect_assert else 'deasserted' logging.info('Checking if ecrst is %s', expected_txt) try: rv = self.cr50.send_command_get_output('ecrst', [r'EC_RST_L is (%s)' % expected_txt]) logging.info(rv) except error.TestError as e: raise error.TestFail(str(e)) def ping_ec(self, expect_response): """Check if EC is running and responding. Args: expect_response: True if EC should respond False otherwise. Raises: TestFail: if ec responsiveness is not as same as expected. """ try: logging.info('Checking if ec is %sresponsive', '' if expect_response else 'not ') rv = self.ec.send_command_get_output('help', ['.*>'])[0].strip() except servo.UnresponsiveConsoleError as e: logging.info(str(e)) return else: if not expect_response: logging.error('EC should not respond') raise error.TestFail(rv) def test_deferred_ec_reset(self, power_button_hold, rdd_enable): """Do a power-on reset, and check if EC responds. Args: power_button_hold: True if it should be pressed on a system reset. False otherwise. rdd_enable: True if RDD should be detected on a system reset. False otherwise. """ # If the board has a rdd leakage issue, RDD shall be detected # always in G3. EC_RST will be asserted if the power_button is # being presed in this test. expect_ec_response = not (power_button_hold and (rdd_enable or self.rdd_leakage)) logging.info('Test deferred_ec_reset starts') logging.info('Power button held : %s', power_button_hold) logging.info('RDD connection : %s', rdd_enable) logging.info('RDD leakage : %s', self.rdd_leakage) logging.info('Expected EC response : %s', expect_ec_response) try: # enable RDD Connection (or disable) before power-on-reset self.servo.set_dts_mode('on' if rdd_enable else 'off') # Set power button before the dut loses power, # because the power button value cannot be changed during power-off. self.servo.set('pwr_button', 'press' if power_button_hold else 'release') # Do a power-on-reset on CR50. self.cr50_power_on_reset() # Wait for a while wait_sec = 30 logging.info('waiting for %d seconds', wait_sec) time.sleep(wait_sec) # Check if EC_RST_L is asserted and EC is on. # (or EC_RST_L deasserted and EC off) self.check_ecrst_asserted(not expect_ec_response) self.ping_ec(expect_ec_response) # Release power button logging.info('Power button released') self.servo.set('pwr_button', 'release') time.sleep(self.PD_SETTLE_TIME) # Check if EC_RST_L is deasserted and EC is on. self.check_ecrst_asserted(False) self.ping_ec(True) finally: if self.HAS_CR50_RESET_ODL: self.servo.set_nocheck('cr50_reset_odl', 'off') else: self.servo.set_nocheck('servo_v4_role', 'src') self.servo.set_dts_mode(self.dts_restore) time.sleep(1) # Press power button to wake up AP, and releases it soon # in any cases. self.servo.power_short_press() def run_once(self): """Test deferred EC reset feature. """ # Release power button and disable RDD on power-on reset. # EC should be running. self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=False) # Release power button but enable RDD on power-on reset. # EC should be running. self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=True) # Hold power button but disable RDD on power-on reset. # EC should be running. self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=False) # Hold power button and enable RDD on power-on reset. # EC should not be running. self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=True) logging.info('Test is done')