1# Copyright 2018 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
10
11
12class firmware_Cr50ECReset(Cr50Test):
13    """Make sure 'cr50 ecrst' works as intended
14
15    EC_RST_L needs to be able to wake the EC from hibernate and hold the EC in
16    reset. This test verifies the hardware works as intended
17    """
18    version = 1
19
20    # Delays used by the test. Time is given in seconds
21    # Used to wait long enough for the EC to enter/resume from hibernate
22    EC_SETTLE_TIME = 10
23    RELEASE_RESET_DELAY = 3
24    SHORT_PULSE = 1
25
26
27    def initialize(self, host, cmdline_args, full_args):
28        super(firmware_Cr50ECReset, self).initialize(host, cmdline_args,
29                                                     full_args)
30        # Don't bother if there is no Chrome EC or if EC hibernate doesn't work.
31        if not self.check_ec_capability():
32            raise error.TestNAError("Nothing needs to be tested on this device")
33        self.check_ec_hibernate()
34
35
36    def cleanup(self):
37        """Make sure the EC is on, if there is a Chrome EC."""
38        if self.check_ec_capability():
39            self.guarantee_ec_is_up()
40        super(firmware_Cr50ECReset, self).cleanup()
41
42
43    def ec_is_up(self):
44        """If the console is responsive, then the EC is awake"""
45        time.sleep(self.EC_SETTLE_TIME)
46        try:
47            self.ec.send_command_get_output('time', ['.*>'])
48        except error.TestFail, e:
49            logging.info(e)
50            if 'Timeout waiting for response' in str(e):
51                return False
52            raise
53        else:
54            return True
55
56
57    def cold_reset(self, state):
58        """Set cold reset"""
59        self.servo.set('cold_reset', state)
60
61
62    def power_button(self, state):
63        """Press or release the power button"""
64        self.servo.set('pwr_button', 'press' if state == 'on' else 'release')
65
66
67    def cr50_ecrst(self, state):
68        """Set ecrst on cr50"""
69        self.cr50.send_command('ecrst ' + state)
70
71
72    def wake_ec(self, wake_method):
73        """Pulse the wake method to wake the EC
74
75        Args:
76            wake_method: a function that takes in 'on' or 'off' to control the
77                         wake source.
78        """
79        wake_method('on')
80        time.sleep(self.SHORT_PULSE)
81        wake_method('off')
82
83
84    def ec_hibernate(self):
85        """Put the EC in hibernate"""
86        self.ec.send_command('hibernate')
87        if self.ec_is_up():
88            raise error.TestError('Could not put the EC into hibernate')
89
90
91    def guarantee_ec_is_up(self):
92        """Make sure ec isn't held in reset. Use the power button to wake it
93
94        The power button wakes the EC on all systems. Use that to wake the EC
95        and make sure all versions of ecrst are released.
96        """
97        self.cold_reset('off')
98        self.cr50_ecrst('off')
99        time.sleep(self.RELEASE_RESET_DELAY)
100        self.wake_ec(self.power_button)
101        if not self.ec_is_up():
102            raise error.TestError('Could not recover EC')
103
104
105    def can_wake_ec(self, wake_method):
106        """Put the EC in hibernate and verify it can wake up with wake_method
107
108        Args:
109            wake_method: a function that takes in 'on' or 'off' to control the
110                         wake source.
111        Returns:
112            True if wake_method can be used to wake the EC from hibernate
113        """
114        self.ec_hibernate()
115        self.wake_ec(self.cold_reset)
116        wake_successful = self.ec_is_up()
117        self.guarantee_ec_is_up()
118        return wake_successful
119
120
121    def check_basic_ecrst(self):
122        """Verify cr50 can hold the EC in reset"""
123        self.cr50_ecrst('on')
124        if self.ec_is_up():
125            raise error.TestFail('Could not use cr50 ecrst to hold the EC in '
126                                 'reset')
127        # Verify cr50 can release the EC from reset
128        self.cr50_ecrst('off')
129        if not self.ec_is_up():
130            raise error.TestFail('Could not release the EC from reset')
131        self.guarantee_ec_is_up()
132
133    def check_ec_hibernate(self):
134        """Verify EC hibernate"""
135        try:
136            self.ec_hibernate()
137        except error.TestError, e:
138            if 'Could not put the EC into hibernate' in str(e):
139                raise error.TestNAError("EC hibernate doesn't work.")
140        finally:
141            self.guarantee_ec_is_up()
142
143
144    def run_once(self):
145        """Make sure 'cr50 ecrst' works as intended."""
146        failed_wake = []
147
148        # Open cr50 so the test has access to ecrst
149        self.fast_open(True)
150
151        self.check_basic_ecrst()
152
153        if not self.can_wake_ec(self.cr50_ecrst):
154            failed_wake.append('cr50 ecrst')
155
156        if not self.can_wake_ec(self.cold_reset):
157            failed_wake.append('servo cold_reset')
158
159        if failed_wake:
160            raise error.TestFail('Failed to wake EC with %s' %
161                                 ' and '.join(failed_wake))
162