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 HAS_CR50_RESET_ODL = False 32 33 def cr50_power_on_reset(self): 34 """Perform a power-on-reset on cr50. 35 If cr50_reset_odl control is available, then use it. 36 Otherwise, disconnect and reconnect battery and power source. 37 """ 38 if self.HAS_CR50_RESET_ODL: 39 self.servo.set('cr50_reset_odl', 'on') 40 41 time.sleep(self.CUTOFF_DELAY) 42 43 self.servo.set('cr50_reset_odl', 'off') 44 else: 45 # Stop power delivery to dut 46 logging.info('Stop charging') 47 self.servo.set('servo_v4_role', 'snk') 48 49 # Battery Cutoff 50 logging.info('Cut battery off') 51 self.ec.send_command('cutoff') 52 53 time.sleep(self.CUTOFF_DELAY) 54 55 # Enable power delivery to dut 56 logging.info('Start charging') 57 self.servo.set('servo_v4_role', 'src') 58 59 time.sleep(self.PD_SETTLE_TIME) 60 61 def ac_is_plugged_in(self): 62 """Check if AC is plugged. 63 64 Returns: 65 True if AC is plugged, or False otherwise. 66 """ 67 68 rv = self.ec.send_command_get_output('chgstate', 69 [r'ac\s*=\s*(0|1)\s*'])[0][1] 70 return rv == '1' 71 72 def initialize(self, host, cmdline_args, full_args): 73 """Initialize the test and check if cr50 exists, DTS is controllable, 74 and power delivery mode and power button is adjustable. 75 76 Raises: 77 TestFail: If test initialization setup fails. 78 TestNAError: If the dut is not proper for this test for its RDD 79 recognition problem. 80 """ 81 super(firmware_Cr50DeferredECReset, self).initialize(host, cmdline_args, 82 full_args) 83 if not hasattr(self, 'cr50'): 84 raise error.TestNAError('Test can only be run on devices with ' 85 'access to the Cr50 console') 86 if not self.cr50.servo_dts_mode_is_valid(): 87 raise error.TestNAError('Need working servo v4 DTS control') 88 self.dts_restore = self.servo.get_dts_mode() 89 90 # Fast open cr50 and check if testlab is enabled. 91 self.fast_ccd_open(enable_testlab=True) 92 if not self.cr50.testlab_is_on(): 93 raise error.TestNAError('Cr50 testlab mode is not enabled') 94 95 # Check 'rdd_leakage' is marked in cr50 capability. 96 if self.check_cr50_capability(['rdd_leakage']): 97 self.rdd_leakage = True 98 logging.warn('RDD leakage is marked in cr50 cap config') 99 else: 100 self.rdd_leakage = False 101 102 # Test if the power button is adjustable. 103 self.servo.set('pwr_button', 'press') 104 self.servo.set('pwr_button', 'release') 105 106 # Check if 'cr50_reset_odl' controlis available. 107 try: 108 self.servo.get('cr50_reset_odl') 109 self.HAS_CR50_RESET_ODL = True 110 except error.TestFail: 111 self.HAS_CR50_RESET_ODL = False 112 113 # Test the external power delivery 114 self.servo.set('servo_v4_role', 'snk') 115 time.sleep(self.PD_SETTLE_TIME) 116 117 if self.ac_is_plugged_in(): 118 raise error.TestFail('Failed to set servo_v4_role sink') 119 120 # Test stopping the external power delivery 121 self.servo.set('servo_v4_role', 'src') 122 time.sleep(self.PD_SETTLE_TIME) 123 124 if not self.ac_is_plugged_in(): 125 raise error.TestFail('Failed to set servo_v4_role source') 126 127 # Check if the dut has any RDD recognition issue. 128 # First, cut off power source and hold the power button. 129 # disable RDD connection. 130 self.servo.set_dts_mode('off') 131 self.servo.set('pwr_button', 'press') 132 self.cr50_power_on_reset() 133 try: 134 # Third, check if the rdd status is disconnected. 135 # If not, terminate the test. 136 ccdstate = self.cr50.get_ccdstate() 137 138 if (ccdstate['Rdd'].lower() != 'disconnected') != self.rdd_leakage: 139 raise error.TestError('RDD leakage does not match capability' 140 ' configuration.') 141 finally: 142 self.servo.set_dts_mode(self.dts_restore) 143 self.servo.set_nocheck('pwr_button', 'release') 144 time.sleep(self.PD_SETTLE_TIME) 145 146 self.servo.power_short_press() # Wake up AP 147 148 logging.info('Initialization is done') 149 150 def check_ecrst_asserted(self, expect_assert): 151 """Ask CR50 whether EC_RST_L is asserted or deasserted. 152 153 Args: 154 expect_assert: True if it is expected asserted. 155 False otherwise. 156 157 Raises: 158 TestFail: if ecrst value is not as expected. 159 """ 160 161 # If the console is responsive, then the EC is awake. 162 expected_txt = 'asserted' if expect_assert else 'deasserted' 163 logging.info('Checking if ecrst is %s', expected_txt) 164 165 try: 166 rv = self.cr50.send_command_get_output('ecrst', 167 [r'EC_RST_L is (%s)' % expected_txt]) 168 logging.info(rv) 169 except error.TestError as e: 170 raise error.TestFail(str(e)) 171 172 def ping_ec(self, expect_response): 173 """Check if EC is running and responding. 174 175 Args: 176 expect_response: True if EC should respond 177 False otherwise. 178 Raises: 179 TestFail: if ec responsiveness is not as same as expected. 180 """ 181 try: 182 logging.info('Checking if ec is %sresponsive', 183 '' if expect_response else 'not ') 184 rv = self.ec.send_command_get_output('help', ['.*>'])[0].strip() 185 except servo.UnresponsiveConsoleError as e: 186 logging.info(str(e)) 187 return 188 else: 189 if not expect_response: 190 logging.error('EC should not respond') 191 raise error.TestFail(rv) 192 193 def test_deferred_ec_reset(self, power_button_hold, rdd_enable): 194 """Do a power-on reset, and check if EC responds. 195 196 Args: 197 power_button_hold: True if it should be pressed on a system reset. 198 False otherwise. 199 rdd_enable: True if RDD should be detected on a system reset. 200 False otherwise. 201 """ 202 203 # If the board has a rdd leakage issue, RDD shall be detected 204 # always in G3. EC_RST will be asserted if the power_button is 205 # being presed in this test. 206 expect_ec_response = not (power_button_hold and 207 (rdd_enable or self.rdd_leakage)) 208 logging.info('Test deferred_ec_reset starts') 209 logging.info('Power button held : %s', power_button_hold) 210 logging.info('RDD connection : %s', rdd_enable) 211 logging.info('RDD leakage : %s', self.rdd_leakage) 212 logging.info('Expected EC response : %s', expect_ec_response) 213 214 try: 215 # enable RDD Connection (or disable) before power-on-reset 216 self.servo.set_dts_mode('on' if rdd_enable else 'off') 217 218 # Set power button before the dut loses power, 219 # because the power button value cannot be changed during power-off. 220 self.servo.set('pwr_button', 221 'press' if power_button_hold else 'release') 222 223 # Do a power-on-reset on CR50. 224 self.cr50_power_on_reset() 225 226 # Wait for a while 227 wait_sec = 30 228 logging.info('waiting for %d seconds', wait_sec) 229 time.sleep(wait_sec) 230 231 # Check if EC_RST_L is asserted and EC is on. 232 # (or EC_RST_L deasserted and EC off) 233 self.check_ecrst_asserted(not expect_ec_response) 234 self.ping_ec(expect_ec_response) 235 236 # Release power button 237 logging.info('Power button released') 238 self.servo.set('pwr_button', 'release') 239 time.sleep(self.PD_SETTLE_TIME) 240 241 # Check if EC_RST_L is deasserted and EC is on. 242 self.check_ecrst_asserted(False) 243 self.ping_ec(True) 244 245 finally: 246 if self.HAS_CR50_RESET_ODL: 247 self.servo.set_nocheck('cr50_reset_odl', 'off') 248 else: 249 self.servo.set_nocheck('servo_v4_role', 'src') 250 251 self.servo.set_dts_mode(self.dts_restore) 252 time.sleep(1) 253 254 # Press power button to wake up AP, and releases it soon 255 # in any cases. 256 self.servo.power_short_press() 257 258 def run_once(self): 259 """Test deferred EC reset feature. """ 260 261 # Release power button and disable RDD on power-on reset. 262 # EC should be running. 263 self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=False) 264 265 # Release power button but enable RDD on power-on reset. 266 # EC should be running. 267 self.test_deferred_ec_reset(power_button_hold=False, rdd_enable=True) 268 269 # Hold power button but disable RDD on power-on reset. 270 # EC should be running. 271 self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=False) 272 273 # Hold power button and enable RDD on power-on reset. 274 # EC should not be running. 275 self.test_deferred_ec_reset(power_button_hold=True, rdd_enable=True) 276 277 logging.info('Test is done') 278