summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/dm/clk.c37
-rw-r--r--test/dm/reset.c33
-rw-r--r--test/dm/test-fdt.c43
-rw-r--r--test/dm/video.c2
-rw-r--r--test/py/README.md6
-rw-r--r--test/py/conftest.py19
-rw-r--r--test/py/multiplexed_log.css4
-rw-r--r--test/py/multiplexed_log.py30
-rw-r--r--test/py/tests/test_efi_selftest.py14
-rw-r--r--test/py/tests/test_mmc_rd.py129
-rw-r--r--test/py/tests/test_sf.py218
-rw-r--r--test/py/u_boot_utils.py24
12 files changed, 551 insertions, 8 deletions
diff --git a/test/dm/clk.c b/test/dm/clk.c
index 712a1e674a5..d3649103ee6 100644
--- a/test/dm/clk.c
+++ b/test/dm/clk.c
@@ -101,3 +101,40 @@ static int dm_test_clk(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_clk, DM_TESTF_SCAN_FDT);
+
+static int dm_test_clk_bulk(struct unit_test_state *uts)
+{
+ struct udevice *dev_clk, *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-sbox",
+ &dev_clk));
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test",
+ &dev_test));
+ ut_assertok(sandbox_clk_test_get_bulk(dev_test));
+
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+ /* Fixed clock does not support enable, thus should not fail */
+ ut_assertok(sandbox_clk_test_enable_bulk(dev_test));
+ ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+ ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+ /* Fixed clock does not support disable, thus should not fail */
+ ut_assertok(sandbox_clk_test_disable_bulk(dev_test));
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+ /* Fixed clock does not support enable, thus should not fail */
+ ut_assertok(sandbox_clk_test_enable_bulk(dev_test));
+ ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+ ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+ /* Fixed clock does not support disable, thus should not fail */
+ ut_assertok(sandbox_clk_test_release_bulk(dev_test));
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI));
+ ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C));
+
+ return 0;
+}
+DM_TEST(dm_test_clk_bulk, DM_TESTF_SCAN_FDT);
diff --git a/test/dm/reset.c b/test/dm/reset.c
index 0ae8031540c..8dc0023c080 100644
--- a/test/dm/reset.c
+++ b/test/dm/reset.c
@@ -13,6 +13,9 @@
/* This must match the specifier for mbox-names="test" in the DT node */
#define TEST_RESET_ID 2
+/* This is the other reset phandle specifier handled by bulk */
+#define OTHER_RESET_ID 2
+
static int dm_test_reset(struct unit_test_state *uts)
{
struct udevice *dev_reset;
@@ -37,3 +40,33 @@ static int dm_test_reset(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_reset, DM_TESTF_SCAN_FDT);
+
+static int dm_test_reset_bulk(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset;
+ struct udevice *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl",
+ &dev_reset));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(sandbox_reset_test_get_bulk(dev_test));
+
+ ut_assertok(sandbox_reset_test_assert_bulk(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_deassert_bulk(dev_test));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_release_bulk(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_bulk, DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 920ccbf016d..0d11bfdb2f9 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -419,3 +419,46 @@ static int dm_test_first_next_ok_device(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static const struct udevice_id fdt_dummy_ids[] = {
+ { .compatible = "denx,u-boot-fdt-dummy", },
+ { }
+};
+
+UCLASS_DRIVER(fdt_dummy) = {
+ .name = "fdt_dummy",
+ .id = UCLASS_TEST_DUMMY,
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+};
+
+U_BOOT_DRIVER(fdt_dummy_drv) = {
+ .name = "fdt_dummy_drv",
+ .of_match = fdt_dummy_ids,
+ .id = UCLASS_TEST_DUMMY,
+};
+
+static int dm_test_fdt_translation(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ /* Some simple translations */
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
+ ut_asserteq_str("dev@0,0", dev->name);
+ ut_asserteq(0x8000, dev_read_addr(dev));
+
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 1, true, &dev));
+ ut_asserteq_str("dev@1,100", dev->name);
+ ut_asserteq(0x9000, dev_read_addr(dev));
+
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 2, true, &dev));
+ ut_asserteq_str("dev@2,200", dev->name);
+ ut_asserteq(0xA000, dev_read_addr(dev));
+
+ /* No translation for busses with #size-cells == 0 */
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 3, true, &dev));
+ ut_asserteq_str("dev@42", dev->name);
+ ut_asserteq(0x42, dev_read_addr(dev));
+
+ return 0;
+}
+DM_TEST(dm_test_fdt_translation, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/video.c b/test/dm/video.c
index 29917d0c2d8..caca4969027 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -186,7 +186,7 @@ static int dm_test_video_ansi(struct unit_test_state *uts)
/* test colors (30-37 fg color, 40-47 bg color) */
vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
- ut_asserteq(268, compress_frame_buffer(dev));
+ ut_asserteq(265, compress_frame_buffer(dev));
return 0;
}
diff --git a/test/py/README.md b/test/py/README.md
index eefac377567..aed2fd063a8 100644
--- a/test/py/README.md
+++ b/test/py/README.md
@@ -150,7 +150,7 @@ processing.
option takes a single argument which is used to filter test names. Simple
logical operators are supported. For example:
- `'ums'` runs only tests with "ums" in their name.
- - ``ut_dm'` runs only tests with "ut_dm" in their name. Note that in this
+ - `'ut_dm'` runs only tests with "ut_dm" in their name. Note that in this
case, "ut_dm" is a parameter to a test rather than the test name. The full
test name is e.g. "test_ut[ut_dm_leak]".
- `'not reset'` runs everything except tests with "reset" in their name.
@@ -320,7 +320,7 @@ If U-Boot has already been built:
```bash
PATH=$HOME/ubtest/bin:$PATH \
- PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \
+ PYTHONPATH=${HOME}/ubtest/py/${HOSTNAME}:${PYTHONPATH} \
./test/py/test.py --bd seaboard
```
@@ -331,7 +331,7 @@ follow:
```bash
CROSS_COMPILE=arm-none-eabi- \
PATH=$HOME/ubtest/bin:$PATH \
- PYTHONPATH=${HOME}/ubtest/py:${PYTHONPATH} \
+ PYTHONPATH=${HOME}/ubtest/py/${HOSTNAME}:${PYTHONPATH} \
./test/py/test.py --bd seaboard --build
```
diff --git a/test/py/conftest.py b/test/py/conftest.py
index 3fe91e87460..83eaca46a90 100644
--- a/test/py/conftest.py
+++ b/test/py/conftest.py
@@ -344,6 +344,7 @@ tests_failed = []
tests_xpassed = []
tests_xfailed = []
tests_skipped = []
+tests_warning = []
tests_passed = []
def pytest_itemcollected(item):
@@ -380,6 +381,11 @@ def cleanup():
if log:
with log.section('Status Report', 'status_report'):
log.status_pass('%d passed' % len(tests_passed))
+ if tests_warning:
+ log.status_warning('%d passed with warning' % len(tests_warning))
+ for test in tests_warning:
+ anchor = anchors.get(test, None)
+ log.status_warning('... ' + test, anchor)
if tests_skipped:
log.status_skipped('%d skipped' % len(tests_skipped))
for test in tests_skipped:
@@ -520,7 +526,9 @@ def pytest_runtest_protocol(item, nextitem):
A list of pytest reports (test result data).
"""
+ log.get_and_reset_warning()
reports = runtestprotocol(item, nextitem=nextitem)
+ was_warning = log.get_and_reset_warning()
# In pytest 3, runtestprotocol() may not call pytest_runtest_setup() if
# the test is skipped. That call is required to create the test's section
@@ -531,9 +539,14 @@ def pytest_runtest_protocol(item, nextitem):
start_test_section(item)
failure_cleanup = False
- test_list = tests_passed
- msg = 'OK'
- msg_log = log.status_pass
+ if not was_warning:
+ test_list = tests_passed
+ msg = 'OK'
+ msg_log = log.status_pass
+ else:
+ test_list = tests_warning
+ msg = 'OK (with warning)'
+ msg_log = log.status_warning
for report in reports:
if report.outcome == 'failed':
if hasattr(report, 'wasxfail'):
diff --git a/test/py/multiplexed_log.css b/test/py/multiplexed_log.css
index 9b7c44fe4de..562f69f3b6f 100644
--- a/test/py/multiplexed_log.css
+++ b/test/py/multiplexed_log.css
@@ -70,6 +70,10 @@ pre {
color: #00ff00
}
+.status-warning {
+ color: #ffff00
+}
+
.status-skipped {
color: #ffff00
}
diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py
index 8ca515319ce..a2cfd717461 100644
--- a/test/py/multiplexed_log.py
+++ b/test/py/multiplexed_log.py
@@ -224,6 +224,7 @@ class Logfile(object):
self.timestamp_start = self._get_time()
self.timestamp_prev = self.timestamp_start
self.timestamp_blocks = []
+ self.seen_warning = False
shutil.copy(mod_dir + '/multiplexed_log.css', os.path.dirname(fn))
self.f.write('''\
@@ -252,6 +253,7 @@ $(document).ready(function () {
passed_bcs = passed_bcs.not(":has(.status-xfail)");
passed_bcs = passed_bcs.not(":has(.status-xpass)");
passed_bcs = passed_bcs.not(":has(.status-skipped)");
+ passed_bcs = passed_bcs.not(":has(.status-warning)");
// Hide the passed blocks
passed_bcs.addClass("hidden");
// Flip the expand/contract button hiding for those blocks.
@@ -478,8 +480,23 @@ $(document).ready(function () {
Nothing.
"""
+ self.seen_warning = True
self._note("warning", msg)
+ def get_and_reset_warning(self):
+ """Get and reset the log warning flag.
+
+ Args:
+ None
+
+ Returns:
+ Whether a warning was seen since the last call.
+ """
+
+ ret = self.seen_warning
+ self.seen_warning = False
+ return ret
+
def info(self, msg):
"""Write an informational note to the log file.
@@ -542,6 +559,19 @@ $(document).ready(function () {
self._note("status-pass", msg, anchor)
+ def status_warning(self, msg, anchor=None):
+ """Write a note to the log file describing test(s) which passed.
+
+ Args:
+ msg: A message describing the passed test(s).
+ anchor: Optional internal link target.
+
+ Returns:
+ Nothing.
+ """
+
+ self._note("status-warning", msg, anchor)
+
def status_skipped(self, msg, anchor=None):
"""Write a note to the log file describing skipped test(s).
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 66b799bed66..b1ef6bd5811 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -25,6 +25,20 @@ def test_efi_selftest(u_boot_console):
u_boot_console.restart_uboot();
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
+@pytest.mark.buildconfigspec('of_control')
+def test_efi_selftest_device_tree(u_boot_console):
+ u_boot_console.run_command(cmd='setenv efi_selftest list')
+ output = u_boot_console.run_command('bootefi selftest')
+ assert '\'device tree\'' in output
+ u_boot_console.run_command(cmd='setenv efi_selftest device tree')
+ u_boot_console.run_command(cmd='setenv -f serial# Testing DT')
+ u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False)
+ m = u_boot_console.p.expect(['serial-number: Testing DT', 'U-Boot'])
+ if m != 0:
+ raise Exception('Reset failed in \'device tree\' test')
+ u_boot_console.restart_uboot();
+
+@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
def test_efi_selftest_watchdog_reboot(u_boot_console):
u_boot_console.run_command(cmd='setenv efi_selftest list')
output = u_boot_console.run_command('bootefi selftest')
diff --git a/test/py/tests/test_mmc_rd.py b/test/py/tests/test_mmc_rd.py
new file mode 100644
index 00000000000..7ff76228e2e
--- /dev/null
+++ b/test/py/tests/test_mmc_rd.py
@@ -0,0 +1,129 @@
+# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# Test U-Boot's "mmc read" command. The test reads data from the eMMC or SD
+# card, and validates the no errors occurred, and that the expected data was
+# read if the test configuration contains a CRC of the expected data.
+
+import pytest
+import u_boot_utils
+
+"""
+This test relies on boardenv_* to containing configuration values to define
+which MMC devices should be tested. For example:
+
+env__mmc_rd_configs = (
+ {
+ "fixture_id": "emmc-boot0",
+ "is_emmc": True,
+ "devid": 0,
+ "partid": 1,
+ "sector": 0x10,
+ "count": 1,
+ },
+ {
+ "fixture_id": "emmc-boot1",
+ "is_emmc": True,
+ "devid": 0,
+ "partid": 2,
+ "sector": 0x10,
+ "count": 1,
+ },
+ {
+ "fixture_id": "emmc-data",
+ "is_emmc": True,
+ "devid": 0,
+ "partid": 0,
+ "sector": 0x10,
+ "count": 0x1000,
+ },
+ {
+ "fixture_id": "sd-mbr",
+ "is_emmc": False,
+ "devid": 1,
+ "partid": None,
+ "sector": 0,
+ "count": 1,
+ "crc32": "8f6ecf0d",
+ },
+ {
+ "fixture_id": "sd-large",
+ "is_emmc": False,
+ "devid": 1,
+ "partid": None,
+ "sector": 0x10,
+ "count": 0x1000,
+ },
+)
+"""
+
+@pytest.mark.buildconfigspec('cmd_mmc')
+def test_mmc_rd(u_boot_console, env__mmc_rd_config):
+ """Test the "mmc read" command.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__mmc_rd_config: The single MMC configuration on which
+ to run the test. See the file-level comment above for details
+ of the format.
+
+ Returns:
+ Nothing.
+ """
+
+ is_emmc = env__mmc_rd_config['is_emmc']
+ devid = env__mmc_rd_config['devid']
+ partid = env__mmc_rd_config.get('partid', 0)
+ sector = env__mmc_rd_config.get('sector', 0)
+ count_sectors = env__mmc_rd_config.get('count', 1)
+ expected_crc32 = env__mmc_rd_config.get('crc32', None)
+
+ count_bytes = count_sectors * 512
+ bcfg = u_boot_console.config.buildconfig
+ has_cmd_memory = bcfg.get('config_cmd_memory', 'n') == 'y'
+ has_cmd_crc32 = bcfg.get('config_cmd_crc32', 'n') == 'y'
+ ram_base = u_boot_utils.find_ram_base(u_boot_console)
+ addr = '0x%08x' % ram_base
+
+ # Select MMC device
+ cmd = 'mmc dev %d' % devid
+ if is_emmc:
+ cmd += ' %d' % partid
+ response = u_boot_console.run_command(cmd)
+ assert 'no card present' not in response
+ if is_emmc:
+ partid_response = "(part %d)" % partid
+ else:
+ partid_response = ""
+ good_response = 'mmc%d%s is current device' % (devid, partid_response)
+ assert good_response in response
+
+ # Clear target RAM
+ if expected_crc32:
+ if has_cmd_memory and has_cmd_crc32:
+ cmd = 'mw.b %s 0 0x%x' % (addr, count_bytes)
+ u_boot_console.run_command(cmd)
+
+ cmd = 'crc32 %s 0x%x' % (addr, count_bytes)
+ response = u_boot_console.run_command(cmd)
+ assert expected_crc32 not in response
+ else:
+ u_boot_console.log.warning(
+ 'CONFIG_CMD_MEMORY or CONFIG_CMD_CRC32 != y: Skipping RAM clear')
+
+ # Read data
+ cmd = 'mmc read %s %x %x' % (addr, sector, count_sectors)
+ response = u_boot_console.run_command(cmd)
+ good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (
+ devid, sector, count_sectors, count_sectors)
+ assert good_response in response
+
+ # Check target RAM
+ if expected_crc32:
+ if has_cmd_crc32:
+ cmd = 'crc32 %s 0x%x' % (addr, count_bytes)
+ response = u_boot_console.run_command(cmd)
+ assert expected_crc32 in response
+ else:
+ u_boot_console.log.warning('CONFIG_CMD_CRC32 != y: Skipping check')
diff --git a/test/py/tests/test_sf.py b/test/py/tests/test_sf.py
new file mode 100644
index 00000000000..95a75649073
--- /dev/null
+++ b/test/py/tests/test_sf.py
@@ -0,0 +1,218 @@
+# Copyright (c) 2016, Xilinx Inc. Michal Simek
+# Copyright (c) 2017, Xiphos Systems Corp. All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import re
+import pytest
+import random
+import u_boot_utils
+
+"""
+Note: This test relies on boardenv_* containing configuration values to define
+which SPI Flash areas are available for testing. Without this, this test will
+be automatically skipped.
+For example:
+
+# A list of sections of Flash memory to be tested.
+env__sf_configs = (
+ {
+ # Where in SPI Flash should the test operate.
+ 'offset': 0x00000000,
+ # This value is optional.
+ # If present, specifies the [[bus:]cs] argument used in `sf probe`
+ # If missing, defaults to 0.
+ 'id': '0:1',
+ # This value is optional.
+ # If set as a number, specifies the speed of the SPI Flash.
+ # If set as an array of 2, specifies a range for a random speed.
+ # If missing, defaults to 0.
+ 'speed': 1000000,
+ # This value is optional.
+ # If present, specifies the size to use for read/write operations.
+ # If missing, the SPI Flash page size is used as a default (based on
+ # the `sf probe` output).
+ 'len': 0x10000,
+ # This value is optional.
+ # If present, specifies if the test can write to Flash offset
+ # If missing, defaults to False.
+ 'writeable': False,
+ # This value is optional.
+ # If present, specifies the expected CRC32 value of the flash area.
+ # If missing, extra check is ignored.
+ 'crc32': 0xCAFECAFE,
+ },
+)
+"""
+
+def sf_prepare(u_boot_console, env__sf_config):
+ """Check global state of the SPI Flash before running any test.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__sf_config: The single SPI Flash device configuration on which to
+ run the tests.
+
+ Returns:
+ sf_params: a dictionary of SPI Flash parameters.
+ """
+
+ sf_params = {}
+ sf_params['ram_base'] = u_boot_utils.find_ram_base(u_boot_console)
+
+ probe_id = env__sf_config.get('id', 0)
+ speed = env__sf_config.get('speed', 0)
+ if isinstance(speed, int):
+ sf_params['speed'] = speed
+ else:
+ assert len(speed) == 2, "If speed is a list, it must have 2 entries"
+ sf_params['speed'] = random.randint(speed[0], speed[1])
+
+ cmd = 'sf probe %d %d' % (probe_id, sf_params['speed'])
+
+ output = u_boot_console.run_command(cmd)
+ assert 'SF: Detected' in output, 'No Flash device available'
+
+ m = re.search('page size (.+?) Bytes', output)
+ assert m, 'SPI Flash page size not recognized'
+ sf_params['page_size'] = int(m.group(1))
+
+ m = re.search('erase size (.+?) KiB', output)
+ assert m, 'SPI Flash erase size not recognized'
+ sf_params['erase_size'] = int(m.group(1))
+ sf_params['erase_size'] *= 1024
+
+ m = re.search('total (.+?) MiB', output)
+ assert m, 'SPI Flash total size not recognized'
+ sf_params['total_size'] = int(m.group(1))
+ sf_params['total_size'] *= 1024 * 1024
+
+ assert 'offset' in env__sf_config, \
+ '\'offset\' is required for this test.'
+ sf_params['len'] = env__sf_config.get('len', sf_params['erase_size'])
+
+ assert not env__sf_config['offset'] % sf_params['erase_size'], \
+ 'offset not multiple of erase size.'
+ assert not sf_params['len'] % sf_params['erase_size'], \
+ 'erase length not multiple of erase size.'
+
+ assert not (env__sf_config.get('writeable', False) and
+ 'crc32' in env__sf_config), \
+ 'Cannot check crc32 on writeable sections'
+
+ return sf_params
+
+def sf_read(u_boot_console, env__sf_config, sf_params):
+ """Helper function used to read and compute the CRC32 value of a section of
+ SPI Flash memory.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__sf_config: The single SPI Flash device configuration on which to
+ run the tests.
+ sf_params: SPI Flash parameters.
+
+ Returns:
+ CRC32 value of SPI Flash section
+ """
+
+ addr = sf_params['ram_base']
+ offset = env__sf_config['offset']
+ count = sf_params['len']
+ pattern = random.randint(0, 0xFF)
+ crc_expected = env__sf_config.get('crc32', None)
+
+ cmd = 'mw.b %08x %02x %x' % (addr, pattern, count)
+ u_boot_console.run_command(cmd)
+ crc_pattern = u_boot_utils.crc32(u_boot_console, addr, count)
+ if crc_expected:
+ assert crc_pattern != crc_expected
+
+ cmd = 'sf read %08x %08x %x' % (addr, offset, count)
+ response = u_boot_console.run_command(cmd)
+ assert 'Read: OK' in response, 'Read operation failed'
+ crc_readback = u_boot_utils.crc32(u_boot_console, addr, count)
+ assert crc_pattern != crc_readback, 'sf read did not update RAM content.'
+ if crc_expected:
+ assert crc_readback == crc_expected
+
+ return crc_readback
+
+def sf_update(u_boot_console, env__sf_config, sf_params):
+ """Helper function used to update a section of SPI Flash memory.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ env__sf_config: The single SPI Flash device configuration on which to
+ run the tests.
+
+ Returns:
+ CRC32 value of SPI Flash section
+ """
+
+ addr = sf_params['ram_base']
+ offset = env__sf_config['offset']
+ count = sf_params['len']
+ pattern = int(random.random() * 0xFF)
+
+ cmd = 'mw.b %08x %02x %x' % (addr, pattern, count)
+ u_boot_console.run_command(cmd)
+ crc_pattern = u_boot_utils.crc32(u_boot_console, addr, count)
+
+ cmd = 'sf update %08x %08x %x' % (addr, offset, count)
+ u_boot_console.run_command(cmd)
+ crc_readback = sf_read(u_boot_console, env__sf_config, sf_params)
+
+ assert crc_readback == crc_pattern
+
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('cmd_crc32')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_sf_read(u_boot_console, env__sf_config):
+ sf_params = sf_prepare(u_boot_console, env__sf_config)
+ sf_read(u_boot_console, env__sf_config, sf_params)
+
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('cmd_crc32')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_sf_read_twice(u_boot_console, env__sf_config):
+ sf_params = sf_prepare(u_boot_console, env__sf_config)
+
+ crc1 = sf_read(u_boot_console, env__sf_config, sf_params)
+ sf_params['ram_base'] += 0x100
+ crc2 = sf_read(u_boot_console, env__sf_config, sf_params)
+
+ assert crc1 == crc2, 'CRC32 of two successive read operation do not match'
+
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('cmd_crc32')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_sf_erase(u_boot_console, env__sf_config):
+ if not env__sf_config.get('writeable', False):
+ pytest.skip('Flash config is tagged as not writeable')
+
+ sf_params = sf_prepare(u_boot_console, env__sf_config)
+ addr = sf_params['ram_base']
+ offset = env__sf_config['offset']
+ count = sf_params['len']
+
+ cmd = 'sf erase %08x %x' % (offset, count)
+ output = u_boot_console.run_command(cmd)
+ assert 'Erased: OK' in output, 'Erase operation failed'
+
+ cmd = 'mw.b %08x ff %x' % (addr, count)
+ u_boot_console.run_command(cmd)
+ crc_ffs = u_boot_utils.crc32(u_boot_console, addr, count)
+
+ crc_read = sf_read(u_boot_console, env__sf_config, sf_params)
+ assert crc_ffs == crc_read, 'Unexpected CRC32 after erase operation.'
+
+@pytest.mark.buildconfigspec('cmd_sf')
+@pytest.mark.buildconfigspec('cmd_crc32')
+@pytest.mark.buildconfigspec('cmd_memory')
+def test_sf_update(u_boot_console, env__sf_config):
+ if not env__sf_config.get('writeable', False):
+ pytest.skip('Flash config is tagged as not writeable')
+
+ sf_params = sf_prepare(u_boot_console, env__sf_config)
+ sf_update(u_boot_console, env__sf_config, sf_params)
diff --git a/test/py/u_boot_utils.py b/test/py/u_boot_utils.py
index 9acb92ddc44..de9ee2643f5 100644
--- a/test/py/u_boot_utils.py
+++ b/test/py/u_boot_utils.py
@@ -11,7 +11,7 @@ import os.path
import pytest
import sys
import time
-import pytest
+import re
def md5sum_data(data):
"""Calculate the MD5 hash of some data.
@@ -311,3 +311,25 @@ def persistent_file_helper(u_boot_log, filename):
"""
return PersistentFileHelperCtxMgr(u_boot_log, filename)
+
+def crc32(u_boot_console, address, count):
+ """Helper function used to compute the CRC32 value of a section of RAM.
+
+ Args:
+ u_boot_console: A U-Boot console connection.
+ address: Address where data starts.
+ count: Amount of data to use for calculation.
+
+ Returns:
+ CRC32 value
+ """
+
+ bcfg = u_boot_console.config.buildconfig
+ has_cmd_crc32 = bcfg.get('config_cmd_crc32', 'n') == 'y'
+ assert has_cmd_crc32, 'Cannot compute crc32 without CONFIG_CMD_CRC32.'
+ output = u_boot_console.run_command('crc32 %08x %x' % (address, count))
+
+ m = re.search('==> ([0-9a-fA-F]{8})$', output)
+ assert m, 'CRC32 operation failed.'
+
+ return m.group(1)