mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
176 lines
5.4 KiB
C
176 lines
5.4 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "sdkconfig.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
#include "spi_flash_defs.h"
|
|
#include "esp_rom_sys.h"
|
|
#include "esp_rom_spiflash.h"
|
|
#include "spi_flash_override.h"
|
|
#include "esp_private/spi_flash_os.h"
|
|
|
|
// TODO: These dependencies will be removed after remove bootloader_flash to G0.IDF-4609
|
|
#include "bootloader_flash_override.h"
|
|
#include "bootloader_flash_priv.h"
|
|
|
|
/***********************************************************************************
|
|
* Flash wrap feature (also called burst read on some flash chips)
|
|
*
|
|
* Different flash chips enter wrap (burst read) mode in different strategies.
|
|
* 1. Command 0xC0 + 8 Bytes.
|
|
* 2. Command 0x77 + 24 dummy + 8 Bytes.
|
|
**********************************************************************************/
|
|
|
|
#if SOC_SPI_MEM_SUPPORT_WRAP
|
|
|
|
const static char *FLASH_WRAP_TAG = "flash wrap";
|
|
|
|
// TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
|
|
extern uint32_t bootloader_flash_execute_command_common(
|
|
uint8_t command,
|
|
uint32_t addr_len, uint32_t address,
|
|
uint8_t dummy_len,
|
|
uint8_t mosi_len, uint32_t mosi_data,
|
|
uint8_t miso_len);
|
|
|
|
esp_err_t spi_flash_wrap_probe_c0(uint32_t flash_id)
|
|
{
|
|
esp_err_t ret = ESP_OK;
|
|
|
|
switch (flash_id) {
|
|
/* The flash listed here should enter the wrap with command 0xC0 */
|
|
case 0xC22018:
|
|
break;
|
|
default:
|
|
ret = ESP_ERR_NOT_FOUND;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Burst read with command 0xC0 + 8 Bytes
|
|
*
|
|
* |------------|-----------------------------|
|
|
* | data | wrap depth |
|
|
* | 00h | 8 |
|
|
* | 01h | 16 |
|
|
* | 02h | 32 |
|
|
* | 03h | 64 |
|
|
* |------------|-----------------------------|
|
|
*/
|
|
esp_err_t spi_flash_wrap_enable_c0(spi_flash_wrap_size_t wrap_size)
|
|
{
|
|
uint8_t wrap_code = (uint8_t) (__builtin_ctz(wrap_size) - 3);
|
|
bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, wrap_code, 0);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Burst read with command 0x77 + 24 Dummy + 8 Bytes
|
|
*
|
|
* |-------------------|-----------------------------|
|
|
* | data(W6,W5) | wrap depth |
|
|
* | 00h | 8 |
|
|
* | 01h | 16 |
|
|
* | 02h | 32 |
|
|
* | 03h | 64 |
|
|
* |-------------------|-----------------------------|
|
|
*/
|
|
esp_err_t spi_flash_wrap_enable_77(spi_flash_wrap_size_t wrap_size)
|
|
{
|
|
uint8_t wrap_code = (uint8_t) (((__builtin_ctz(wrap_size) - 3) * 2) << 4);
|
|
// According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
|
|
REG_SET_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
|
|
bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, wrap_code, 0);
|
|
REG_CLR_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Burst read is cleared by setting 0x1xh,
|
|
* so we set 0x10 to disable this feature.
|
|
*/
|
|
esp_err_t spi_flash_wrap_clear_c0(void)
|
|
{
|
|
bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, 0x10, 0);
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Burst read is cleared by setting W4 bit 1,
|
|
* so we set 0x10 to disable this feature.
|
|
*/
|
|
esp_err_t spi_flash_wrap_clear_77(void)
|
|
{
|
|
// According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
|
|
REG_SET_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
|
|
bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, 0x10, 0);
|
|
REG_CLR_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
|
|
return ESP_OK;
|
|
}
|
|
|
|
const spi_flash_wrap_info_t __attribute__((weak)) spi_flash_wrap_list[] = {
|
|
/* method probe chip wrap set chip wrap clear */
|
|
{"C0H+8B", spi_flash_wrap_probe_c0, spi_flash_wrap_enable_c0, spi_flash_wrap_clear_c0},
|
|
{"default", NULL, spi_flash_wrap_enable_77, spi_flash_wrap_clear_77},
|
|
};
|
|
|
|
static const spi_flash_wrap_info_t *chip_wrap = NULL;
|
|
|
|
esp_err_t spi_flash_wrap_probe(void)
|
|
{
|
|
uint32_t flash_chip_id = g_rom_flashchip.device_id;
|
|
const spi_flash_wrap_info_t *chip = spi_flash_wrap_list;
|
|
esp_err_t ret = ESP_OK;
|
|
while (chip->probe) {
|
|
ret = chip->probe(flash_chip_id);
|
|
if (ret == ESP_OK) {
|
|
break;
|
|
}
|
|
chip++;
|
|
}
|
|
chip_wrap = chip;
|
|
return ret;
|
|
}
|
|
|
|
esp_err_t spI_flash_wrap_enable(spi_flash_wrap_size_t wrap_size)
|
|
{
|
|
// Calculate pre_code. pre_code equals log(2)(wrap_size) - 3
|
|
// So the wrap_size:pre_code is 8:0, 16:1, 32:2, 64:3.
|
|
return chip_wrap->chip_wrap_set(wrap_size);
|
|
}
|
|
|
|
esp_err_t spi_flash_wrap_disable(void)
|
|
{
|
|
return chip_wrap->chip_wrap_clr();
|
|
}
|
|
|
|
bool spi_flash_support_wrap_size(uint32_t wrap_size)
|
|
{
|
|
// Only QIO mode supports wrap.
|
|
if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO)) {
|
|
ESP_EARLY_LOGE(FLASH_WRAP_TAG, "flash wrap is only supported in QIO mode");
|
|
abort();
|
|
}
|
|
// Only following size can be wrapped.
|
|
switch (wrap_size) {
|
|
case 0:
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#endif // SOC_SPI_MEM_SUPPORT_WRAP
|