aboutsummaryrefslogtreecommitdiff
path: root/tests/pflash-cfi02-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/pflash-cfi02-test.c')
-rw-r--r--tests/pflash-cfi02-test.c110
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);
}