[sw] - Update flash sanity test for info partitions as well
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/sw/device/boot_rom/bootstrap.c b/sw/device/boot_rom/bootstrap.c
index 2566669..9d8ea78 100644
--- a/sw/device/boot_rom/bootstrap.c
+++ b/sw/device/boot_rom/bootstrap.c
@@ -112,7 +112,7 @@
LOG_INFO("Flash erase successful");
}
- if (flash_write(frame.header.flash_offset, frame.data,
+ if (flash_write(frame.header.flash_offset, kDataPartition, frame.data,
SPIFLASH_FRAME_DATA_WORDS) != 0) {
return E_BS_WRITE;
}
diff --git a/sw/device/lib/flash_ctrl.c b/sw/device/lib/flash_ctrl.c
index 39fbb08..a1419e1 100644
--- a/sw/device/lib/flash_ctrl.c
+++ b/sw/device/lib/flash_ctrl.c
@@ -5,7 +5,6 @@
#include "flash_ctrl_regs.h" // Generated.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
-
#include "sw/device/lib/common.h"
#define FLASH_CTRL0_BASE_ADDR TOP_EARLGREY_FLASH_CTRL_BASE_ADDR
@@ -82,22 +81,24 @@
return get_clr_err();
}
-int flash_page_erase(uint32_t addr) {
+int flash_page_erase(uint32_t addr, part_type_t part) {
REG32(FLASH_CTRL_ADDR(0)) = addr;
REG32(FLASH_CTRL_CONTROL(0)) = FLASH_ERASE << FLASH_CTRL_CONTROL_OP_OFFSET |
FLASH_PAGE_ERASE
<< FLASH_CTRL_CONTROL_ERASE_SEL |
+ part << FLASH_CTRL_CONTROL_PARTITION_SEL |
0x1 << FLASH_CTRL_CONTROL_START;
wait_done_and_ack();
return get_clr_err();
}
-static int flash_write_internal(uint32_t addr, const uint32_t *data,
- uint32_t size) {
+static int flash_write_internal(uint32_t addr, part_type_t part,
+ const uint32_t *data, uint32_t size) {
// TODO: Do we need to select bank as part of the write?
// TODO: Update with address alignment requirements.
REG32(FLASH_CTRL_ADDR(0)) = addr;
REG32(FLASH_CTRL_CONTROL(0)) = (FLASH_PROG << FLASH_CTRL_CONTROL_OP_OFFSET |
+ part << FLASH_CTRL_CONTROL_PARTITION_SEL |
(size - 1) << FLASH_CTRL_CONTROL_NUM_OFFSET |
0x1 << FLASH_CTRL_CONTROL_START);
for (int i = 0; i < size; ++i) {
@@ -107,14 +108,16 @@
return get_clr_err();
}
-int flash_write(uint32_t addr, const uint32_t *data, uint32_t size) {
+int flash_write(uint32_t addr, part_type_t part, const uint32_t *data,
+ uint32_t size) {
// TODO: Breakdown into FIFO chunks if needed.
- return flash_write_internal(addr, data, size);
+ return flash_write_internal(addr, part, data, size);
}
-int flash_read(uint32_t addr, uint32_t size, uint32_t *data) {
+int flash_read(uint32_t addr, part_type_t part, uint32_t size, uint32_t *data) {
REG32(FLASH_CTRL_ADDR(0)) = addr;
REG32(FLASH_CTRL_CONTROL(0)) = FLASH_READ << FLASH_CTRL_CONTROL_OP_OFFSET |
+ part << FLASH_CTRL_CONTROL_PARTITION_SEL |
(size - 1) << FLASH_CTRL_CONTROL_NUM_OFFSET |
0x1 << FLASH_CTRL_CONTROL_START;
for (uint32_t i = 0; i < size;) {
@@ -145,6 +148,7 @@
REG32(FLASH_CTRL_MP_REGION_CFG0(0) + region_cfg->num * 4) =
region_cfg->base << FLASH_CTRL_MP_REGION_CFG0_BASE0_OFFSET |
region_cfg->size << FLASH_CTRL_MP_REGION_CFG0_SIZE0_OFFSET |
+ region_cfg->part << FLASH_CTRL_MP_REGION_CFG0_PARTITION0 |
region_cfg->rd_en << FLASH_CTRL_MP_REGION_CFG0_RD_EN0 |
region_cfg->prog_en << FLASH_CTRL_MP_REGION_CFG0_PROG_EN0 |
region_cfg->erase_en << FLASH_CTRL_MP_REGION_CFG0_ERASE_EN0 |
diff --git a/sw/device/lib/flash_ctrl.h b/sw/device/lib/flash_ctrl.h
index f15d197..cad7cb9 100644
--- a/sw/device/lib/flash_ctrl.h
+++ b/sw/device/lib/flash_ctrl.h
@@ -22,6 +22,14 @@
typedef enum bank_index { FLASH_BANK_0 = 0, FLASH_BANK_1 = 1 } bank_index_t;
/**
+ * Flash partitions
+ */
+typedef enum partition_type {
+ kDataPartition = 0,
+ kInfoPartition = 1
+} part_type_t;
+
+/**
* Memory protection configuration options.
*/
typedef struct mp_region {
@@ -31,6 +39,8 @@
uint32_t base;
/** Region config size. */
uint32_t size;
+ /** Region partition size. */
+ part_type_t part;
/** Read enable flag. */
uint32_t rd_en;
/** Program enable flag. */
@@ -56,27 +66,30 @@
* @return Non zero on failure.
*/
int flash_bank_erase(bank_index_t idx);
-int flash_page_erase(uint32_t addr);
+int flash_page_erase(uint32_t addr, part_type_t part);
/**
* Write `data` at `addr` offset with `size` in 4B words
*
* @param addr Flash address 32bit aligned.
+ * @param part Flash parittion to access.
* @param data Data to write.
* @param size Number of 4B words to write from `data` buffer.
* @return Non zero on failure.
*/
-int flash_write(uint32_t addr, const uint32_t *data, uint32_t size);
+int flash_write(uint32_t addr, part_type_t part, const uint32_t *data,
+ uint32_t size);
/**
* Read `size` 4B words and write result to `data`.
*
* @param addr Read start address.
+ * @param part Flash parittion to access.
* @param size Number of 4B words to read.
* @param data Output buffer.
* @return Non zero on failure.
*/
-int flash_read(uint32_t addr, uint32_t size, uint32_t *data);
+int flash_read(uint32_t addr, part_type_t part, uint32_t size, uint32_t *data);
/**
* Configure bank erase enable
diff --git a/sw/device/tests/flash_ctrl_test.c b/sw/device/tests/flash_ctrl_test.c
index 6a40cc1..5f54baf 100644
--- a/sw/device/tests/flash_ctrl_test.c
+++ b/sw/device/tests/flash_ctrl_test.c
@@ -24,19 +24,40 @@
#define CHECK_EQZ(x) CHECK((x) == 0)
#define CHECK_NEZ(x) CHECK((x) != 0)
+/*
+ * Basic test of page erase / program / read functions
+ * Tests pages from both the data and info partitions
+ */
static void test_basic_io(void) {
+ // setup default access for data partition
flash_default_region_access(/*rd_en=*/true, /*prog_en=*/true,
/*erase_en=*/true);
+ // info partition has no default access, specifically setup a region
+ mp_region_t info_region = {
+ .num = 0x0,
+ .base = FLASH_PAGES_PER_BANK,
+ .size = 0x1,
+ .part = kInfoPartition,
+ .rd_en = true,
+ .prog_en = true,
+ .erase_en = true,
+ };
+ flash_cfg_region(&info_region);
+
uintptr_t flash_bank_1_addr = FLASH_MEM_BASE_ADDR + FLASH_BANK_SZ;
mmio_region_t flash_bank_1 = mmio_region_from_addr(flash_bank_1_addr);
- // Test erasing flash; this should turn the whole bank to all ones.
- CHECK_EQZ(flash_page_erase(flash_bank_1_addr));
+ // Test erasing flash data partition; this should turn the whole bank to all
+ // ones.
+ CHECK_EQZ(flash_page_erase(flash_bank_1_addr, kDataPartition));
for (int i = 0; i < FLASH_WORDS_PER_PAGE; ++i) {
CHECK_EQZ(~mmio_region_read32(flash_bank_1, i * sizeof(uint32_t)));
}
+ // Erasing flash info partition; this should turn the whole bank to all ones.
+ CHECK_EQZ(flash_page_erase(flash_bank_1_addr, kInfoPartition));
+
// Prepare an entire page of non-trivial data to program
// into flash.
uint32_t input_page[FLASH_WORDS_PER_PAGE];
@@ -48,20 +69,34 @@
// Attempt to live-program an entire page, where the overall
// payload is much larger than the internal flash FIFO.
- CHECK_EQZ(flash_page_erase(flash_bank_1_addr));
+ CHECK_EQZ(flash_page_erase(flash_bank_1_addr, kDataPartition));
+ CHECK_EQZ(flash_write(flash_bank_1_addr, kDataPartition, input_page,
+ FLASH_WORDS_PER_PAGE));
+ CHECK_EQZ(flash_read(flash_bank_1_addr, kDataPartition, FLASH_WORDS_PER_PAGE,
+ output_page));
+ CHECK_ARRAYS_EQ(output_page, input_page, FLASH_WORDS_PER_PAGE);
- CHECK_EQZ(flash_write(flash_bank_1_addr, input_page, FLASH_WORDS_PER_PAGE));
- CHECK_EQZ(flash_read(flash_bank_1_addr, FLASH_WORDS_PER_PAGE, output_page));
-
+ // Similar check for info page
+ CHECK_EQZ(flash_page_erase(flash_bank_1_addr, kInfoPartition));
+ CHECK_EQZ(flash_write(flash_bank_1_addr, kInfoPartition, input_page,
+ FLASH_WORDS_PER_PAGE));
+ CHECK_EQZ(flash_read(flash_bank_1_addr, kInfoPartition, FLASH_WORDS_PER_PAGE,
+ output_page));
CHECK_ARRAYS_EQ(output_page, input_page, FLASH_WORDS_PER_PAGE);
uintptr_t flash_bank_0_last_page_addr = flash_bank_1_addr - FLASH_PAGE_SZ;
- CHECK_EQZ(flash_page_erase(flash_bank_0_last_page_addr));
+ mmio_region_t flash_bank_0_last_page =
+ mmio_region_from_addr(flash_bank_0_last_page_addr);
+ CHECK_EQZ(flash_page_erase(flash_bank_0_last_page_addr, kDataPartition));
+ for (int i = 0; i < FLASH_WORDS_PER_PAGE; ++i) {
+ CHECK_EQZ(
+ ~mmio_region_read32(flash_bank_0_last_page, i * sizeof(uint32_t)));
+ }
- CHECK_EQZ(flash_write(flash_bank_0_last_page_addr, input_page,
+ CHECK_EQZ(flash_write(flash_bank_0_last_page_addr, kDataPartition, input_page,
FLASH_WORDS_PER_PAGE));
- CHECK_EQZ(flash_read(flash_bank_0_last_page_addr, FLASH_WORDS_PER_PAGE,
- output_page));
+ CHECK_EQZ(flash_read(flash_bank_0_last_page_addr, kDataPartition,
+ FLASH_WORDS_PER_PAGE, output_page));
CHECK_ARRAYS_EQ(output_page, input_page, FLASH_WORDS_PER_PAGE);
}
@@ -75,6 +110,7 @@
.num = 0x0,
.base = FLASH_PAGES_PER_BANK,
.size = 0x1,
+ .part = kDataPartition,
.rd_en = true,
.prog_en = true,
.erase_en = true,
@@ -89,8 +125,8 @@
uintptr_t bad_region_start = ok_region_end;
// Erase good and bad regions.
- CHECK_EQZ(flash_page_erase(ok_region_start));
- CHECK_EQZ(flash_page_erase(bad_region_start));
+ CHECK_EQZ(flash_page_erase(ok_region_start, kDataPartition));
+ CHECK_EQZ(flash_page_erase(bad_region_start, kDataPartition));
// Turn off flash access by default.
flash_default_region_access(/*rd_en=*/false, /*prog_en=*/false,
@@ -108,7 +144,8 @@
}
// Perform a partial write.
- CHECK_NEZ(flash_write(region_boundary_start, words, ARRAYSIZE(words)));
+ CHECK_NEZ(flash_write(region_boundary_start, kDataPartition, words,
+ ARRAYSIZE(words)));
// Words in the good region should still match, while words in the bad
// region should be all-ones, since we erased
for (int i = 0; i < ARRAYSIZE(words); ++i) {
@@ -121,10 +158,10 @@
}
// Attempt to erase bad page, which should fail.
- CHECK_NEZ(flash_page_erase(bad_region_start));
+ CHECK_NEZ(flash_page_erase(bad_region_start, kDataPartition));
// Attempt to erase the good page, which should succeed.
- CHECK_EQZ(flash_page_erase(ok_region_start));
+ CHECK_EQZ(flash_page_erase(ok_region_start, kDataPartition));
for (int i = 0; i < FLASH_WORDS_PER_PAGE; i++) {
CHECK_EQZ(~mmio_region_read32(ok_region, i * sizeof(uint32_t)));
}