Skip to content

Commit

Permalink
spi_flash: Fix issue that cannot get accurate flash size when encount…
Browse files Browse the repository at this point in the history
…er large size memory,

Closes #9566
  • Loading branch information
mythbuster5 committed Mar 20, 2023
1 parent 55e040b commit e94d951
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 75 deletions.
72 changes: 46 additions & 26 deletions components/spi_flash/esp_flash_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ static const char TAG[] = "spi_flash";
} while(0)
#endif // CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED

/* Convenience macro for beginning of all API functions.
* Check the return value of `rom_spiflash_api_funcs->chip_check` is correct,
* and the chip supports the operation in question.
*/
#define VERIFY_CHIP_OP(op) do { \
if (err != ESP_OK) return err; \
if (chip->chip_drv->op == NULL) { \
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
} \
} while (0)

#define IO_STR_LEN 10

static const char io_mode_str[][IO_STR_LEN] = {
Expand Down Expand Up @@ -211,7 +222,7 @@ esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)

// Detect flash size
uint32_t size;
err = esp_flash_get_size(chip, &size);
err = esp_flash_get_physical_size(chip, &size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to get chip size");
return err;
Expand Down Expand Up @@ -291,7 +302,7 @@ esp_err_t IRAM_ATTR esp_flash_init_main(esp_flash_t *chip)

// Detect flash size
uint32_t size;
err = esp_flash_get_size(chip, &size);
err = esp_flash_get_physical_size(chip, &size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to get chip size");
return err;
Expand Down Expand Up @@ -449,33 +460,16 @@ static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
return ESP_OK;
}

#ifndef CONFIG_SPI_FLASH_ROM_IMPL

/* Convenience macro for beginning of all API functions.
* Check the return value of `rom_spiflash_api_funcs->chip_check` is correct,
* and the chip supports the operation in question.
*/
#define VERIFY_CHIP_OP(OP) do { \
if (err != ESP_OK) return err; \
if (chip->chip_drv->OP == NULL) { \
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
} \
} while (0)

/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);

esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
esp_err_t IRAM_ATTR esp_flash_get_physical_size(esp_flash_t *chip, uint32_t *flash_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
VERIFY_CHIP_OP(detect_size);
if (out_size == NULL) {
if (flash_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (chip->size != 0) {
*out_size = chip->size;
return ESP_OK;
}

err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
Expand All @@ -484,12 +478,38 @@ esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
uint32_t detect_size;
err = chip->chip_drv->detect_size(chip, &detect_size);
if (err == ESP_OK) {
chip->size = detect_size;
*out_size = chip->size;
if (chip->size == 0) {
// chip->size will not be changed if detected, it will always be equal to configured flash size.
chip->size = detect_size;
}
*flash_size = detect_size;
}
return rom_spiflash_api_funcs->end(chip, err);
}

#ifndef CONFIG_SPI_FLASH_ROM_IMPL

/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);

esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
if (out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (chip->size != 0) {
*out_size = chip->size;
return ESP_OK;
}
//Return flash chip physical size, when this API is called before flash initialisation,
//After initialization will return available size.
return esp_flash_get_physical_size(chip, out_size);
}

esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
Expand Down
1 change: 1 addition & 0 deletions components/spi_flash/esp_flash_spi_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ esp_err_t esp_flash_init_default_chip(void)
if (default_chip.size > legacy_chip->chip_size) {
ESP_EARLY_LOGW(TAG, "Detected size(%dk) larger than the size in the binary image header(%dk). Using the size in the binary image header.", default_chip.size/1024, legacy_chip->chip_size/1024);
}
// Set chip->size equal to ROM flash size(also equal to menuconfig flash size), which means the available size that can be used
default_chip.size = legacy_chip->chip_size;

esp_flash_default_chip = &default_chip;
Expand Down
20 changes: 17 additions & 3 deletions components/spi_flash/include/esp_flash.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ struct esp_flash_t {
void *os_func_data; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``.

esp_flash_io_mode_t read_mode; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation.
uint32_t size; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. Note: Only stands for the available size (`CONFIG_ESPTOOLPY_FLASHSIZE`), If you want to get the flash physical size, please call `esp_flash_get_physical_size`.
uint32_t chip_id; ///< Detected chip id.
uint32_t busy :1; ///< This flag is used to verify chip's status.
uint32_t hpm_dummy_ena :1; ///< This flag is used to verify whether flash works under HPM status.
Expand Down Expand Up @@ -145,15 +145,29 @@ esp_err_t esp_flash_read_id(esp_flash_t *chip, uint32_t *out_id);
/** @brief Detect flash size based on flash ID.
*
* @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init()
* @param[out] out_size Detected size in bytes.
* @param[out] out_size Detected size in bytes, standing for the available size (`CONFIG_ESPTOOLPY_FLASHSIZE`).
*
* @note Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If
* @note 1. Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If
* the manufacturer doesn't follow this convention, the size may be incorrectly detected.
* 2. The out_size returned only stands for the size selected in menuconfig.
* If you want to get the real size of the chip, please call `esp_flash_get_physical_size` instead.
*
* @return ESP_OK on success, or a flash error code if operation failed.
*/
esp_err_t esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size);

/** @brief Detect flash size based on flash ID.
*
* @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init()
* @param[out] flash_size Detected size in bytes.
*
* @note Most flash chips use a common format for flash ID, where the lower 4 bits specify the size as a power of 2. If
* the manufacturer doesn't follow this convention, the size may be incorrectly detected.
*
* @return ESP_OK on success, or a flash error code if operation failed.
*/
esp_err_t esp_flash_get_physical_size(esp_flash_t *chip, uint32_t *flash_size);

/** @brief Read flash unique ID via the common "RDUID" SPI flash command.
*
* @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init().
Expand Down
35 changes: 21 additions & 14 deletions components/spi_flash/spi_flash_chip_gd.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -47,6 +39,21 @@ spi_flash_caps_t spi_flash_chip_gd_get_caps(esp_flash_t *chip)
return caps_flags;
}

esp_err_t spi_flash_chip_gd_detect_size(esp_flash_t *chip, uint32_t *size)
{
uint32_t id = chip->chip_id;
*size = 0;

/* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or
* 0xC0 or similar. */
if (((id & 0xFFFF) == 0x0000) || ((id & 0xFFFF) == 0xFFFF)) {
return ESP_ERR_FLASH_UNSUPPORTED_CHIP;
}

*size = 1 << (id & 0xFF);
return ESP_OK;
}

#ifndef CONFIG_SPI_FLASH_ROM_IMPL

#define FLASH_ID_MASK 0xFF00
Expand Down Expand Up @@ -114,7 +121,7 @@ const spi_flash_chip_t esp_flash_chip_gd = {
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_gd_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.detect_size = spi_flash_chip_gd_detect_size,
.erase_chip = spi_flash_chip_generic_erase_chip,
.erase_sector = spi_flash_chip_gd_erase_sector,
.erase_block = spi_flash_chip_gd_erase_block,
Expand Down
43 changes: 27 additions & 16 deletions components/spi_flash/spi_flash_chip_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ DRAM_ATTR static spi_flash_encryption_t esp_flash_encryption_default __attribute
#define HOST_DELAY_INTERVAL_US 1
#define CHIP_WAIT_IDLE_INTERVAL_US 20

#define SPI_FLASH_LINEAR_DENSITY_LAST_VALUE (0x19)
#define SPI_FLASH_HEX_A_F_RANGE (6)

const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {
.idle_timeout = SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS * 1000,
.chip_erase_timeout = SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS * 1000,
Expand All @@ -82,6 +85,30 @@ const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {

static const char TAG[] = "chip_generic";

esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size)
{
uint32_t id = chip->chip_id;
*size = 0;

/* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or
* 0xC0 or similar. */
if (((id & 0xFFFF) == 0x0000) || ((id & 0xFFFF) == 0xFFFF)) {
return ESP_ERR_FLASH_UNSUPPORTED_CHIP;
}

/* Get flash capacity from flash chip id depends on different vendors. According to majority of flash datasheets,
Flash 256Mb to 512Mb directly from 0x19 to 0x20, instead of from 0x19 to 0x1a. So here we leave the common behavior.
However, some other flash vendors also have their own rule, we will add them in chip specific files.
*/
uint32_t mem_density = (id & 0xFF);
if (mem_density > SPI_FLASH_LINEAR_DENSITY_LAST_VALUE ) {
mem_density -= SPI_FLASH_HEX_A_F_RANGE;
}

*size = 1 << mem_density;
return ESP_OK;
}

#ifndef CONFIG_SPI_FLASH_ROM_IMPL

esp_err_t spi_flash_chip_generic_probe(esp_flash_t *chip, uint32_t flash_id)
Expand Down Expand Up @@ -115,22 +142,6 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip)
return err;
}

esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size)
{
uint32_t id = chip->chip_id;
*size = 0;

/* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or
* 0xC0 or similar. */
if (((id & 0xFFFF) == 0x0000) || ((id & 0xFFFF) == 0xFFFF)) {
return ESP_ERR_FLASH_UNSUPPORTED_CHIP;
}

*size = 1 << (id & 0xFF);
return ESP_OK;
}


esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
{
esp_err_t err;
Expand Down
35 changes: 21 additions & 14 deletions components/spi_flash/spi_flash_chip_mxic_opi.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>
#include "spi_flash_chip_generic.h"
Expand Down Expand Up @@ -46,6 +38,21 @@ esp_err_t spi_flash_chip_mxic_opi_probe(esp_flash_t *chip, uint32_t flash_id)
return ESP_OK;
}

esp_err_t spi_flash_chip_mxic_opi_detect_size(esp_flash_t *chip, uint32_t *size)
{
uint32_t id = chip->chip_id;
*size = 0;

/* Can't detect size unless the high byte of the product ID matches the same convention, which is usually 0x40 or
* 0xC0 or similar. */
if (((id & 0xFFFF) == 0x0000) || ((id & 0xFFFF) == 0xFFFF)) {
return ESP_ERR_FLASH_UNSUPPORTED_CHIP;
}

*size = 1 << ((id & 0xFF) - 0x20);
return ESP_OK;
}

spi_flash_caps_t spi_flash_chip_mxic_opi_get_caps(esp_flash_t *chip)
{
spi_flash_caps_t caps_flags = 0;
Expand Down Expand Up @@ -384,7 +391,7 @@ const spi_flash_chip_t esp_flash_chip_mxic_opi = {
.timeout = &spi_flash_chip_generic_timeout,
.probe = spi_flash_chip_mxic_opi_probe,
.reset = spi_flash_chip_generic_reset,
.detect_size = spi_flash_chip_generic_detect_size,
.detect_size = spi_flash_chip_mxic_opi_detect_size,
.erase_chip = spi_flash_chip_mxic_opi_erase_chip,
.erase_sector = spi_flash_chip_mxic_opi_erase_sector,
.erase_block = spi_flash_chip_mxic_opi_erase_block,
Expand Down
2 changes: 0 additions & 2 deletions tools/ci/check_copyright_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1237,10 +1237,8 @@ components/spi_flash/sim/flash_mock_util.c
components/spi_flash/sim/sdkconfig/sdkconfig.h
components/spi_flash/sim/stubs/bsd/strlcpy.c
components/spi_flash/spi_flash_chip_boya.c
components/spi_flash/spi_flash_chip_gd.c
components/spi_flash/spi_flash_chip_issi.c
components/spi_flash/spi_flash_chip_mxic.c
components/spi_flash/spi_flash_chip_mxic_opi.c
components/spi_flash/spi_flash_chip_winbond.c
components/spi_flash/test/test_esp_flash.c
components/spi_flash/test/test_flash_encryption.c
Expand Down

0 comments on commit e94d951

Please sign in to comment.