/* * 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 /** * 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; extern int SPI_write_enable(void *spi); static uint32_t s_vendor_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) & 0xff) != 0x80) { 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; } // 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; SPI_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; SPI_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) { static const esp_rom_opiflash_def_t opiflash_cmd_def_mxic = OPI_CMD_FORMAT_MXIC(); 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); 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, true, true); esp_rom_spi_set_dtr_swap_mode(1, true, true); #endif esp_rom_opiflash_wait_idle(); } #endif // #if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP /*---------------------------------------------------------------------------------------------------- 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 } 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 }; #endif static const opi_flash_func_t *registered_chip_funcs[] = { #if CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP &opi_flash_func_mxic, #endif 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 //To check which Flash chip is used 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 (*chip_func)->init(mode); s_vendor_id = vendor_id; s_register_rom_function(); break; } 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) { bool is_swap = false; #if CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_DTR if (s_vendor_id == ESP_FLASH_CHIP_MXIC_OCT) { 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); }