summary refs log tree commit diff
path: root/drivers/wear_leveling
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2022-06-30 07:42:23 +1000
committerGitHub <noreply@github.com>2022-06-30 07:42:23 +1000
commit34e244cecf62afb30ee5a4362867f24b03675691 (patch)
tree5e349edd1e2749a2f158011f6cbf3fed3c054203 /drivers/wear_leveling
parent1204cbb7ea53ff1e4e2aeb45e2cd0f371d30dcec (diff)
Wear-leveling EEPROM drivers: `embedded_flash`, `spi_flash`, `legacy` (#17376)
Diffstat (limited to 'drivers/wear_leveling')
-rw-r--r--drivers/wear_leveling/wear_leveling_flash_spi.c101
-rw-r--r--drivers/wear_leveling/wear_leveling_flash_spi_config.h34
2 files changed, 135 insertions, 0 deletions
diff --git a/drivers/wear_leveling/wear_leveling_flash_spi.c b/drivers/wear_leveling/wear_leveling_flash_spi.c
new file mode 100644
index 0000000000..6191f8bf09
--- /dev/null
+++ b/drivers/wear_leveling/wear_leveling_flash_spi.c
@@ -0,0 +1,101 @@
+// Copyright 2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdbool.h>
+#include <hal.h>
+#include "util.h"
+#include "timer.h"
+#include "wear_leveling.h"
+#include "wear_leveling_internal.h"
+
+#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT
+#    define WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT 32
+#endif // WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT
+
+bool backing_store_init(void) {
+    bs_dprintf("Init\n");
+    flash_init();
+    return true;
+}
+
+bool backing_store_unlock(void) {
+    bs_dprintf("Unlock\n");
+    // No-op -- handled by the flash driver as it is.
+    return true;
+}
+
+bool backing_store_erase(void) {
+#ifdef WEAR_LEVELING_DEBUG_OUTPUT
+    uint32_t start = timer_read32();
+#endif
+
+    bool ret = true;
+    for (int i = 0; i < (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT); ++i) {
+        flash_status_t status = flash_erase_block(((WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) + i) * (EXTERNAL_FLASH_BLOCK_SIZE));
+        if (status != FLASH_STATUS_SUCCESS) {
+            ret = false;
+            break;
+        }
+    }
+
+    bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start)));
+    return ret;
+}
+
+bool backing_store_write(uint32_t address, backing_store_int_t value) {
+    return backing_store_write_bulk(address, &value, 1);
+}
+
+bool backing_store_lock(void) {
+    bs_dprintf("Lock  \n");
+    // No-op -- handled by the flash driver as it is.
+    return true;
+}
+
+bool backing_store_read(uint32_t address, backing_store_int_t *value) {
+    return backing_store_read_bulk(address, value, 1);
+}
+
+bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
+    bs_dprintf("Read  ");
+    uint32_t       offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address;
+    flash_status_t status = flash_read_block(offset, values, sizeof(backing_store_int_t) * item_count);
+    if (status == FLASH_STATUS_SUCCESS) {
+        for (size_t i = 0; i < item_count; ++i) {
+            values[i] = ~values[i];
+        }
+        wl_dump(offset, values, sizeof(backing_store_int_t) * item_count);
+    }
+    return status == FLASH_STATUS_SUCCESS;
+}
+
+bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
+    uint32_t            offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address;
+    size_t              index  = 0;
+    backing_store_int_t temp[WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT];
+    do {
+        // Copy out the block of data we want to transmit first
+        size_t this_loop = MIN(item_count, WEAR_LEVELING_EXTERNAL_FLASH_BULK_COUNT);
+        for (size_t i = 0; i < this_loop; ++i) {
+            temp[i] = values[index + i];
+        }
+
+        bs_dprintf("Write ");
+        wl_dump(offset, temp, sizeof(backing_store_int_t) * this_loop);
+
+        // Take the complement instead
+        for (size_t i = 0; i < this_loop; ++i) {
+            temp[i] = ~temp[i];
+        }
+
+        // Write out the block
+        if (flash_write_block(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) {
+            return false;
+        }
+
+        offset += this_loop * sizeof(backing_store_int_t);
+        index += this_loop;
+        item_count -= this_loop;
+    } while (item_count > 0);
+
+    return true;
+}
diff --git a/drivers/wear_leveling/wear_leveling_flash_spi_config.h b/drivers/wear_leveling/wear_leveling_flash_spi_config.h
new file mode 100644
index 0000000000..394370daa3
--- /dev/null
+++ b/drivers/wear_leveling/wear_leveling_flash_spi_config.h
@@ -0,0 +1,34 @@
+// Copyright 2022 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#ifndef __ASSEMBLER__
+#    include <stdlib.h>
+#    include <stdint.h>
+#    include "flash_spi.h"
+#endif
+
+// Use 1 block -- check the config for the SPI flash to determine how big it is
+#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT
+#    define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT 1
+#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT
+
+// Start at the first block of the external flash
+#ifndef WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET
+#    define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET 0
+#endif // WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET
+
+// 8-byte writes by default
+#ifndef BACKING_STORE_WRITE_SIZE
+#    define BACKING_STORE_WRITE_SIZE 8
+#endif
+
+// The space allocated by the block
+#ifndef WEAR_LEVELING_BACKING_SIZE
+#    define WEAR_LEVELING_BACKING_SIZE ((EXTERNAL_FLASH_BLOCK_SIZE) * (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT))
+#endif // WEAR_LEVELING_BACKING_SIZE
+
+// Use half of the backing size for logical EEPROM
+#ifndef WEAR_LEVELING_LOGICAL_SIZE
+#    define WEAR_LEVELING_LOGICAL_SIZE ((WEAR_LEVELING_BACKING_SIZE) / 2)
+#endif // WEAR_LEVELING_LOGICAL_SIZE