From 1fd2027b6b2bccbede51d36b2a94394aba2c784b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 7 Oct 2024 23:31:23 +0200 Subject: [PATCH] feat(spi_nand_flash): add support for Micron MT29F2G01ABAGD --- spi_nand_flash/src/dhara_glue.c | 85 +++++++++++++++++++++++-- spi_nand_flash/src/nand.c | 21 ++++-- spi_nand_flash/src/nand.h | 6 ++ spi_nand_flash/src/nand_flash_devices.h | 1 + 4 files changed, 101 insertions(+), 12 deletions(-) diff --git a/spi_nand_flash/src/dhara_glue.c b/spi_nand_flash/src/dhara_glue.c index 91d97a936d..6e46f9b18c 100644 --- a/spi_nand_flash/src/dhara_glue.c +++ b/spi_nand_flash/src/dhara_glue.c @@ -68,8 +68,15 @@ int dhara_nand_is_bad(const struct dhara_nand *n, dhara_block_t b) ESP_GOTO_ON_ERROR(read_page_and_wait(dev, first_block_page, NULL), fail, TAG, ""); + uint16_t column_addr = dev->page_size; + + if (dev->flags & NAND_FLAG_HAS_READ_PLANE_SELECT) { + uint32_t plane = b % dev->num_planes; + column_addr += plane << dev->dhara_nand.log2_page_size; + } + // Read the first 2 bytes on the OOB of the first page in the block. This should be 0xFFFF for a good block - ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, (uint8_t *) &bad_block_indicator, dev->page_size, 2), + ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, (uint8_t *) &bad_block_indicator, column_addr, 2), fail, TAG, ""); ESP_LOGD(TAG, "is_bad, block=%"PRIu32", page=%"PRIu32",indicator = %04x", b, first_block_page, bad_block_indicator); @@ -94,8 +101,14 @@ void dhara_nand_mark_bad(const struct dhara_nand *n, dhara_block_t b) fail, TAG, ""); ESP_GOTO_ON_ERROR(spi_nand_write_enable(dev->config.device_handle), fail, TAG, ""); + + uint32_t column_addr = dev->page_size; + if (dev->flags & NAND_FLAG_HAS_READ_PLANE_SELECT) { + uint32_t plane = b % dev->num_planes; + column_addr += plane << dev->dhara_nand.log2_page_size; + } ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, (const uint8_t *) &bad_block_indicator, - dev->page_size, 2), + column_addr, 2), fail, TAG, ""); ESP_GOTO_ON_ERROR(program_execute_and_wait(dev, first_block_page, NULL), fail, TAG, ""); return; @@ -138,13 +151,20 @@ int dhara_nand_prog(const struct dhara_nand *n, dhara_page_t p, const uint8_t *d esp_err_t ret; uint8_t status; uint16_t used_marker = 0; + uint32_t column_addr = 0; + + if (dev->flags & NAND_FLAG_HAS_PROG_PLANE_SELECT) { + uint32_t block = p >> dev->dhara_nand.log2_ppb; + uint32_t plane = block % dev->num_planes; + column_addr += plane << dev->dhara_nand.log2_page_size; + } ESP_GOTO_ON_ERROR(read_page_and_wait(dev, p, NULL), fail, TAG, ""); ESP_GOTO_ON_ERROR(spi_nand_write_enable(dev->config.device_handle), fail, TAG, ""); - ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, data, 0, dev->page_size), + ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, data, column_addr, dev->page_size), fail, TAG, ""); ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, (uint8_t *)&used_marker, - dev->page_size + 2, 2), + column_addr + dev->page_size + 2, 2), fail, TAG, ""); ESP_GOTO_ON_ERROR(program_execute_and_wait(dev, p, &status), fail, TAG, ""); @@ -167,8 +187,16 @@ int dhara_nand_is_free(const struct dhara_nand *n, dhara_page_t p) uint16_t used_marker; ESP_GOTO_ON_ERROR(read_page_and_wait(dev, p, NULL), fail, TAG, ""); + + uint16_t column_addr = dev->page_size + 2; + if (dev->flags & NAND_FLAG_HAS_READ_PLANE_SELECT) { + uint32_t block = p >> dev->dhara_nand.log2_ppb; + uint32_t plane = block % dev->num_planes; + column_addr += plane << dev->dhara_nand.log2_page_size; + } + ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, (uint8_t *)&used_marker, - dev->page_size + 2, 2), + column_addr, 2), fail, TAG, ""); ESP_LOGD(TAG, "is free, page=%"PRIu32", used_marker=%04x,", p, used_marker); @@ -200,7 +228,14 @@ int dhara_nand_read(const struct dhara_nand *n, dhara_page_t p, size_t offset, s return -1; } - ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, data, offset, length), fail, TAG, ""); + uint16_t column_addr = offset; + if (dev->flags & NAND_FLAG_HAS_READ_PLANE_SELECT) { + uint32_t block = p >> dev->dhara_nand.log2_ppb; + uint32_t plane = block % dev->num_planes; + column_addr += plane << dev->dhara_nand.log2_page_size; + } + + ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, data, column_addr, length), fail, TAG, ""); return 0; fail: @@ -222,8 +257,44 @@ int dhara_nand_copy(const struct dhara_nand *n, dhara_page_t src, dhara_page_t d dhara_set_error(err, DHARA_E_ECC); return -1; } - ESP_GOTO_ON_ERROR(spi_nand_write_enable(dev->config.device_handle), fail, TAG, ""); + + bool need_copy_via_ram = false; + if (dev->num_planes > 1 && (dev->flags & (NAND_FLAG_HAS_PROG_PLANE_SELECT | NAND_FLAG_HAS_READ_PLANE_SELECT))) { + uint32_t src_block = src >> dev->dhara_nand.log2_ppb; + uint32_t dst_block = dst >> dev->dhara_nand.log2_ppb; + need_copy_via_ram = src_block % dev->num_planes != dst_block % dev->num_planes; + } + + if (need_copy_via_ram) { + uint8_t *copy_buf = malloc(dev->page_size + 2); + ESP_GOTO_ON_FALSE(copy_buf, ESP_ERR_NO_MEM, fail, TAG, "Failed to allocate copy buffer"); + + uint32_t src_column_addr = 0; + if (dev->flags & NAND_FLAG_HAS_READ_PLANE_SELECT) { + uint32_t src_block = src >> dev->dhara_nand.log2_ppb; + uint32_t plane = src_block % dev->num_planes; + src_column_addr += plane << dev->dhara_nand.log2_page_size; + } + + uint32_t dst_column_addr = 0; + if (dev->flags & NAND_FLAG_HAS_PROG_PLANE_SELECT) { + uint32_t dst_block = dst >> dev->dhara_nand.log2_ppb; + uint32_t plane = dst_block % dev->num_planes; + dst_column_addr += plane << dev->dhara_nand.log2_page_size; + } + + ESP_GOTO_ON_ERROR(spi_nand_read(dev->config.device_handle, copy_buf, src_column_addr, dev->page_size), fail, TAG, ""); + + ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, copy_buf, dst_column_addr, dev->page_size), + fail, TAG, ""); + uint16_t used_marker = 0; + ESP_GOTO_ON_ERROR(spi_nand_program_load(dev->config.device_handle, (uint8_t *)&used_marker, + dst_column_addr + dev->page_size + 2, 2), + fail, TAG, ""); + free(copy_buf); + } + ESP_GOTO_ON_ERROR(program_execute_and_wait(dev, dst, &status), fail, TAG, ""); if ((status & STAT_PROGRAM_FAILED) != 0) { diff --git a/spi_nand_flash/src/nand.c b/spi_nand_flash/src/nand.c index 7415551eee..b5867b6c3f 100644 --- a/spi_nand_flash/src/nand.c +++ b/spi_nand_flash/src/nand.c @@ -139,15 +139,24 @@ static esp_err_t spi_nand_micron_init(spi_nand_flash_device_t *dev) .miso_data = &device_id }; spi_nand_execute_transaction(dev->config.device_handle, &t); - dev->read_page_delay_us = 115; dev->erase_block_delay_us = 2000; - dev->program_page_delay_us = 240; switch (device_id) { case MICRON_DI_34: + dev->read_page_delay_us = 115; + dev->program_page_delay_us = 240; dev->dhara_nand.num_blocks = 2048; dev->dhara_nand.log2_ppb = 6; // 64 pages per block dev->dhara_nand.log2_page_size = 12; // 4096 bytes per page break; + case MICRON_DI_24: + dev->read_page_delay_us = 55; + dev->program_page_delay_us = 220; + dev->dhara_nand.num_blocks = 2048; + dev->dhara_nand.log2_ppb = 6; // 64 pages per block + dev->dhara_nand.log2_page_size = 11; // 2048 bytes per page + dev->flags |= NAND_FLAG_HAS_PROG_PLANE_SELECT | NAND_FLAG_HAS_READ_PLANE_SELECT; + dev->num_planes = 2; + break; default: return ESP_ERR_INVALID_RESPONSE; } @@ -222,6 +231,8 @@ esp_err_t spi_nand_flash_init_device(spi_nand_flash_config_t *config, spi_nand_f (*handle)->block_size = (1 << (*handle)->dhara_nand.log2_ppb) * (*handle)->page_size; (*handle)->num_blocks = (*handle)->dhara_nand.num_blocks; (*handle)->work_buffer = malloc((*handle)->page_size); + (*handle)->num_planes = 1; + (*handle)->flags = 0; ESP_GOTO_ON_FALSE((*handle)->work_buffer != NULL, ESP_ERR_NO_MEM, fail, TAG, "nomem"); @@ -276,7 +287,7 @@ esp_err_t spi_nand_erase_chip(spi_nand_flash_device_t *handle) 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; + dhara_error_t err = 0; esp_err_t ret = ESP_OK; xSemaphoreTake(handle->mutex, portMAX_DELAY); @@ -296,7 +307,7 @@ esp_err_t spi_nand_flash_read_sector(spi_nand_flash_device_t *handle, uint8_t *b esp_err_t spi_nand_flash_write_sector(spi_nand_flash_device_t *handle, const uint8_t *buffer, dhara_sector_t sector_id) { - dhara_error_t err; + dhara_error_t err = 0; esp_err_t ret = ESP_OK; xSemaphoreTake(handle->mutex, portMAX_DELAY); @@ -311,7 +322,7 @@ esp_err_t spi_nand_flash_write_sector(spi_nand_flash_device_t *handle, const uin esp_err_t spi_nand_flash_sync(spi_nand_flash_device_t *handle) { - dhara_error_t err; + dhara_error_t err = 0; esp_err_t ret = ESP_OK; xSemaphoreTake(handle->mutex, portMAX_DELAY); diff --git a/spi_nand_flash/src/nand.h b/spi_nand_flash/src/nand.h index 4b046c9a34..f7e6cb0947 100644 --- a/spi_nand_flash/src/nand.h +++ b/spi_nand_flash/src/nand.h @@ -19,11 +19,17 @@ extern "C" { #define INVALID_PAGE 0xFFFF +#define NAND_FLAG_HAS_QE BIT(0) +#define NAND_FLAG_HAS_PROG_PLANE_SELECT BIT(1) +#define NAND_FLAG_HAS_READ_PLANE_SELECT BIT(2) + struct spi_nand_flash_device_t { spi_nand_flash_config_t config; uint32_t block_size; uint32_t page_size; uint32_t num_blocks; + uint32_t num_planes; + uint32_t flags; struct dhara_map dhara_map; struct dhara_nand dhara_nand; uint8_t *work_buffer; diff --git a/spi_nand_flash/src/nand_flash_devices.h b/spi_nand_flash/src/nand_flash_devices.h index 1b439e6cd6..97c1573b90 100644 --- a/spi_nand_flash/src/nand_flash_devices.h +++ b/spi_nand_flash/src/nand_flash_devices.h @@ -42,3 +42,4 @@ #define WINBOND_DI_BC21 0xBC21 #define MICRON_DI_34 0x34 +#define MICRON_DI_24 0x24 // MT29F2G