mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
307 lines
11 KiB
C
307 lines
11 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "sdkconfig.h"
|
|
#include "esp_log.h"
|
|
#include "esp_err.h"
|
|
#include "esp_rom_gpio.h"
|
|
#include "esp32s3/rom/gpio.h"
|
|
#include "esp32s3/rom/spi_flash.h"
|
|
#include "esp32s3/rom/opi_flash.h"
|
|
#include "esp_private/spi_flash_os.h"
|
|
#include "opi_flash_private.h"
|
|
#include "soc/spi_mem_reg.h"
|
|
#include "soc/io_mux_reg.h"
|
|
#include "opi_flash_cmd_format_mxic.h"
|
|
|
|
#define SPI_FLASH_SPI_CMD_WRCR2 0x72
|
|
#define SPI_FLASH_SPI_CMD_RDSR 0x05
|
|
#define SPI_FLASH_SPI_CMD_RDCR 0x15
|
|
#define SPI_FLASH_SPI_CMD_WRSRCR 0x01
|
|
#define SPI_FLASH_SPI_CMD_RDSFDP 0x5A
|
|
|
|
/**
|
|
* Supported Flash chip vendor id
|
|
*/
|
|
#define ESP_FLASH_CHIP_MXIC_OCT 0xC2
|
|
|
|
const static char *TAG = "Octal Flash";
|
|
// default value is rom_default_spiflash_legacy_flash_func
|
|
extern const spiflash_legacy_funcs_t *rom_spiflash_legacy_funcs;
|
|
static uint32_t s_chip_id;
|
|
|
|
|
|
static void s_register_rom_function(void)
|
|
{
|
|
static spiflash_legacy_funcs_t rom_func =
|
|
{
|
|
.read_sub_len = 32,
|
|
.write_sub_len = 32,
|
|
.unlock = esp_rom_opiflash_wait_idle,
|
|
.erase_block = esp_rom_opiflash_erase_block_64k,
|
|
.erase_sector = esp_rom_opiflash_erase_sector,
|
|
.read = esp_rom_opiflash_read,
|
|
.write = esp_rom_opiflash_write,
|
|
.wait_idle = esp_rom_opiflash_wait_idle,
|
|
.wren = esp_rom_opiflash_wren,
|
|
.erase_area = esp_rom_opiflash_erase_area,
|
|
};
|
|
rom_spiflash_legacy_funcs = &rom_func;
|
|
}
|
|
|
|
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
|
|
/*----------------------------------------------------------------------------------------------------
|
|
MXIC Specific Functions
|
|
-----------------------------------------------------------------------------------------------------*/
|
|
static esp_err_t s_probe_mxic_chip(uint32_t chip_id, uint8_t *out_vendor_id)
|
|
{
|
|
if (chip_id >> 16 != ESP_FLASH_CHIP_MXIC_OCT) {
|
|
return ESP_ERR_NOT_FOUND;
|
|
}
|
|
if (((chip_id >> 8) & 0xf0) != 0x80) {
|
|
// We now suppose that middle id of opi flash is 0x8*.
|
|
ESP_EARLY_LOGE(TAG, "Detected MXIC Flash, but memory type is not Octal");
|
|
return ESP_ERR_NOT_FOUND;
|
|
}
|
|
*out_vendor_id = ESP_FLASH_CHIP_MXIC_OCT;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
static bool s_mxic_dtr_need_swap(void)
|
|
{
|
|
// This function is used for judging the data bytes whether need swap.
|
|
// For some of opi flash chips, the data bytes are ordered by D1-D0-D3-D2. This kinds of order needs swap.
|
|
// On the contrary, some opi flash chips order the data like D0-D1-D2-D3. This kinds of order doesn't need swap.
|
|
// Note: this function must be called when flash works under single line mode.
|
|
// 1. Send 0x5A to read SFDP regs for getting the first address of JEDEC Flash Parameter table.
|
|
// 2. Add offset with first address to get the order in 8D-8D-8D mode.
|
|
// 3. Judge whether the BIT(7) is 1, 1 stands for need swap, vice versa.
|
|
uint8_t JEDEC_first_address = 0;
|
|
uint8_t byte_order_val = 0;
|
|
uint8_t dummy = 8;
|
|
uint8_t cmd_len = 8;
|
|
uint8_t addr_len = 24;
|
|
uint8_t miso_bit_len = 8;
|
|
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_RDSFDP, cmd_len,
|
|
0x0C, addr_len,
|
|
dummy,
|
|
NULL, 0,
|
|
(uint8_t*)&JEDEC_first_address, miso_bit_len,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
|
|
esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_RDSFDP, cmd_len,
|
|
(JEDEC_first_address + 0x47), addr_len,
|
|
dummy,
|
|
NULL, 0,
|
|
(uint8_t*)&byte_order_val, miso_bit_len,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
|
|
return ((byte_order_val & 0x80) == 0x80) ? true : false;
|
|
}
|
|
#endif // CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
|
|
// 0x00: SPI; 0x01: STR OPI; 0x02: DTR OPI
|
|
static void s_set_flash_dtr_str_opi_mode(int spi_num, uint8_t val)
|
|
{
|
|
uint8_t cmd_len = 8;
|
|
int addr_bit_len = 32;
|
|
int dummy = 0;
|
|
int data_bit_len = 8;
|
|
|
|
esp_rom_spiflash_write_enable(&g_rom_flashchip);
|
|
//SPI command, WRCR2
|
|
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_WRCR2, cmd_len,
|
|
0, addr_bit_len,
|
|
dummy,
|
|
(uint8_t *)&val, data_bit_len,
|
|
NULL, 0,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
}
|
|
|
|
//To set the output driver strength
|
|
static void s_set_flash_ouput_driver_strength(int spi_num, uint8_t strength)
|
|
{
|
|
uint16_t reg_val = 0;
|
|
uint8_t sr_reg_val = 0;
|
|
uint8_t cr_reg_val = 0;
|
|
uint8_t cmd_len = 8;
|
|
uint32_t addr = 0;
|
|
int addr_bit_len = 0;
|
|
int dummy = 0;
|
|
int data_bit_len = 8;
|
|
|
|
//Read
|
|
//SPI command, RDSR
|
|
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_RDSR, cmd_len,
|
|
addr, addr_bit_len,
|
|
dummy,
|
|
NULL, 0,
|
|
(uint8_t*)&sr_reg_val, data_bit_len,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
|
|
//SPI command, RDCR
|
|
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_RDCR, cmd_len,
|
|
addr, addr_bit_len,
|
|
dummy,
|
|
NULL, 0,
|
|
(uint8_t*)&cr_reg_val, data_bit_len,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
|
|
//Modify
|
|
reg_val = (((cr_reg_val & 0xf8) | strength) << 8) | sr_reg_val;
|
|
|
|
//Write
|
|
//SPI command, WRSR/WRCR
|
|
data_bit_len = 16;
|
|
esp_rom_spiflash_write_enable(&g_rom_flashchip);
|
|
esp_rom_opiflash_exec_cmd(spi_num, ESP_ROM_SPIFLASH_FASTRD_MODE,
|
|
SPI_FLASH_SPI_CMD_WRSRCR, cmd_len,
|
|
addr, addr_bit_len,
|
|
dummy,
|
|
(uint8_t*)®_val, data_bit_len,
|
|
NULL, 0,
|
|
ESP_ROM_OPIFLASH_SEL_CS0,
|
|
false);
|
|
}
|
|
|
|
static void s_set_pin_drive_capability(uint8_t drv)
|
|
{
|
|
//flash clock
|
|
REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, 3);
|
|
//cs0
|
|
PIN_SET_DRV(IO_MUX_GPIO29_REG, 3);
|
|
}
|
|
|
|
static void s_flash_init_mxic(esp_rom_spiflash_read_mode_t mode)
|
|
{
|
|
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
|
|
static const esp_rom_opiflash_def_t opiflash_cmd_def_mxic = OPI_CMD_FORMAT_MXIC_STR();
|
|
#elif CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
static const esp_rom_opiflash_def_t opiflash_cmd_def_mxic = OPI_CMD_FORMAT_MXIC_DTR();
|
|
#endif
|
|
esp_rom_opiflash_legacy_driver_init(&opiflash_cmd_def_mxic);
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
|
|
|
// increase flash output driver strength
|
|
s_set_flash_ouput_driver_strength(1, 7);
|
|
|
|
// STR/DTR specific setting
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
|
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
|
|
s_set_pin_drive_capability(3);
|
|
s_set_flash_dtr_str_opi_mode(1, 0x1);
|
|
esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
|
|
esp_rom_spi_set_dtr_swap_mode(0, false, false);
|
|
esp_rom_spi_set_dtr_swap_mode(1, false, false);
|
|
#else //CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
s_set_pin_drive_capability(3);
|
|
bool need_swap = s_mxic_dtr_need_swap();
|
|
s_set_flash_dtr_str_opi_mode(1, 0x2);
|
|
esp_rom_opiflash_cache_mode_config(mode, &rom_opiflash_cmd_def->cache_rd_cmd);
|
|
esp_rom_spi_set_dtr_swap_mode(0, need_swap, need_swap);
|
|
esp_rom_spi_set_dtr_swap_mode(1, need_swap, need_swap);
|
|
#endif
|
|
|
|
esp_rom_opiflash_wait_idle();
|
|
}
|
|
#endif // #if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
|
|
|
|
static void s_mxic_set_required_regs(uint32_t chip_id)
|
|
{
|
|
bool is_swap = false;
|
|
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
is_swap = true;
|
|
#else
|
|
//STR mode does not need to enable ddr_swap registers
|
|
#endif
|
|
esp_rom_spi_set_dtr_swap_mode(0, is_swap, is_swap);
|
|
esp_rom_spi_set_dtr_swap_mode(1, is_swap, is_swap);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------------------------------
|
|
General Functions
|
|
-----------------------------------------------------------------------------------------------------*/
|
|
typedef struct opi_flash_func_t {
|
|
esp_err_t (*probe)(uint32_t flash_id, uint8_t *out_vendor_id); //Function pointer for detecting Flash chip vendor
|
|
void (*init)(esp_rom_spiflash_read_mode_t mode); //Function pointer for initialising certain Flash chips
|
|
void (*regs_set)(uint32_t flash_id); //Function pointer for setting required registers, decided by certain flash chips.
|
|
} opi_flash_func_t;
|
|
|
|
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
|
|
static const opi_flash_func_t opi_flash_func_mxic = {
|
|
.probe = &s_probe_mxic_chip,
|
|
.init = &s_flash_init_mxic,
|
|
.regs_set = &s_mxic_set_required_regs,
|
|
};
|
|
#endif
|
|
|
|
static const opi_flash_func_t *registered_chip_funcs[] = {
|
|
#if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP
|
|
&opi_flash_func_mxic,
|
|
#endif
|
|
NULL,
|
|
};
|
|
|
|
//To check which Flash chip is used
|
|
static const opi_flash_func_t **s_chip_func = NULL;
|
|
|
|
esp_err_t esp_opiflash_init(uint32_t chip_id)
|
|
{
|
|
esp_err_t ret = ESP_FAIL;
|
|
esp_rom_spiflash_read_mode_t mode;
|
|
#if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR
|
|
mode = ESP_ROM_SPIFLASH_OPI_STR_MODE;
|
|
#elif CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR
|
|
mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
|
|
#else
|
|
mode = ESP_ROM_SPIFLASH_FASTRD_MODE;
|
|
#endif
|
|
|
|
const opi_flash_func_t **chip_func = ®istered_chip_funcs[0];
|
|
|
|
uint8_t vendor_id = 0;
|
|
while (*chip_func) {
|
|
ret = (*chip_func)->probe(chip_id, &vendor_id);
|
|
if (ret == ESP_OK) {
|
|
// Detect this is the supported chip type
|
|
s_chip_id = chip_id;
|
|
(*chip_func)->init(mode);
|
|
s_register_rom_function();
|
|
break;
|
|
}
|
|
chip_func++;
|
|
}
|
|
s_chip_func = chip_func;
|
|
|
|
if (ret != ESP_OK) {
|
|
ESP_EARLY_LOGE(TAG, "No detected Flash chip, please check the menuconfig to see if the chip is supported");
|
|
abort();
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
/**
|
|
* Add Flash chip specifically required MSPI register settings here
|
|
*/
|
|
void esp_opiflash_set_required_regs(void)
|
|
{
|
|
(*s_chip_func)->regs_set(s_chip_id);
|
|
}
|