diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index 048542bf31b..7889e09e8f5 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -42,6 +42,20 @@ #error "Unsupported configuraiton" #endif +#define TEST_FLASH_START (DT_REG_ADDR(DT_CHOSEN(zephyr_flash))) +#if (DT_PROP(DT_CHOSEN(zephyr_flash), size)) +/* When flash is defined in DTS as: + * size = < 0x4000000 >; + * reg = < 0x0 >; + */ +#define TEST_FLASH_SIZE (DT_PROP(DT_CHOSEN(zephyr_flash), size)) +#else +/* When flash is defined in DTS as: + * reg = < 0xe000000 0x200000 >; + */ +#define TEST_FLASH_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash))) +#endif /* #if (DT_PROP(DT_CHOSEN(zephyr_flash), size)) */ + #define EXPECTED_SIZE 512 #if !defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && \ @@ -253,5 +267,273 @@ ZTEST(flash_driver, test_flash_flatten) zassert_equal(i, EXPECTED_SIZE, "Expected device to be filled wth 0xaa"); } +ZTEST(flash_driver, test_flash_erase) +{ + int rc; + uint8_t read_buf[EXPECTED_SIZE]; + bool comparison_result; + const struct flash_parameters *fparams = flash_get_parameters(flash_dev); + + erase_value = fparams->erase_value; + + /* Write test data */ + rc = flash_write(flash_dev, page_info.start_offset, expected, EXPECTED_SIZE); + zassert_equal(rc, 0, "Cannot write to flash"); + + /* Confirm write operation */ + rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE); + zassert_equal(rc, 0, "Cannot read flash"); + + comparison_result = true; + for (int i = 0; i < EXPECTED_SIZE; i++) { + if (read_buf[i] != expected[i]) { + comparison_result = false; + TC_PRINT("i=%d:\tread_buf[i]=%d\texpected[i]=%d\n", i, read_buf[i], + expected[i]); + } + } + zassert_true(comparison_result, "Write operation failed"); + /* Cross check - confirm that expected data is pseudo-random */ + zassert_not_equal(read_buf[0], expected[1], "These values shall be different"); + + /* Erase a nb of pages aligned to the EXPECTED_SIZE */ + rc = flash_erase( + flash_dev, page_info.start_offset, + (page_info.size * ((EXPECTED_SIZE + page_info.size - 1) / page_info.size))); + zassert_equal(rc, 0, "Flash memory not properly erased"); + + /* Confirm erase operation */ + rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE); + zassert_equal(rc, 0, "Cannot read flash"); + + comparison_result = true; + for (int i = 0; i < EXPECTED_SIZE; i++) { + if (read_buf[i] != erase_value) { + comparison_result = false; + TC_PRINT("i=%d:\tread_buf[i]=%d\texpected=%d\n", i, read_buf[i], + erase_value); + } + } + zassert_true(comparison_result, "Write operation failed"); + /* Cross check - confirm that expected data + * doesn't contain erase_value + */ + zassert_not_equal(expected[0], erase_value, "These values shall be different"); +} + +ZTEST(flash_driver, test_negative_flash_erase) +{ + int rc; + +#if !defined(TEST_AREA) + /* Flash memory boundaries are correctly calculated + * only for storage_partition. + */ + ztest_test_skip(); +#endif + + TC_PRINT("TEST_FLASH_START = 0x%lx\n", (unsigned long)TEST_FLASH_START); + TC_PRINT("TEST_FLASH_SIZE = 0x%lx\n", (unsigned long)TEST_FLASH_SIZE); + + /* Check error returned when erasing memory at wrong address (too low) */ + rc = flash_erase(flash_dev, (TEST_FLASH_START - 1), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc); + + /* Check error returned when erasing memory at wrong address (too high) */ + rc = flash_erase(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc); + + /* Check error returned when erasing to large chunk of memory */ + rc = flash_erase(flash_dev, TEST_AREA_OFFSET, (TEST_FLASH_SIZE - TEST_AREA_OFFSET + 1)); + zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc); + + /* Erasing 0 bytes shall succeed */ + rc = flash_erase(flash_dev, TEST_AREA_OFFSET, 0); + zassert_true(rc == 0, "flash_erase 0 bytes returned %d", rc); +} + +ZTEST(flash_driver, test_negative_flash_fill) +{ + int rc; + uint8_t fill_val = 0xA; /* Dummy value */ + +#if !defined(TEST_AREA) + /* Flash memory boundaries are correctly calculated + * only for storage_partition. + */ + ztest_test_skip(); +#endif + + /* Check error returned when filling memory at wrong address (too low) */ + rc = flash_fill(flash_dev, fill_val, (TEST_FLASH_START - 1), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc); + + /* Check error returned when filling memory at wrong address (too high) */ + rc = flash_fill(flash_dev, fill_val, (TEST_FLASH_START + TEST_FLASH_SIZE), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc); + + /* Check error returned when filling to large chunk of memory */ + rc = flash_fill(flash_dev, fill_val, TEST_AREA_OFFSET, + (TEST_FLASH_SIZE - TEST_AREA_OFFSET + 1)); + zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc); + + /* Filling 0 bytes shall succeed */ + rc = flash_fill(flash_dev, fill_val, TEST_AREA_OFFSET, 0); + zassert_true(rc == 0, "flash_fill 0 bytes returned %d", rc); +} + +ZTEST(flash_driver, test_negative_flash_flatten) +{ + int rc; + +#if !defined(TEST_AREA) + /* Flash memory boundaries are correctly calculated + * only for storage_partition. + */ + ztest_test_skip(); +#endif + + /* Check error returned when flatten memory at wrong address (too low) */ + rc = flash_flatten(flash_dev, (TEST_FLASH_START - 1), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc); + + /* Check error returned when flatten memory at wrong address (too high) */ + rc = flash_flatten(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc); + + /* Check error returned when flatten to large chunk of memory */ + rc = flash_flatten(flash_dev, TEST_AREA_OFFSET, (TEST_FLASH_SIZE - TEST_AREA_OFFSET + 1)); + zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc); + + /* Flatten 0 bytes shall succeed */ + rc = flash_flatten(flash_dev, TEST_AREA_OFFSET, 0); + zassert_true(rc == 0, "flash_flatten 0 bytes returned %d", rc); +} + +ZTEST(flash_driver, test_negative_flash_read) +{ + int rc; + uint8_t read_buf[EXPECTED_SIZE]; + +#if !defined(TEST_AREA) + /* Flash memory boundaries are correctly calculated + * only for storage_partition. + */ + ztest_test_skip(); +#endif + + /* Check error returned when reading from a wrong address (too low) */ + rc = flash_read(flash_dev, (TEST_FLASH_START - 1), read_buf, EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc); + + /* Check error returned when reading from a wrong address (too high) */ + rc = flash_read(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), read_buf, EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc); + + /* Check error returned when reading too many data */ + rc = flash_read(flash_dev, TEST_AREA_OFFSET, read_buf, + (TEST_FLASH_SIZE - TEST_AREA_OFFSET + 1)); + zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc); + + /* Reading 0 bytes shall succeed */ + rc = flash_read(flash_dev, TEST_AREA_OFFSET, read_buf, 0); + zassert_true(rc == 0, "flash_read 0 bytes returned %d", rc); +} + +ZTEST(flash_driver, test_negative_flash_write) +{ + int rc; + +#if !defined(TEST_AREA) + /* Flash memory boundaries are correctly calculated + * only for storage_partition. + */ + ztest_test_skip(); +#endif + + /* Check error returned when writing to a wrong address (too low) */ + rc = flash_write(flash_dev, (TEST_FLASH_START - 1), expected, EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc); + + /* Check error returned when writing to a wrong address (too high) */ + rc = flash_write(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), expected, EXPECTED_SIZE); + zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc); + + /* Check error returned when writing too many data */ + rc = flash_write(flash_dev, TEST_AREA_OFFSET, expected, + (TEST_FLASH_SIZE - TEST_AREA_OFFSET + 1)); + zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc); + + /* Writing 0 bytes shall succeed */ + rc = flash_write(flash_dev, TEST_AREA_OFFSET, expected, 0); + zassert_true(rc == 0, "flash_write 0 bytes returned %d", rc); +} + +struct test_cb_data_type { + uint32_t page_counter; /* used to count how many pages was iterated */ + uint32_t exit_page; /* terminate iteration when this page is reached */ +}; + +static bool flash_callback(const struct flash_pages_info *info, void *data) +{ + struct test_cb_data_type *cb_data = (struct test_cb_data_type *)data; + + cb_data->page_counter++; + + if (cb_data->page_counter >= cb_data->exit_page) { + return false; + } + + return true; +} + +ZTEST(flash_driver, test_flash_page_layout) +{ + int rc; + struct flash_pages_info page_info_off = {0}; + struct flash_pages_info page_info_idx = {0}; + size_t page_count; + struct test_cb_data_type test_cb_data = {0}; + +#if !defined(CONFIG_FLASH_PAGE_LAYOUT) + ztest_test_skip(); +#endif + + /* Get page info with flash_get_page_info_by_offs() */ + rc = flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET, &page_info_off); + zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc); + TC_PRINT("start_offset=0x%lx\tsize=%d\tindex=%d\n", page_info_off.start_offset, + (int)page_info_off.size, page_info_off.index); + zassert_true(page_info_off.start_offset >= 0, "start_offset is %d", rc); + zassert_true(page_info_off.size > 0, "size is %d", rc); + zassert_true(page_info_off.index >= 0, "index is %d", rc); + + /* Get info for the same page with flash_get_page_info_by_idx() */ + rc = flash_get_page_info_by_idx(flash_dev, page_info_off.index, &page_info_idx); + zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc); + zassert_equal(page_info_off.start_offset, page_info_idx.start_offset); + zassert_equal(page_info_off.size, page_info_idx.size); + zassert_equal(page_info_off.index, page_info_idx.index); + + page_count = flash_get_page_count(flash_dev); + TC_PRINT("page_count=%d\n", (int)page_count); + zassert_true(page_count > 0, "flash_get_page_count returned %d", rc); + zassert_true(page_count >= page_info_off.index); + + /* Test that callback is executed for every page */ + test_cb_data.exit_page = page_count + 1; + flash_page_foreach(flash_dev, flash_callback, &test_cb_data); + zassert_true(page_count == test_cb_data.page_counter, + "page_count = %d not equal to pages counted with cb = %d", page_count, + test_cb_data.page_counter); + + /* Test that callback can cancell iteration */ + test_cb_data.page_counter = 0; + test_cb_data.exit_page = page_count >> 1; + flash_page_foreach(flash_dev, flash_callback, &test_cb_data); + zassert_true(test_cb_data.exit_page == test_cb_data.page_counter, + "%d pages were iterated while it shall stop on page %d", + test_cb_data.page_counter, test_cb_data.exit_page); +} ZTEST_SUITE(flash_driver, NULL, flash_driver_setup, NULL, NULL, NULL); diff --git a/tests/drivers/flash/common/testcase.yaml b/tests/drivers/flash/common/testcase.yaml index 028383fb5f8..487c8cd97fe 100644 --- a/tests/drivers/flash/common/testcase.yaml +++ b/tests/drivers/flash/common/testcase.yaml @@ -31,13 +31,15 @@ tests: - nrf52840dk/nrf52840 drivers.flash.common.default: filter: ((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE) - and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) + and (dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions") + or dt_label_with_parent_compat_enabled("storage_partition", "nordic,owned-partitions"))) integration_platforms: - qemu_x86 - mimxrt1060_evk drivers.flash.common.no_explicit_erase: platform_allow: - nrf54l15pdk/nrf54l15/cpuapp + - nrf54h20dk/nrf54h20/cpuapp drivers.flash.common.tfm_ns: build_only: true filter: (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE