From 34e244cecf62afb30ee5a4362867f24b03675691 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 30 Jun 2022 07:42:23 +1000 Subject: Wear-leveling EEPROM drivers: `embedded_flash`, `spi_flash`, `legacy` (#17376) --- drivers/eeprom/eeprom_wear_leveling.c | 23 +++++ drivers/wear_leveling/wear_leveling_flash_spi.c | 101 +++++++++++++++++++++ .../wear_leveling/wear_leveling_flash_spi_config.h | 34 +++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/eeprom/eeprom_wear_leveling.c create mode 100644 drivers/wear_leveling/wear_leveling_flash_spi.c create mode 100644 drivers/wear_leveling/wear_leveling_flash_spi_config.h (limited to 'drivers') diff --git a/drivers/eeprom/eeprom_wear_leveling.c b/drivers/eeprom/eeprom_wear_leveling.c new file mode 100644 index 0000000000..bd77eef35c --- /dev/null +++ b/drivers/eeprom/eeprom_wear_leveling.c @@ -0,0 +1,23 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + +#include "eeprom_driver.h" +#include "wear_leveling.h" + +void eeprom_driver_init(void) { + wear_leveling_init(); +} + +void eeprom_driver_erase(void) { + wear_leveling_erase(); +} + +void eeprom_read_block(void *buf, const void *addr, size_t len) { + wear_leveling_read((uint32_t)addr, buf, len); +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { + wear_leveling_write((uint32_t)addr, buf, len); +} 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 +#include +#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 +# include +# 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 -- cgit v1.2.3