xref: /aosp_15_r20/external/autotest/server/site_tests/firmware_ECWakeFromULP/firmware_ECWakeFromULP.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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