1# Copyright 2019 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.server.cros.faft.cr50_test import Cr50Test 10from autotest_lib.server.cros.servo import servo 11 12 13class firmware_Cr50DeferredECReset(Cr50Test): 14 """Verify EC_RST_L stays asserted only if all conditions below are True. 15 (1) System got 'Power-On reset'. 16 (2) RDD cable is connected. 17 (3) The power button is held. 18 19 After this, EC_RST_L should be deasserted as soon as the power button 20 gets released. 21 22 Attributes 23 version: test version number 24 CUTOFF_DELAY: duration in second to keep cr50 powered off, 25 PD_SETTLE_TIME: duration in second to wait PD to be stable 26 HAS_CR50_RESET_ODL: boolean if 'cr50_reset_odl' control is available 27 """ 28 version = 1 29 CUTOFF_DELAY = 10 30 PD_SETTLE_TIME = 3 31 WAIT_DUT_UP = 5 32 HAS_CR50_RESET_ODL = False 33 34 def cr50_power_on_reset(self): 35 """Perform a power-on-reset on cr50. 36 If cr50_reset_odl control is available, then use it. 37 Otherwise, disconnect and reconnect battery and power source. 38 """ 39 if self.HAS_CR50_RESET_ODL: 40 self.servo.set('cr50_reset_odl', 'on') 41 42 time.sleep(self.CUTOFF_DELAY) 43 44 self.servo.set('cr50_reset_odl', 'off') 45 else: 46 # Stop power delivery to dut 47 logging.info('Stop charging') 48 self.servo.set('servo_pd_role', 'snk') 49 50 # Battery Cutoff 51 logging.info('Cut battery off') 52 self.ec.send_command('cutoff') 53 54 time.sleep(self.CUTOFF_DELAY) 55 56 # Enable power delivery to dut 57 logging.info('Start charging') 58 self.servo.set('servo_pd_role', 'src') 59 60 time.sleep(self.PD_SETTLE_TIME) 61 62 def ac_is_plugged_in(self): 63 """Check if AC is plugged. 64 65 Returns: 66 True if AC is plugged, or False otherwise. 67 """ 68 69 rv = self.ec.send_command_get_output('chgstate', 70 [r'ac\s*=\s*(0|1)\s*'])[0][1] 71 return rv == '1' 72 73 def cleanup(self): 74 """Restore dts mode.""" 75 try: 76 if hasattr(self, 'HAS_CR50_RESET_ODL'): 77 self.restore_dut(self.HAS_CR50_RESET_ODL) 78 self.servo.set_dts_mode(self.dts_restore) 79 finally: 80 super(firmware_Cr50DeferredECReset, self).cleanup() 81 82 def initialize(self, host, cmdline_args, full_args): 83 """Initialize the test and check if cr50 exists, DTS is controllable, 84 and power delivery mode and power button is adjustable. 85 86 Raises: 87 TestFail: If test initialization setup fails. 88 TestNAError: If the dut is not proper for this test for its RDD 89 recognition problem. 90 """ 91 super(firmware_Cr50DeferredECReset, self).initialize(host, cmdline_args, 92 full_args) 93 if not hasattr(self, 'cr50'): 94 raise error.TestNAError('Test can only be run on devices with ' 95 'access to the Cr50 console') 96 if not self.cr50.servo_dts_mode_is_valid(): 97 raise error.TestNAError('Need working servo v4 DTS control') 98 self.dts_restore = self.servo.get_dts_mode() 99 100 # Fast open cr50 and check if testlab is enabled. 101 self.fast_ccd_open(enable_testlab=True) 102 if not self.cr50.testlab_is_on(): 103 raise error.TestNAError('Cr50 testlab mode is not enabled') 104 105 # Check 'rdd_leakage' is marked in cr50 capability. 106 if self.check_cr50_capability(['rdd_leakage']): 107 self.rdd_leakage = True 108 logging.warning('RDD leakage is marked in cr50 cap config') 109 else: 110 self.rdd_leakage = False 111 112 # Test if the power button is adjustable. 113 self.servo.set('pwr_button', 'press') 114 self.servo.set('pwr_button', 'release') 115 116 # Check if 'cr50_reset_odl' controlis available. 117 try: 118 self.servo.get('cr50_reset_odl') 119 self.HAS_CR50_RESET_ODL = True 120 except error.TestFail: 121 self.HAS_CR50_RESET_ODL = False 122 123 # Test the external power delivery 124 self.servo.set('servo_pd_role', 'snk') 125 time.sleep(self.PD_SETTLE_TIME) 126 127 if self.ac_is_plugged_in(): 128 raise error.TestFail('Failed to set servo_v4_role sink') 129 130 # Test stopping the external power delivery 131 self.servo.set('servo_pd_role', 'src') 132 time.sleep(self.PD_SETTLE_TIME) 133 134 if not self.ac_is_plugged_in(): 135 raise error.TestFail('Failed to set servo_v4_role source') 136 137 # Check if the dut has any RDD recognition issue. 138 # First, cut off power source and hold the power button. 139 # disable RDD connection. 140 self.servo.set_dts_mode('off') 141 self.servo.set('pwr_button', 'press') 142 self.cr50_power_on_reset() 143 try: 144 # Third, check if the rdd status is disconnected. 145 # If not, terminate the test. 146 ccdstate = self.cr50.get_ccdstate() 147 148 if (ccdstate['Rdd'].lower() != 'disconnected') != self.rdd_leakage: 149 raise error.TestError('RDD leakage does not match capability' 150 ' configuration.') 151 finally: 152 self.restore_dut(False) 153 154 logging.info('Initialization is done') 155 156 def restore_dut(self, use_cr50_reset): 157 """Restore the dut state.""" 158 logging.info('Restore the dut') 159 self.servo.set('pwr_button', 'release') 160 161 if use_cr50_reset: 162 self.servo.set_nocheck('cr50_reset_odl', 'off') 163 else: 164 time.sleep(self.PD_SETTLE_TIME) 165 self.servo.set_nocheck('servo_pd_role', 'snk') 166 time.sleep(self.PD_SETTLE_TIME) 167 self.servo.set_nocheck('servo_pd_role', 'src') 168 169 # Give the EC some time to come up before resetting cr50. 170 time.sleep(self.WAIT_DUT_UP) 171 172 # Reboot cr50 to ensure EC_RST_L is deasserted. 173 self.fast_ccd_open(enable_testlab=True) 174 self.cr50.reboot() 175 176 time.sleep(self.WAIT_DUT_UP) 177 178 # Press power button to wake up AP, and releases it soon 179 # in any cases. 180 if not self.cr50.ap_is_on(): 181 self.servo.power_short_press() 182 logging.info('Restoration done') 183 184 def check_ecrst_asserted(self, expect_assert): 185 """Ask CR50 whether EC_RST_L is asserted or deasserted. 186 187 Args: 188 expect_assert: True if it is expected asserted. 189 False otherwise. 190 191 Raises: 192 TestFail: if ecrst value is not as expected. 193 """ 194 195 # If the console is responsive, then the EC is awake. 196 expected_txt = 'asserted' if expect_assert else 'deasserted' 197 logging.info('Checking if ecrst is %s', expected_txt) 198 199 try: 200 rv = self.cr50.send_command_retry_get_output( 201 'ecrst', [r'EC_RST_L is ((de)?asserted)'], safe=True) 202 logging.info(rv) 203 except error.TestError as e: 204 raise error.TestFail(str(e)) 205 actual_txt = rv[0][1] 206 logging.info('ecrst is %s', actual_txt) 207 if actual_txt != expected_txt: 208 raise error.TestFail('EC_RST_L mismatch: expected %r got %r' % 209 (expected_txt, actual_txt)) 210 211 def ping_ec(self, expect_response): 212 """Check if EC is running and responding. 213 214 Args: 215 expect_response: True if EC should respond 216 False otherwise. 217 Raises: 218 TestFail: if ec responsiveness is not as same as expected. 219 """ 220 try: 221 logging.info('Checking if ec is %sresponsive', 222 '' if expect_response else 'not ') 223 rv = self.ec.send_command_get_output('help', ['.*>'])[0].strip() 224 except servo.UnresponsiveConsoleError as e: 225 logging.info(str(e)) 226 return 227 else: 228 if not expect_response: 229 logging.error('EC should not respond') 230 raise error.TestFail(rv) 231 232 def test_deferred_ec_reset(self, power_button_hold, rdd_enable): 233 """Do a power-on reset, and check if EC responds. 234 235 Args: 236 power_button_hold: True if it should be pressed on a system reset. 237 False otherwise. 238 rdd_enable: True if RDD should be detected on a system reset. 239 False otherwise. 240 """ 241 242 # If the board has a rdd leakage issue, RDD shall be detected 243 # always in G3. EC_RST will be asserted if the power_button is 244 # being presed in this test. 245 expect_ec_response = not (power_button_hold and 246 (rdd_enable or self.rdd_leakage)) 247 logging.info('Test deferred_ec_reset starts') 248 logging.info('Power button held : %s', power_button_hold) 249 logging.info('RDD connection : %s', rdd_enable) 250 logging.info('RDD leakage : %s', self.rdd_leakage) 251 logging.info('Expected EC response : %s', expect_ec_response) 252 253 try: 254 # enable RDD Connection (or disable) before power-on-reset 255 self.servo.set_dts_mode('on' if rdd_enable else 'off') 256 257 # Set power button before the dut loses power, 258 # because the power button value cannot be changed during power-off. 259 self.servo.set('pwr_button', 260 'press' if power_button_hold else 'release') 261 262 # Do a power-on-reset on CR50. 263 self.cr50_power_on_reset() 264 265 # Wait for a while 266 wait_sec = 30 267 logging.info('waiting for %d seconds', wait_sec) 268 time.sleep(wait_sec) 269 270 # Check if EC_RST_L is asserted and EC is on. 271 # (or EC_RST_L deasserted and EC off) 272 self.check_ecrst_asserted(not expect_ec_response) 273 self.ping_ec(expect_ec_response) 274 275 # Release power button 276 logging.info('Power button released') 277 self.servo.set('pwr_button', 'release') 278 time.sleep(self.PD_SETTLE_TIME) 279 280 # Check if EC_RST_L is deasserted and EC is on. 281 self.check_ecrst_asserted(False) 282 self.ping_ec(True) 283 284 finally: 285 self.restore_dut(self.HAS_CR50_RESET_ODL) 286 287 def run_once(self): 288 """Test deferred EC reset feature. """ 289 290 # Release power button and disable RDD on power-on reset. 291 # EC should be running. 292 self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=False) 293 294 # Release power button but enable RDD on power-on reset. 295 # EC should be running. 296 self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=True) 297 298 # Hold power button but disable RDD on power-on reset. 299 # EC should be running. 300 self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=False) 301 302 # Hold power button and enable RDD on power-on reset. 303 # EC should not be running. 304 self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=True) 305 306 logging.info('Test is done') 307