From 53cfdc958899ff01b2f447411050270c15c45386 Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Thu, 24 Oct 2024 11:15:15 +0200 Subject: [PATCH] feat(spi_nand_flash): Add data refresh threshold for ECC correction --- spi_nand_flash/src/dhara_glue.c | 37 +++++++++++++++++++++++------- spi_nand_flash/src/nand.c | 33 ++++++++++++++++++++++---- spi_nand_flash/src/nand.h | 18 +++++++++++++++ spi_nand_flash/src/spi_nand_oper.h | 1 + 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/spi_nand_flash/src/dhara_glue.c b/spi_nand_flash/src/dhara_glue.c index 9ee25f4690..1d815e7420 100644 --- a/spi_nand_flash/src/dhara_glue.c +++ b/spi_nand_flash/src/dhara_glue.c @@ -219,9 +219,31 @@ int dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p) return 0; } -static int is_ecc_error(uint8_t status) +#define PACK_2BITS_STATUS(status, bit1, bit0) ((((status) & (bit1)) << 1) | ((status) & (bit0))) +#define PACK_3BITS_STATUS(status, bit2, bit1, bit0) ((((status) & (bit2)) << 2) | (((status) & (bit1)) << 1) | ((status) & (bit0))) + +static bool is_ecc_error(spi_nand_flash_device_t *dev, uint8_t status, dhara_error_t *err) { - return (status & STAT_ECC1) != 0 && (status & STAT_ECC0) == 0; + bool is_ecc_err = false; + ecc_status_t bits_corrected_status = STAT_ECC_OK; + if (dev->ecc_data.ecc_status_reg_len_in_bits == 2) { + bits_corrected_status = PACK_2BITS_STATUS(status, STAT_ECC1, STAT_ECC0); + } else if (dev->ecc_data.ecc_status_reg_len_in_bits == 3) { + bits_corrected_status = PACK_3BITS_STATUS(status, STAT_ECC2, STAT_ECC1, STAT_ECC0); + } else { + bits_corrected_status = STAT_ECC_MAX; + } + dev->ecc_data.ecc_corrected_bits_status = bits_corrected_status; + if (bits_corrected_status) { + if (bits_corrected_status == STAT_ECC_MAX) { + ESP_LOGE(TAG, "%s: Error while initializing value of ecc_status_reg_len_in_bits", __func__); + is_ecc_err = true; + } else if (bits_corrected_status == STAT_ECC_NOT_CORRECTED) { + dhara_set_error(err, DHARA_E_ECC); + is_ecc_err = true; + } + } + return is_ecc_err; } int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, size_t length, @@ -235,9 +257,8 @@ int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, s ESP_GOTO_ON_ERROR(read_page_and_wait(dev, p, &status), fail, TAG, ""); - if (is_ecc_error(status)) { + if (is_ecc_error(dev, status, err)) { ESP_LOGD(TAG, "read ecc error, page=%"PRIu32"", p); - dhara_set_error(err, DHARA_E_ECC); return -1; } @@ -261,9 +282,8 @@ int dhara_nand_copy(const struct dhara_nand *n, dhara_page_t src, dhara_page_t d ESP_GOTO_ON_ERROR(read_page_and_wait(dev, src, &status), fail, TAG, ""); - if (is_ecc_error(status)) { + if (is_ecc_error(dev, status, err)) { ESP_LOGD(TAG, "copy, ecc error"); - dhara_set_error(err, DHARA_E_ECC); return -1; } @@ -286,11 +306,12 @@ int dhara_nand_copy(const struct dhara_nand *n, dhara_page_t src, dhara_page_t d } // Then read dst page data from nand memory array and load it in cache ESP_GOTO_ON_ERROR(read_page_and_wait(dev, dst, &status), fail, TAG, ""); - if (is_ecc_error(status)) { + + if (is_ecc_error(dev, status, err)) { ESP_LOGE(TAG, "%s: dst_page=%"PRIu32" read, ecc error", __func__, dst); - dhara_set_error(err, DHARA_E_ECC); goto fail; } + // Check if the data in the src page matches the dst page ret = s_verify_write(dev, temp_buf, 0, dev->page_size); if (ret != ESP_OK) { diff --git a/spi_nand_flash/src/nand.c b/spi_nand_flash/src/nand.c index c4f42ef899..c47f9d8779 100644 --- a/spi_nand_flash/src/nand.c +++ b/spi_nand_flash/src/nand.c @@ -145,6 +145,7 @@ static esp_err_t spi_nand_micron_init(spi_nand_flash_device_t *dev) .flags = SPI_TRANS_USE_RXDATA, }; spi_nand_execute_transaction(dev->config.device_handle, &t); + dev->ecc_data.ecc_status_reg_len_in_bits = 3; dev->erase_block_delay_us = 2000; ESP_LOGD(TAG, "%s: device_id: %x\n", __func__, device_id); switch (device_id) { @@ -227,6 +228,8 @@ esp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_f memcpy(&(*handle)->config, config, sizeof(spi_nand_flash_config_t)); + (*handle)->ecc_data.ecc_status_reg_len_in_bits = 2; + (*handle)->ecc_data.ecc_data_refresh_threshold = 4; (*handle)->dhara_nand.log2_ppb = 6; // 64 pages per block is standard (*handle)->dhara_nand.log2_page_size = 11; // 2048 bytes per page is fairly standard @@ -296,6 +299,25 @@ esp_err_t spi_nand_erase_chip(spi_nand_flash_device_t *handle) return ret; } +static bool s_need_data_refresh(spi_nand_flash_device_t *handle) +{ + uint8_t min_bits_corrected = 0; + bool ret = false; + if (handle->ecc_data.ecc_corrected_bits_status == STAT_ECC_1_TO_3_BITS_CORRECTED) { + min_bits_corrected = 1; + } else if (handle->ecc_data.ecc_corrected_bits_status == STAT_ECC_4_TO_6_BITS_CORRECTED) { + min_bits_corrected = 4; + } else if (handle->ecc_data.ecc_corrected_bits_status == STAT_ECC_7_8_BITS_CORRECTED) { + min_bits_corrected = 7; + } + + // if number of corrected bits is greater than refresh threshold then rewite the sector + if (min_bits_corrected >= handle->ecc_data.ecc_data_refresh_threshold) { + ret = true; + } + return ret; +} + esp_err_t spi_nand_flash_read_sector(spi_nand_flash_device_t *handle, uint8_t *buffer, dhara_sector_t sector_id) { dhara_error_t err; @@ -303,12 +325,15 @@ esp_err_t spi_nand_flash_read_sector(spi_nand_flash_device_t *handle, uint8_t *b xSemaphoreTake(handle->mutex, portMAX_DELAY); + // After a successful read operation, check the ECC corrected bit status; if the read fails, return an error if (dhara_map_read(&handle->dhara_map, sector_id, handle->read_buffer, &err)) { ret = ESP_ERR_FLASH_BASE + err; - } else if (err) { - // This indicates a soft ECC error, we rewrite the sector to recover - if (dhara_map_write(&handle->dhara_map, sector_id, handle->read_buffer, &err)) { - ret = ESP_ERR_FLASH_BASE + err; + } else if (handle->ecc_data.ecc_corrected_bits_status) { + // This indicates a soft ECC error, we rewrite the sector to recover if corrected bits are greater than refresh threshold + if (s_need_data_refresh(handle)) { + if (dhara_map_write(&handle->dhara_map, sector_id, handle->read_buffer, &err)) { + ret = ESP_ERR_FLASH_BASE + err; + } } } diff --git a/spi_nand_flash/src/nand.h b/spi_nand_flash/src/nand.h index d5db7c9c08..bd78227901 100644 --- a/spi_nand_flash/src/nand.h +++ b/spi_nand_flash/src/nand.h @@ -19,6 +19,23 @@ extern "C" { #define INVALID_PAGE 0xFFFF +typedef enum { + STAT_ECC_OK = 0, + STAT_ECC_1_TO_3_BITS_CORRECTED = 1, + STAT_ECC_BITS_CORRECTED = STAT_ECC_1_TO_3_BITS_CORRECTED, + STAT_ECC_NOT_CORRECTED = 2, + STAT_ECC_4_TO_6_BITS_CORRECTED = 3, + STAT_ECC_MAX_BITS_CORRECTED = STAT_ECC_4_TO_6_BITS_CORRECTED, + STAT_ECC_7_8_BITS_CORRECTED = 5, + STAT_ECC_MAX +} ecc_status_t; + +typedef struct { + uint8_t ecc_status_reg_len_in_bits; + uint8_t ecc_data_refresh_threshold; + ecc_status_t ecc_corrected_bits_status; +} ecc_data_t; + struct spi_nand_flash_device_t { spi_nand_flash_config_t config; uint32_t block_size; @@ -31,6 +48,7 @@ struct spi_nand_flash_device_t { uint32_t read_page_delay_us; uint32_t erase_block_delay_us; uint32_t program_page_delay_us; + ecc_data_t ecc_data; SemaphoreHandle_t mutex; }; diff --git a/spi_nand_flash/src/spi_nand_oper.h b/spi_nand_flash/src/spi_nand_oper.h index 7bf0e9de36..39036fd897 100644 --- a/spi_nand_flash/src/spi_nand_oper.h +++ b/spi_nand_flash/src/spi_nand_oper.h @@ -53,6 +53,7 @@ typedef struct spi_nand_transaction_t spi_nand_transaction_t; #define STAT_PROGRAM_FAILED 1 << 3 #define STAT_ECC0 1 << 4 #define STAT_ECC1 1 << 5 +#define STAT_ECC2 1 << 6 esp_err_t spi_nand_execute_transaction(spi_device_handle_t device, spi_nand_transaction_t *transaction);