xref: /aosp_15_r20/external/autotest/server/site_tests/firmware_ECPowerButton/firmware_ECPowerButton.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Copyright (c) 2012 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 time
6import logging
7from threading import Timer
8
9from autotest_lib.client.common_lib import error
10from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
11
12
13class firmware_ECPowerButton(FirmwareTest):
14    """
15    Servo based EC power button test.
16    """
17    version = 1
18
19    # Delay between recovery screen and shutdown by power button
20    RECOVERY_SCREEN_SHUTDOWN_DELAY = 3
21
22    # Duration of holding down power button to test ignoring power button press
23    POWER_BUTTON_IGNORE_PRESS_DURATION = 0.2
24
25    # Delay after pressing power button to check power state
26    POWER_BUTTON_IGNORE_PRESS_DELAY = 10
27
28    # Number of tries when checking power state
29    POWER_STATE_CHECK_TRIES = 20
30
31    # After the device has reached the wanted shutdown power states (S5 or G3),
32    # wait for a short time before executing a power button wakeup.
33    SHUTDOWN_STABLE_DELAY = 1
34
35    def initialize(self, host, cmdline_args):
36        super(firmware_ECPowerButton, self).initialize(host, cmdline_args)
37
38        # Duration of holding down power button to shut down with powerd
39        self.POWER_BUTTON_POWERD_DURATION = (
40                self.faft_config.hold_pwr_button_poweroff)
41        # Duration of holding down power button to shut down without powerd
42        self.POWER_BUTTON_NO_POWERD_DURATION = max(
43                self.faft_config.hold_pwr_button_nopowerd_shutdown, 11)
44        # Short duration of holding down power button to power on
45        self.POWER_BUTTON_SHORT_POWER_ON_DURATION = max(
46                self.faft_config.hold_pwr_button_poweron, 0.05)
47        # Long duration of holding down power button to power on
48        self.POWER_BUTTON_LONG_POWER_ON_DURATION = max(
49                self.faft_config.hold_pwr_button_poweron, 1)
50        # Only run in normal mode
51        self.switcher.setup_mode('normal')
52        self.has_display = host.has_internal_display() or \
53                host.has_external_display()
54
55    def kill_powerd(self):
56        """Stop powerd on client."""
57        self.faft_client.system.run_shell_command("stop powerd")
58
59    def debounce_power_button(self):
60        """Check if power button debouncing works.
61
62        Press power button for a very short period and checks for power
63        button keycode.
64        """
65        # Delay 3 seconds to ensure client machine is waiting for key press.
66        # Press power button for only 10ms. Should be debounced.
67        logging.info('ECPowerButton: debounce_power_button')
68        Timer(3, self.servo.power_key, [0.001]).start()
69        return self.faft_client.system.check_keys([116])
70
71    def shutdown_and_wake(self, shutdown_powerkey_duration, power_state,
72                          wake_powerkey_duration):
73        """
74        Shutdown the system by power button, delay, wait for requested power
75        states and then power on by power button again.
76        """
77
78        # Shutdown the system by pressing the power button
79        self.servo.power_key(shutdown_powerkey_duration)
80
81        # Wait for the system to enter the requested power mode
82        if not self.wait_power_state(power_state,
83                                     self.POWER_STATE_CHECK_TRIES):
84            raise error.TestFail('The device failed to reach %s.' %
85                                 power_state)
86
87        # Add a delay to confirm the system is stabily shut down
88        time.sleep(self.SHUTDOWN_STABLE_DELAY)
89
90        # Send a new line to wakeup EC from deepsleep,
91        # it can happen if the EC console is not used for some time.
92        self.ec.send_command("")
93
94        # Power on the system by pressing the power button
95        self.servo.power_key(wake_powerkey_duration)
96
97        # Some platforms undergo extra power state transitions during power-on.
98        # We need to wait for longer time for the power state to be stable.
99        time.sleep(self.faft_config.delay_powerinfo_stable)
100
101    def run_once(self):
102        """Runs a single iteration of the test."""
103        if not self.check_ec_capability():
104            raise error.TestNAError("Nothing needs to be tested on this device")
105
106        # Ensure that detachable is in OFF State for following test
107        if self.faft_config.is_detachable:
108            # Skip this test step for detachable
109            # Setting Power State to off for entry to next step
110            logging.info("Setting Power Off")
111            self.servo.get_power_state_controller().power_off()
112        else:
113            # Run these test steps for non detachable devices
114            logging.info("Boot to recovery screen.")
115            self.switcher.enable_rec_mode_and_reboot(usb_state='host')
116            time.sleep(self.faft_config.firmware_screen)
117            if self.get_power_state() != self.POWER_STATE_S0:
118                raise error.TestFail("DUT didn't boot to recovery screen")
119
120            logging.info("Shutdown by short power button press.")
121            self.servo.power_key(self.faft_config.hold_pwr_button_poweron)
122            time.sleep(self.RECOVERY_SCREEN_SHUTDOWN_DELAY)
123            power_state = self.get_power_state()
124            if (power_state != self.POWER_STATE_S5
125                        and power_state != self.POWER_STATE_G3):
126                raise error.TestFail("DUT didn't shutdown by "
127                                     "short power button press")
128            if self.ec.check_feature('EC_FEATURE_EFS2'):
129                logging.info("Check if EC jumped to RW.")
130                if not self.ec.check_ro_rw('RW'):
131                    raise error.TestFail("EC didn't jump to RW")
132
133        logging.info("Boot by short power button press.")
134        self.servo.power_key(self.faft_config.hold_pwr_button_poweron)
135        self.switcher.wait_for_client()
136        if self.get_power_state() != self.POWER_STATE_S0:
137            raise error.TestFail("DUT didn't boot by short power button press")
138
139        if self.has_display:
140            logging.info("Display connected, check system ignores short 200ms "
141                         "power button press.")
142            old_boot_id = self.get_bootid(retry=1)
143            self.servo.power_key(self.POWER_BUTTON_IGNORE_PRESS_DURATION)
144            time.sleep(self.POWER_BUTTON_IGNORE_PRESS_DELAY)
145            power_state = self.get_power_state()
146            new_boot_id = self.get_bootid(retry=1)
147            if power_state != self.POWER_STATE_S0 or new_boot_id != old_boot_id:
148                self._reset_client()
149                raise error.TestFail("DUT shutdown from short 200ms power "
150                                     "button press")
151        else:
152            logging.info("No display connected, check system shuts down from "
153                         "short 200ms power button check.")
154            self.servo.power_key(self.POWER_BUTTON_IGNORE_PRESS_DURATION)
155            time.sleep(self.POWER_BUTTON_IGNORE_PRESS_DELAY)
156            power_state = self.get_power_state()
157            logging.info("Power state = %s", power_state)
158            if (power_state != self.POWER_STATE_S5 and
159                power_state != self.POWER_STATE_G3):
160                self._reset_client()
161                raise error.TestFail("DUT didn't shutdown by "
162                                    "short power button press")
163            self.servo.power_key(self.faft_config.hold_pwr_button_poweron)
164            self.switcher.wait_for_client()
165            if self.get_power_state() != self.POWER_STATE_S0:
166                self._reset_client()
167                raise error.TestFail("DUT didn't boot by short power button press")
168
169        logging.info(
170                "Shutdown when powerd is still running and wake from S5/G3 "
171                "with short power button press.")
172        if self.servo.is_localhost() and self.has_display:
173            self.check_state(self.debounce_power_button)
174        self.switcher.mode_aware_reboot(
175                'custom', lambda: self.shutdown_and_wake(
176                        self.POWER_BUTTON_POWERD_DURATION,
177                        self.POWER_STATE_S5 + '|' + self.POWER_STATE_G3,
178                        self.POWER_BUTTON_SHORT_POWER_ON_DURATION))
179
180        logging.info("Shutdown when powerd is stopped and wake from G3 "
181                          "with short power button press.")
182        self.kill_powerd()
183        self.switcher.mode_aware_reboot(
184                'custom', lambda: self.shutdown_and_wake(
185                        self.POWER_BUTTON_NO_POWERD_DURATION, self.
186                        POWER_STATE_G3,
187                        self.POWER_BUTTON_SHORT_POWER_ON_DURATION))
188
189        logging.info("Shutdown when powerd is still running and wake from G3 "
190                     "with long power button press.")
191        self.switcher.mode_aware_reboot(
192                'custom', lambda: self.shutdown_and_wake(
193                        self.POWER_BUTTON_POWERD_DURATION,
194                        self.POWER_STATE_G3,
195                        self.POWER_BUTTON_LONG_POWER_ON_DURATION))
196
197        logging.info("Shutdown when powerd is stopped and wake from S5/G3 "
198                     "with long power button press.")
199        self.kill_powerd()
200        self.switcher.mode_aware_reboot(
201                'custom', lambda: self.shutdown_and_wake(
202                        self.POWER_BUTTON_NO_POWERD_DURATION,
203                        self.POWER_STATE_S5 + '|' + self.POWER_STATE_G3,
204                        self.POWER_BUTTON_LONG_POWER_ON_DURATION))
205