1# SPDX-License-Identifier: GPL-2.0
2# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
3
4# Test U-Boot's "mmc read" command. The test reads data from the eMMC or SD
5# card, and validates the no errors occurred, and that the expected data was
6# read if the test configuration contains a CRC of the expected data.
7
8import pytest
9import time
10import u_boot_utils
11
12"""
13This test relies on boardenv_* to containing configuration values to define
14which MMC devices should be tested. For example:
15
16# Configuration data for test_mmc_dev, test_mmc_rescan, test_mmc_info; defines
17# whole MMC devices that mmc dev/rescan/info commands may operate upon.
18env__mmc_dev_configs = (
19    {
20        'fixture_id': 'emmc-boot0',
21        'is_emmc': True,
22        'devid': 0,
23        'partid': 1,
24        'info_device': ???,
25        'info_speed': ???,
26        'info_mode': ???,
27        'info_buswidth': ???.
28    },
29    {
30        'fixture_id': 'emmc-boot1',
31        'is_emmc': True,
32        'devid': 0,
33        'partid': 2,
34        'info_device': ???,
35        'info_speed': ???,
36        'info_mode': ???,
37        'info_buswidth': ???.
38    },
39    {
40        'fixture_id': 'emmc-data',
41        'is_emmc': True,
42        'devid': 0,
43        'partid': 0,
44        'info_device': ???,
45        'info_speed': ???,
46        'info_mode': ???,
47        'info_buswidth': ???.
48    },
49    {
50        'fixture_id': 'sd',
51        'is_emmc': False,
52        'devid': 1,
53        'partid': None,
54        'info_device': ???,
55        'info_speed': ???,
56        'info_mode': ???,
57        'info_buswidth': ???.
58    },
59)
60
61# Configuration data for test_mmc_rd; defines regions of the MMC (entire
62# devices, or ranges of sectors) which can be read:
63env__mmc_rd_configs = (
64    {
65        'fixture_id': 'emmc-boot0',
66        'is_emmc': True,
67        'devid': 0,
68        'partid': 1,
69        'sector': 0x10,
70        'count': 1,
71    },
72    {
73        'fixture_id': 'emmc-boot1',
74        'is_emmc': True,
75        'devid': 0,
76        'partid': 2,
77        'sector': 0x10,
78        'count': 1,
79    },
80    {
81        'fixture_id': 'emmc-data',
82        'is_emmc': True,
83        'devid': 0,
84        'partid': 0,
85        'sector': 0x10,
86        'count': 0x1000,
87    },
88    {
89        'fixture_id': 'sd-mbr',
90        'is_emmc': False,
91        'devid': 1,
92        'partid': None,
93        'sector': 0,
94        'count': 1,
95        'crc32': '8f6ecf0d',
96    },
97    {
98        'fixture_id': 'sd-large',
99        'is_emmc': False,
100        'devid': 1,
101        'partid': None,
102        'sector': 0x10,
103        'count': 0x1000,
104    },
105)
106"""
107
108def mmc_dev(u_boot_console, is_emmc, devid, partid):
109    """Run the "mmc dev" command.
110
111    Args:
112        u_boot_console: A U-Boot console connection.
113        is_emmc: Whether the device is eMMC
114        devid: Device ID
115        partid: Partition ID
116
117    Returns:
118        Nothing.
119    """
120
121    # Select MMC device
122    cmd = 'mmc dev %d' % devid
123    if is_emmc:
124        cmd += ' %d' % partid
125    response = u_boot_console.run_command(cmd)
126    assert 'no card present' not in response
127    if is_emmc:
128        partid_response = '(part %d)' % partid
129    else:
130        partid_response = ''
131    good_response = 'mmc%d%s is current device' % (devid, partid_response)
132    assert good_response in response
133
134@pytest.mark.buildconfigspec('cmd_mmc')
135def test_mmc_dev(u_boot_console, env__mmc_dev_config):
136    """Test the "mmc dev" command.
137
138    Args:
139        u_boot_console: A U-Boot console connection.
140        env__mmc_dev_config: The single MMC configuration on which
141            to run the test. See the file-level comment above for details
142            of the format.
143
144    Returns:
145        Nothing.
146    """
147
148    is_emmc = env__mmc_dev_config['is_emmc']
149    devid = env__mmc_dev_config['devid']
150    partid = env__mmc_dev_config.get('partid', 0)
151
152    # Select MMC device
153    mmc_dev(u_boot_console, is_emmc, devid, partid)
154
155@pytest.mark.buildconfigspec('cmd_mmc')
156def test_mmc_rescan(u_boot_console, env__mmc_dev_config):
157    """Test the "mmc rescan" command.
158
159    Args:
160        u_boot_console: A U-Boot console connection.
161        env__mmc_dev_config: The single MMC configuration on which
162            to run the test. See the file-level comment above for details
163            of the format.
164
165    Returns:
166        Nothing.
167    """
168
169    is_emmc = env__mmc_dev_config['is_emmc']
170    devid = env__mmc_dev_config['devid']
171    partid = env__mmc_dev_config.get('partid', 0)
172
173    # Select MMC device
174    mmc_dev(u_boot_console, is_emmc, devid, partid)
175
176    # Rescan MMC device
177    cmd = 'mmc rescan'
178    response = u_boot_console.run_command(cmd)
179    assert 'no card present' not in response
180
181@pytest.mark.buildconfigspec('cmd_mmc')
182def test_mmc_info(u_boot_console, env__mmc_dev_config):
183    """Test the "mmc info" command.
184
185    Args:
186        u_boot_console: A U-Boot console connection.
187        env__mmc_dev_config: The single MMC configuration on which
188            to run the test. See the file-level comment above for details
189            of the format.
190
191    Returns:
192        Nothing.
193    """
194
195    is_emmc = env__mmc_dev_config['is_emmc']
196    devid = env__mmc_dev_config['devid']
197    partid = env__mmc_dev_config.get('partid', 0)
198    info_device = env__mmc_dev_config['info_device']
199    info_speed = env__mmc_dev_config['info_speed']
200    info_mode = env__mmc_dev_config['info_mode']
201    info_buswidth = env__mmc_dev_config['info_buswidth']
202
203    # Select MMC device
204    mmc_dev(u_boot_console, is_emmc, devid, partid)
205
206    # Read MMC device information
207    cmd = 'mmc info'
208    response = u_boot_console.run_command(cmd)
209    good_response = "Device: %s" % info_device
210    assert good_response in response
211    good_response = "Bus Speed: %s" % info_speed
212    assert good_response in response
213    good_response = "Mode: %s" % info_mode
214    assert good_response in response
215    good_response = "Bus Width: %s" % info_buswidth
216    assert good_response in response
217
218@pytest.mark.buildconfigspec('cmd_mmc')
219def test_mmc_rd(u_boot_console, env__mmc_rd_config):
220    """Test the "mmc read" command.
221
222    Args:
223        u_boot_console: A U-Boot console connection.
224        env__mmc_rd_config: The single MMC configuration on which
225            to run the test. See the file-level comment above for details
226            of the format.
227
228    Returns:
229        Nothing.
230    """
231
232    is_emmc = env__mmc_rd_config['is_emmc']
233    devid = env__mmc_rd_config['devid']
234    partid = env__mmc_rd_config.get('partid', 0)
235    sector = env__mmc_rd_config.get('sector', 0)
236    count_sectors = env__mmc_rd_config.get('count', 1)
237    expected_crc32 = env__mmc_rd_config.get('crc32', None)
238    read_duration_max = env__mmc_rd_config.get('read_duration_max', 0)
239
240    count_bytes = count_sectors * 512
241    bcfg = u_boot_console.config.buildconfig
242    has_cmd_memory = bcfg.get('config_cmd_memory', 'n') == 'y'
243    has_cmd_crc32 = bcfg.get('config_cmd_crc32', 'n') == 'y'
244    ram_base = u_boot_utils.find_ram_base(u_boot_console)
245    addr = '0x%08x' % ram_base
246
247    # Select MMC device
248    mmc_dev(u_boot_console, is_emmc, devid, partid)
249
250    # Clear target RAM
251    if expected_crc32:
252        if has_cmd_memory and has_cmd_crc32:
253            cmd = 'mw.b %s 0 0x%x' % (addr, count_bytes)
254            u_boot_console.run_command(cmd)
255
256            cmd = 'crc32 %s 0x%x' % (addr, count_bytes)
257            response = u_boot_console.run_command(cmd)
258            assert expected_crc32 not in response
259        else:
260            u_boot_console.log.warning(
261                'CONFIG_CMD_MEMORY or CONFIG_CMD_CRC32 != y: Skipping RAM clear')
262
263    # Read data
264    cmd = 'mmc read %s %x %x' % (addr, sector, count_sectors)
265    tstart = time.time()
266    response = u_boot_console.run_command(cmd)
267    tend = time.time()
268    good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (
269        devid, sector, count_sectors, count_sectors)
270    assert good_response in response
271
272    # Check target RAM
273    if expected_crc32:
274        if has_cmd_crc32:
275            cmd = 'crc32 %s 0x%x' % (addr, count_bytes)
276            response = u_boot_console.run_command(cmd)
277            assert expected_crc32 in response
278        else:
279            u_boot_console.log.warning('CONFIG_CMD_CRC32 != y: Skipping check')
280
281    # Check if the command did not take too long
282    if read_duration_max:
283        elapsed = tend - tstart
284        u_boot_console.log.info('Reading %d bytes took %f seconds' %
285                                (count_bytes, elapsed))
286        assert elapsed <= (read_duration_max - 0.01)
287