1# Copyright 2021 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.firmware_test import FirmwareTest 10from autotest_lib.server.cros.power import servo_charger 11from autotest_lib.server.cros.servo import servo 12 13 14class firmware_ECWakeFromULP(FirmwareTest): 15 """ 16 Servo based EC wake from ULP test. 17 """ 18 version = 1 19 20 # Retries allowed for reaching designed states. 21 POWER_STATE_RETRY_COUNT = 10 22 23 def initialize(self, host, cmdline_args): 24 super(firmware_ECWakeFromULP, self).initialize(host, cmdline_args) 25 self.setup_pdtester(min_batt_level=10) 26 # Only run in normal mode 27 self.switcher.setup_mode('normal') 28 self.charge_manager = servo_charger.ServoV4ChargeManager( 29 host, host.servo) 30 # stop charging to test hibernate 31 self.charge_manager.stop_charging() 32 33 def cleanup(self): 34 # The DUT might be still hibernated. Force the reboot. 35 if not self.is_ec_console_responsive(): 36 logging.info('System is still hibernated; reboot.') 37 self.switcher.simple_reboot('cold', sync_before_boot=False) 38 39 if not self.wait_power_state(self.POWER_STATE_S0, 40 self.POWER_STATE_RETRY_COUNT): 41 logging.info('System is S5/G3; press pwrbtn to boot to S0.') 42 self.servo.power_short_press() 43 44 # Restore the lid_open switch in case the test failed in the middle. 45 if self.check_ec_capability(['lid']): 46 self.servo.set('lid_open', 'yes') 47 48 self.charge_manager.start_charging() 49 50 super(firmware_ECWakeFromULP, self).cleanup() 51 52 def hibernate_and_wake(self, host, wake_func, wake_state): 53 """Shutdown to G3/S5, hibernate EC, and then wake by power button.""" 54 self.run_shutdown_cmd() 55 if not self.wait_power_state(self.POWER_STATE_G3, 56 self.POWER_STATE_RETRY_COUNT): 57 raise error.TestFail('Platform failed to reach G3 state.') 58 59 self.ec.send_command('hibernate') 60 time.sleep(self.WAKE_DELAY) 61 62 if self.is_ec_console_responsive(): 63 raise error.TestFail('The DUT is not in hibernate mode.') 64 else: 65 logging.info('Hibernated. EC console in not responsive. ') 66 67 # wake system 68 wake_func() 69 if not self.wait_power_state(wake_state, self.POWER_STATE_RETRY_COUNT): 70 raise error.TestFail('Platform failed to reach %s state.' % 71 wake_state) 72 if wake_state == self.POWER_STATE_S0: 73 self.switcher.wait_for_client() 74 75 def is_ec_console_responsive(self): 76 """Test if EC console is responsive.""" 77 try: 78 self.ec.send_command_get_output('help', ['.*>']) 79 return True 80 except servo.UnresponsiveConsoleError: 81 return False 82 83 def wake_by_lid_switch(self): 84 """Wake up the device by lid switch.""" 85 self.servo.set('lid_open', 'no') 86 time.sleep(self.LID_DELAY) 87 self.servo.set('lid_open', 'yes') 88 89 def run_once(self, host): 90 """Runs a single iteration of the test.""" 91 if not self.check_ec_capability(): 92 raise error.TestNAError( 93 "Nothing needs to be tested on this device") 94 95 if self.servo.main_device_is_ccd(): 96 raise error.TestNAError( 97 'With CCD, we can\'t wake up the DUT from ' 98 'hibernate by power button. Skip hibernate ' 99 'test.') 100 elif not self.faft_config.hibernate: 101 raise error.TestNAError('The device does not support hibernate. ' 102 'Skip hibernate test.') 103 elif not self._client.has_battery(): 104 raise error.TestNAError( 105 'The device claims to have hibernate support, but does not ' 106 'have a battery. It probably does not actually have ' 107 'hibernate support, edit the device.json file in ' 108 'fw-testing-configs. Skip hibernate test.') 109 110 # Test hibernate and wake by power button 111 wake_src = 'power button' 112 logging.info('EC hibernate and wake by power button.') 113 self.hibernate_and_wake(host, self.servo.power_short_press, 114 self.POWER_STATE_S0) 115 116 # Test hibernate and wake by lid switch 117 wake_src = 'lid switch' 118 if not self.check_ec_capability(['lid']): 119 logging.info( 120 'The device has no lid. ' 121 'Skip testing hibernate/wake by %s.', wake_src) 122 elif 'c2d2' in self.servo.get_servo_type(): 123 logging.info('The servo is c2d2. We can\'t wake up the DUT from ' 124 'hibernate by lid open. Skip hibernate test') 125 else: 126 logging.info('Hibernate and wake by %s.', wake_src) 127 self.hibernate_and_wake(host, self.wake_by_lid_switch, 128 self.POWER_STATE_S0) 129 130 # Test hibernate and wake by AC on 131 wake_src = 'AC on' 132 self.charge_manager.stop_charging() 133 logging.info('Hibernate and wake by %s.', wake_src) 134 if self.faft_config.ac_on_can_wake_ap_from_ulp: 135 logging.info('AC on event can wake AP from ULP.') 136 wake_state = self.POWER_STATE_S0 137 else: 138 logging.info('AC on event cannot wake AP from ULP.') 139 wake_state = self.POWER_STATE_G3 140 self.hibernate_and_wake(host, self.charge_manager.start_charging, 141 wake_state) 142 143 if not self.faft_config.ac_on_can_wake_ap_from_ulp: 144 # Put AP back to S0 145 self.servo.power_short_press() 146