// -----------------------------------------------------------------------------
+typedef struct
+{
+ uint32_t block_size;
+ uint32_t block_count;
+ uint8_t block_is_erased[0x10000];
+} erase_region_t;
+
+
+typedef struct
+{
+ uint8_t region_count;
+ erase_region_t regions[256];
+} erase_info_t;
+
+
+static erase_info_t erase_info;
+
+
+bool get_erase_info(HIF hif)
+{
+ assert(hif != hifInvalid);
+
+ uint8_t cfi_buf[0x100];
+
+ // Read and verify CFI query information
+ EC_FALSE(flash_cfi(hif, 0, cfi_buf, sizeof(cfi_buf)));
+ EC_FALSE(cfi_buf[0x10] == 'Q');
+ EC_FALSE(cfi_buf[0x11] == 'R');
+ EC_FALSE(cfi_buf[0x12] == 'Y');
+
+ // Flash chips can contain multiple "erase regions," each of which
+ // contains some number of equal-sized eraseable blocks
+
+ // Read the number of regions from the CFI query and loop for each
+ erase_info.region_count = cfi_buf[0x2c];
+
+ for (size_t i = 0; i < erase_info.region_count; i++)
+ {
+ size_t block_info_idx = 0x2d + (4 * i);
+ assert(block_info_idx < 0x100); // Just in case
+
+ // Read the geometry of this region's blocks from the CFI query
+ uint32_t block_count = ((cfi_buf[block_info_idx + 1] << 8) |
+ cfi_buf[block_info_idx + 0]) + 1;
+ uint32_t block_size = ((cfi_buf[block_info_idx + 3] << 8) |
+ cfi_buf[block_info_idx + 2]) * 256;
+ if (block_size == 0) block_size = 128;
+
+ erase_info.regions[i].block_size = block_size;
+ erase_info.regions[i].block_count = block_count;
+ }
+
+ return true;
+
+EC_CLEANUP_BEGIN
+ return false;
+EC_CLEANUP_END
+}
+
+
+bool ensure_erased(HIF hif, uint32_t addr, size_t data_len)
+{
+ assert(hif != hifInvalid);
+
+ uint32_t scan_addr = 0;
+
+ uint32_t region_count = erase_info.region_count;
+ for (uint32_t i = 0; i < region_count; i++)
+ {
+ uint32_t block_count = erase_info.regions[i].block_count;
+ for (uint32_t j = 0; j < block_count; j++)
+ {
+ uint32_t block_size = erase_info.regions[i].block_size;
+ uint32_t block_start = scan_addr;
+ uint32_t block_end = scan_addr + block_size;
+
+ uint32_t data_start = addr;
+ uint32_t data_end = data_start + data_len;
+
+ if (data_start < block_end && data_end > block_start)
+ {
+ if (!erase_info.regions[i].block_is_erased[j])
+ {
+ printf("Erase region:%u of %u, block:%u of %u, addr:%08x size:%08x\n",
+ i+1, region_count,
+ j+1, block_count,
+ block_start, block_size);
+ EC_FALSE(flash_erase(hif, scan_addr));
+ erase_info.regions[i].block_is_erased[j] = 1;
+ }
+ }
+ scan_addr = block_end;
+ }
+ }
+
+ return true;
+
+EC_CLEANUP_BEGIN
+ return false;
+EC_CLEANUP_END
+}
+
+
+// -----------------------------------------------------------------------------
+
+
bool update_ram_read(HIF hif, struct iter *iter, uint32_t addr, size_t data_len)
{
assert(hif != hifInvalid);
assert(hif != hifInvalid);
assert(iter != NULL);
- uint32_t unerased_watermark = 0;
- uint8_t cfi_buf[0x100];
- uint8_t num_erase_regions;
-
- // Read and verify CFI query information
- EC_FALSE(flash_cfi(hif, 0, cfi_buf, sizeof(cfi_buf)));
- EC_FALSE(cfi_buf[0x10] == 'Q');
- EC_FALSE(cfi_buf[0x11] == 'R');
- EC_FALSE(cfi_buf[0x12] == 'Y');
-
- // Read the number of regions from the CFI query and loop for each
- num_erase_regions = cfi_buf[0x2c];
+ if (erase) EC_FALSE(get_erase_info(hif));
while (!iter_done(iter))
{
EC_FALSE(iter_next(iter));
if (erase)
{
- // TODO
+ EC_FALSE(ensure_erased(hif, iter->address, iter->data_len));
}
EC_FALSE(flash_write(hif, iter->address, iter->data, iter->data_len));