diff options
Diffstat (limited to 'tests/pflash-cfi02-test.c')
-rw-r--r-- | tests/pflash-cfi02-test.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c index 303bc87820..d3b23f4f66 100644 --- a/tests/pflash-cfi02-test.c +++ b/tests/pflash-cfi02-test.c @@ -43,6 +43,8 @@ typedef struct { #define CHIP_ERASE_CMD 0x10 #define UNLOCK_BYPASS_CMD 0x20 #define UNLOCK_BYPASS_RESET_CMD 0x00 +#define ERASE_SUSPEND_CMD 0xB0 +#define ERASE_RESUME_CMD SECTOR_ERASE_CMD typedef struct { int bank_width; @@ -241,6 +243,16 @@ static void chip_erase(const FlashConfig *c) flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD); } +static void erase_suspend(const FlashConfig *c) +{ + flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD); +} + +static void erase_resume(const FlashConfig *c) +{ + flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD); +} + /* * Test flash commands with a variety of device geometry. */ @@ -312,11 +324,20 @@ static void test_geometry(const void *opaque) uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27)); g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE); + /* Check that erase suspend to read/write is supported. */ + uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) + + (flash_query_1(c, FLASH_ADDR(0x16)) << 8); + g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions); + g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P')); + g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R')); + g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I')); + g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */ reset(c); const uint64_t dq7 = replicate(c, 0x80); const uint64_t dq6 = replicate(c, 0x40); const uint64_t dq3 = replicate(c, 0x08); + const uint64_t dq2 = replicate(c, 0x04); uint64_t byte_addr = 0; for (int region = 0; region < nb_erase_regions; ++region) { @@ -456,6 +477,95 @@ static void test_geometry(const void *opaque) } } + /* Test erase suspend/resume during erase timeout. */ + sector_erase(c, 0); + /* + * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being + * erased as well as in a sector not being erased. + */ + byte_addr = c->sector_len[0]; + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq3, ==, 0); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + status0 = flash_read(c, byte_addr); + status1 = flash_read(c, byte_addr); + g_assert_cmpint(status0 & dq3, ==, 0); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + + /* + * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in + * an erase suspended sector but that neither toggle (we should be + * getting data) in a sector not being erased. + */ + erase_suspend(c); + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq6, ==, status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); + + /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ + erase_resume(c); + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + status0 = flash_read(c, byte_addr); + status1 = flash_read(c, byte_addr); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + wait_for_completion(c, 0); + + /* Repeat this process but this time suspend after the timeout. */ + sector_erase(c, 0); + qtest_clock_step_next(c->qtest); + /* + * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being + * erased as well as in a sector not being erased. + */ + byte_addr = c->sector_len[0]; + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + status0 = flash_read(c, byte_addr); + status1 = flash_read(c, byte_addr); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + + /* + * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in + * an erase suspended sector but that neither toggle (we should be + * getting data) in a sector not being erased. + */ + erase_suspend(c); + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq6, ==, status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr)); + + /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */ + erase_resume(c); + status0 = flash_read(c, 0); + status1 = flash_read(c, 0); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + status0 = flash_read(c, byte_addr); + status1 = flash_read(c, byte_addr); + g_assert_cmpint(status0 & dq3, ==, dq3); + g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6); + g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2); + wait_for_completion(c, 0); + qtest_quit(qtest); } |