• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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