diff --git a/components/driver/spi_common.c b/components/driver/spi_common.c index b4f48c7627..d269cba95d 100644 --- a/components/driver/spi_common.c +++ b/components/driver/spi_common.c @@ -275,43 +275,23 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1); if (bus_config->mosi_io_num >= 0) { gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in); -#if CONFIG_IDF_TARGET_ESP32 gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false); -#endif } if (bus_config->miso_io_num >= 0) { gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in); -#if CONFIG_IDF_TARGET_ESP32 gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false); -#endif } if (bus_config->quadwp_io_num >= 0) { gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in); -#if CONFIG_IDF_TARGET_ESP32 gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false); -#endif } if (bus_config->quadhd_io_num >= 0) { gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in); -#if CONFIG_IDF_TARGET_ESP32 gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false); -#endif } if (bus_config->sclk_io_num >= 0) { gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in); -#if CONFIG_IDF_TARGET_ESP32 gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false); -#elif CONFIG_IDF_TARGET_ESP32S2BETA - gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false); -#endif } temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS; } else { diff --git a/components/esp32s2beta/cpu_start.c b/components/esp32s2beta/cpu_start.c index 409c07a36b..1c8a19607b 100644 --- a/components/esp32s2beta/cpu_start.c +++ b/components/esp32s2beta/cpu_start.c @@ -46,6 +46,7 @@ #include "esp_heap_caps_init.h" #include "esp_system.h" #include "esp_spi_flash.h" +#include "esp_flash_internal.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spi_flash.h" @@ -318,6 +319,11 @@ void start_cpu0_default(void) spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); + + esp_flash_app_init(); + esp_err_t flash_ret = esp_flash_init_default_chip(); + assert(flash_ret == ESP_OK); + #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 8450d05e2f..5b1ffd7e8c 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -33,14 +33,16 @@ list(APPEND srcs "src/hal/gpio_hal.c" "src/hal/uart_hal.c" "src/hal/uart_hal_iram.c" + "src/hal/spi_flash_hal.c" + "src/hal/spi_flash_hal_iram.c" ) -# TODO: SPI Flash HAL for ESP32S2Beta also if(IDF_TARGET STREQUAL "esp32") - list(APPEND srcs "src/hal/spi_flash_hal.c" - "src/hal/spi_flash_hal_iram.c" - "src/hal/mcpwm_hal.c" - ) + list(APPEND srcs "src/hal/mcpwm_hal.c") +endif() + +if(IDF_TARGET STREQUAL "esp32s2beta") + list(APPEND srcs "src/hal/spi_flash_hal_gpspi.c") endif() idf_component_register(SRCS "${srcs}" diff --git a/components/soc/esp32/include/hal/spi_flash_ll.h b/components/soc/esp32/include/hal/spi_flash_ll.h index a30284fa65..d818f011ca 100644 --- a/components/soc/esp32/include/hal/spi_flash_ll.h +++ b/components/soc/esp32/include/hal/spi_flash_ll.h @@ -153,6 +153,27 @@ static inline void spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) dev->data_buf[0] = word; } +/** + * Set the data to be written in the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data + * @param length Length of data in bytes. + */ +static inline void spi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length) +{ + // Load data registers, word at a time + int num_words = (length + 3) >> 2; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } +} + /** * Program a page of the flash chip. Call ``spi_flash_ll_set_address`` before * this to set the address to program. @@ -164,18 +185,7 @@ static inline void spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) static inline void spi_flash_ll_program_page(spi_dev_t *dev, const void *buffer, uint32_t length) { dev->user.usr_dummy = 0; - - // Load data registers, word at a time - int num_words = (length + 3) / 4; - for (int i = 0; i < num_words; i++) { - uint32_t word = 0; - uint32_t word_len = MIN(length, sizeof(word)); - memcpy(&word, buffer, word_len); - dev->data_buf[i] = word; - length -= word_len; - buffer = (void *)((intptr_t)buffer + word_len); - } - + spi_flash_ll_set_buffer_data(dev, buffer, length); dev->cmd.flash_pp = 1; } diff --git a/components/soc/esp32/include/soc/spi_caps.h b/components/soc/esp32/include/soc/spi_caps.h index bd0bdb87a5..d5b19b4d70 100644 --- a/components/soc/esp32/include/soc/spi_caps.h +++ b/components/soc/esp32/include/soc/spi_caps.h @@ -60,3 +60,4 @@ //#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS //#define SOC_SPI_SUPPORT_CD_SIG +#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(SPI_HOST) true diff --git a/components/soc/esp32s2beta/include/hal/gpspi_flash_ll.h b/components/soc/esp32s2beta/include/hal/gpspi_flash_ll.h new file mode 100644 index 0000000000..b08564856e --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/gpspi_flash_ll.h @@ -0,0 +1,319 @@ +// 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. + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include "soc/spi_periph.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" +#include // For MIN/MAX +#include +#include + + +#define gpspi_flash_ll_get_hw(host_id) (((host_id)==SPI2_HOST ? &GPSPI2 \ + : ((host_id)==SPI3_HOST ? &GPSPI3 \ + : ((host_id)==SPI4_HOST ? &GPSPI4 \ + : ({abort();(spi_dev_t*)0;}))))) + +typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t; + +//Supported clock register values +#define GPSPI_FLASH_LL_CLKREG_VAL_5MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz +#define GPSPI_FLASH_LL_CLKREG_VAL_10MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz +#define GPSPI_FLASH_LL_CLKREG_VAL_20MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz +#define GPSPI_FLASH_LL_CLKREG_VAL_26MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz +#define GPSPI_FLASH_LL_CLKREG_VAL_40MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz +#define GPSPI_FLASH_LL_CLKREG_VAL_80MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_reset(spi_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev) +{ + return (dev->cmd.val == 0); +} + +/** + * Get the read data from the buffer after ``gpspi_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) +{ + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i]; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } +} + +/** + * Write a word to the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param word Data to write at address 0. + */ +static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) +{ + dev->data_buf[0] = word; +} + +/** + * Set the data to be written in the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data + * @param length Length of data in bytes. + */ +static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length) +{ + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_user_start(spi_dev_t *dev) +{ + dev->cmd.usr = 1; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev) +{ + return dev->fsm.st != 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void gpspi_flash_ll_read_phase(spi_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void gpspi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin) +{ + dev->misc.cs0_dis = (pin == 0) ? 0 : 1; + dev->misc.cs1_dis = (pin == 1) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + typeof (dev->user) user = dev->user; + + ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M); + user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M); + + ctrl.val |= SPI_FAST_RD_MODE_M; + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + break; + case SPI_FLASH_QIO: + ctrl.fread_quad = 1; + ctrl.faddr_quad = 1; + user.fwrite_quad = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + user.fwrite_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dual = 1; + ctrl.faddr_dual = 1; + user.fwrite_dual = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + user.fwrite_dual = 1; + break; + case SPI_FLASH_SLOWRD: + ctrl.fast_rd_mode = 0; + break; + default: + abort(); + } + + dev->ctrl = ctrl; + dev->user = user; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock_reg_t *clock_val) +{ + dev->clock = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the command with fixed length (8 bits). + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + */ +static inline void gpspi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (8 - 1), + }; + dev->user2 = user2; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) +{ + dev->addr = addr; +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + dev->user1.usr_dummy_cyclelen = dummy_n - 1; +} + diff --git a/components/soc/esp32s2beta/include/hal/spi_flash_ll.h b/components/soc/esp32s2beta/include/hal/spi_flash_ll.h new file mode 100644 index 0000000000..cae39f4f91 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/spi_flash_ll.h @@ -0,0 +1,85 @@ +// 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. + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include "gpspi_flash_ll.h" +#include "spimem_flash_ll.h" + +// For esp32s2beta, spimem is equivalent to traditional spi peripherals found +// in esp32. Let the spi flash clock reg definitions reflect this. +#define SPI_FLASH_LL_CLKREG_VAL_5MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ} +#define SPI_FLASH_LL_CLKREG_VAL_10MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ} +#define SPI_FLASH_LL_CLKREG_VAL_20MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ} +#define SPI_FLASH_LL_CLKREG_VAL_26MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ} +#define SPI_FLASH_LL_CLKREG_VAL_40MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ} +#define SPI_FLASH_LL_CLKREG_VAL_80MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ} + +#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \ + : gpspi_flash_ll_get_hw(host_id))) + + +typedef union { + gpspi_flash_ll_clock_reg_t gpspi; + spimem_flash_ll_clock_reg_t spimem; +} spi_flash_ll_clock_reg_t; + +#ifdef GPSPI_BUILD +#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev) +#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev) +#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len) +#define spi_flash_ll_set_buffer_data(dev, buffer, len) gpspi_flash_ll_set_buffer_data((spi_dev_t*)dev, buffer, len) +#define spi_flash_ll_user_start(dev) gpspi_flash_ll_user_start((spi_dev_t*)dev) +#define spi_flash_ll_host_idle(dev) gpspi_flash_ll_host_idle((spi_dev_t*)dev) +#define spi_flash_ll_read_phase(dev) gpspi_flash_ll_read_phase((spi_dev_t*)dev) +#define spi_flash_ll_set_cs_pin(dev, pin) gpspi_flash_ll_set_cs_pin((spi_dev_t*)dev, pin) +#define spi_flash_ll_set_read_mode(dev, read_mode) gpspi_flash_ll_set_read_mode((spi_dev_t*)dev, read_mode) +#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk) +#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_set_command8(dev, cmd) gpspi_flash_ll_set_command8((spi_dev_t*)dev, cmd) +#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen) +#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr) +#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy) +#else +#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev) +#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_sector(dev) spimem_flash_ll_erase_sector((spi_mem_dev_t*)dev) +#define spi_flash_ll_erase_block(dev) spimem_flash_ll_erase_block((spi_mem_dev_t*)dev) +#define spi_flash_ll_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp) +#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) spimem_flash_ll_get_buffer_data((spi_mem_dev_t*)dev, buffer, read_len) +#define spi_flash_ll_set_buffer_data(dev, buffer, len) spimem_flash_ll_set_buffer_data((spi_mem_dev_t*)dev, buffer, len) +#define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len) +#define spi_flash_ll_user_start(dev) spimem_flash_ll_user_start((spi_mem_dev_t*)dev) +#define spi_flash_ll_host_idle(dev) spimem_flash_ll_host_idle((spi_mem_dev_t*)dev) +#define spi_flash_ll_read_phase(dev) spimem_flash_ll_read_phase((spi_mem_dev_t*)dev) +#define spi_flash_ll_set_cs_pin(dev, pin) spimem_flash_ll_set_cs_pin((spi_mem_dev_t*)dev, pin) +#define spi_flash_ll_set_read_mode(dev, read_mode) spimem_flash_ll_set_read_mode((spi_mem_dev_t*)dev, read_mode) +#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk) +#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_set_command8(dev, cmd) spimem_flash_ll_set_command8((spi_mem_dev_t*)dev, cmd) +#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen) +#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr) +#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy) +#endif diff --git a/components/soc/esp32s2beta/include/hal/spimem_flash_ll.h b/components/soc/esp32s2beta/include/hal/spimem_flash_ll.h new file mode 100644 index 0000000000..100dd31c99 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/spimem_flash_ll.h @@ -0,0 +1,354 @@ +// 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. + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The Lowlevel layer for SPI Flash + +#pragma once + +#include +#include // For MIN/MAX +#include +#include + +#include "soc/spi_periph.h" +#include "hal/spi_types.h" +#include "hal/spi_flash_types.h" + +#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL )) + +typedef typeof(SPIMEM1.clock) spimem_flash_ll_clock_reg_t; + +//Supported clock register values +#define SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ ((spimem_flash_ll_clock_reg_t){.val=0x000F070F}) ///< Clock set to 5 MHz +#define SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00070307}) ///< Clock set to 10 MHz +#define SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00030103}) ///< Clock set to 20 MHz +#define SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00020002}) ///< Clock set to 26 MHz +#define SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00010001}) ///< Clock set to 40 MHz +#define SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ ((spimem_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz + +/*------------------------------------------------------------------------------ + * Control + *----------------------------------------------------------------------------*/ +/** + * Reset peripheral registers before configuration and starting control + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_reset(spi_mem_dev_t *dev) +{ + dev->user.val = 0; + dev->ctrl.val = 0; +} + +/** + * Check whether the previous operation is done. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if last command is done, otherwise false. + */ +static inline bool spimem_flash_ll_cmd_is_done(const spi_mem_dev_t *dev) +{ + return (dev->cmd.val == 0); +} + +/** + * Erase the flash chip. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_chip(spi_mem_dev_t *dev) +{ + dev->cmd.flash_ce = 1; +} + +/** + * Erase the sector, the address should be set by spimem_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_sector(spi_mem_dev_t *dev) +{ + dev->ctrl.val = 0; + dev->cmd.flash_se = 1; +} + +/** + * Erase the block, the address should be set by spimem_flash_ll_set_address. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev) +{ + dev->cmd.flash_be = 1; +} + +/** + * Enable/disable write protection for the flash chip. + * + * @param dev Beginning address of the peripheral registers. + * @param wp true to enable the protection, false to disable (write enable). + */ +static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp) +{ + if (wp) { + dev->cmd.flash_wrdi = 1; + } else { + dev->cmd.flash_wren = 1; + } +} + +/** + * Get the read data from the buffer after ``spimem_flash_ll_read`` is done. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer to hold the output data + * @param read_len Length to get out of the buffer + */ +static inline void spimem_flash_ll_get_buffer_data(spi_mem_dev_t *dev, void *buffer, uint32_t read_len) +{ + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i]; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } +} + +/** + * Set the data to be written in the data buffer. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data + * @param length Length of data in bytes. + */ +static inline void spimem_flash_ll_set_buffer_data(spi_mem_dev_t *dev, const void *buffer, uint32_t length) +{ + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i] = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } +} + + +/** + * Program a page of the flash chip. Call ``spimem_flash_ll_set_address`` before + * this to set the address to program. + * + * @param dev Beginning address of the peripheral registers. + * @param buffer Buffer holding the data to program + * @param length Length to program. + */ +static inline void spimem_flash_ll_program_page(spi_mem_dev_t *dev, const void *buffer, uint32_t length) +{ + dev->user.usr_dummy = 0; + spimem_flash_ll_set_buffer_data(dev, buffer, length); + dev->cmd.flash_pp = 1; +} + +/** + * Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases, + * should be configured before this is called. + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev) +{ + dev->cmd.usr = 1; +} + +/** + * Check whether the host is idle to perform new commands. + * + * @param dev Beginning address of the peripheral registers. + * + * @return true if the host is idle, otherwise false + */ +static inline bool spimem_flash_ll_host_idle(const spi_mem_dev_t *dev) +{ + return dev->fsm.st != 0; +} + +/** + * Set phases for user-defined transaction to read + * + * @param dev Beginning address of the peripheral registers. + */ +static inline void spimem_flash_ll_read_phase(spi_mem_dev_t *dev) +{ + typeof (dev->user) user = { + .usr_command = 1, + .usr_mosi = 0, + .usr_miso = 1, + .usr_addr = 1, + }; + dev->user = user; +} +/*------------------------------------------------------------------------------ + * Configs + *----------------------------------------------------------------------------*/ +/** + * Select which pin to use for the flash + * + * @param dev Beginning address of the peripheral registers. + * @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins. + */ +static inline void spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin) +{ + dev->misc.cs0_dis = (pin == 0) ? 0 : 1; + dev->misc.cs1_dis = (pin == 1) ? 0 : 1; +} + +/** + * Set the read io mode. + * + * @param dev Beginning address of the peripheral registers. + * @param read_mode I/O mode to use in the following transactions. + */ +static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode) +{ + typeof (dev->ctrl) ctrl = dev->ctrl; + ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M); + ctrl.val |= SPI_MEM_FASTRD_MODE_M; + switch (read_mode) { + case SPI_FLASH_FASTRD: + //the default option + break; + case SPI_FLASH_QIO: + ctrl.fread_qio = 1; + break; + case SPI_FLASH_QOUT: + ctrl.fread_quad = 1; + break; + case SPI_FLASH_DIO: + ctrl.fread_dio = 1; + break; + case SPI_FLASH_DOUT: + ctrl.fread_dual = 1; + break; + case SPI_FLASH_SLOWRD: + ctrl.fastrd_mode = 0; + break; + default: + abort(); + } + dev->ctrl = ctrl; +} + +/** + * Set clock frequency to work at. + * + * @param dev Beginning address of the peripheral registers. + * @param clock_val pointer to the clock value to set + */ +static inline void spimem_flash_ll_set_clock(spi_mem_dev_t *dev, spimem_flash_ll_clock_reg_t *clock_val) +{ + dev->clock = *clock_val; +} + +/** + * Set the input length, in bits. + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of input, in bits. + */ +static inline void spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_miso = bitlen > 0; + dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the output length, in bits (not including command, address and dummy + * phases) + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of output, in bits. + */ +static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user.usr_mosi = bitlen > 0; + dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0; +} + +/** + * Set the command with fixed length (8 bits). + * + * @param dev Beginning address of the peripheral registers. + * @param command Command to send + */ +static inline void spimem_flash_ll_set_command8(spi_mem_dev_t *dev, uint8_t command) +{ + dev->user.usr_command = 1; + typeof(dev->user2) user2 = { + .usr_command_value = command, + .usr_command_bitlen = (8 - 1), + }; + dev->user2 = user2; +} + +/** + * Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param bitlen Length of the address, in bits + */ +static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t bitlen) +{ + dev->user1.usr_addr_bitlen = (bitlen - 1); + dev->user.usr_addr = bitlen ? 1 : 0; +} + +/** + * Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write... + * + * @param dev Beginning address of the peripheral registers. + * @param addr Address to send + */ +static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr) +{ + dev->addr = addr; +} + +/** + * Set the length of dummy cycles. + * + * @param dev Beginning address of the peripheral registers. + * @param dummy_n Cycles of dummy phases + */ +static inline void spimem_flash_ll_set_dummy(spi_mem_dev_t *dev, uint32_t dummy_n) +{ + dev->user.usr_dummy = dummy_n ? 1 : 0; + dev->user1.usr_dummy_cyclelen = dummy_n - 1; +} diff --git a/components/soc/esp32s2beta/include/soc/soc.h b/components/soc/esp32s2beta/include/soc/soc.h index 2f48dd7f5a..8b5af5bd4f 100644 --- a/components/soc/esp32s2beta/include/soc/soc.h +++ b/components/soc/esp32s2beta/include/soc/soc.h @@ -176,7 +176,7 @@ #define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16 #define SPI_CLK_DIV 4 #define TICKS_PER_US_ROM 40 // CPU is 80MHz -#define GPIO_MATRIX_DELAY_NS 25 +#define GPIO_MATRIX_DELAY_NS 15 //}} /* Overall memory map */ diff --git a/components/soc/esp32s2beta/include/soc/spi_caps.h b/components/soc/esp32s2beta/include/soc/spi_caps.h index eeeb5ac655..e28ed76ae7 100644 --- a/components/soc/esp32s2beta/include/soc/spi_caps.h +++ b/components/soc/esp32s2beta/include/soc/spi_caps.h @@ -26,7 +26,7 @@ #define SPI_IOMUX_PIN_NUM_WP 28 //TODO: add the next slot -#define FSPI_FUNC_NUM 0 +#define FSPI_FUNC_NUM 2 #define FSPI_IOMUX_PIN_NUM_HD 9 #define FSPI_IOMUX_PIN_NUM_CS 10 #define FSPI_IOMUX_PIN_NUM_MOSI 11 @@ -43,3 +43,7 @@ #define SOC_SPI_SUPPORT_DDRCLK 1 #define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1 #define SOC_SPI_SUPPORT_CD_SIG 1 + +// Peripheral supports DIO, DOUT, QIO, or QOUT +#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(spi_dev) (!((void*)spi_dev == (void*)&GPSPI3 \ + || (void*)spi_dev == (void*)&GPSPI4)) diff --git a/components/soc/include/hal/spi_flash_hal.h b/components/soc/include/hal/spi_flash_hal.h index ec1b361514..6992daf6e1 100644 --- a/components/soc/include/hal/spi_flash_hal.h +++ b/components/soc/include/hal/spi_flash_hal.h @@ -204,17 +204,7 @@ void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *driver); * * @return True if the buffer can be used to send data, otherwise false. */ -static inline bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p) -{ -#ifdef ESP_PLATFORM - bool direct_write = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 - || esp_ptr_in_dram(p) ); -#else - //If it is not on real chips, there is no limitation that the data has to be in DRAM. - bool direct_write = true; -#endif - return direct_write; -} +bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *driver, const void *p); /** * Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from @@ -225,15 +215,4 @@ static inline bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t * * * @return True if the buffer can be used to receive data, otherwise false. */ -static inline bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p) -{ -#ifdef ESP_PLATFORM -//currently the driver doesn't support to read through DMA, no word-aligned requirements - bool direct_read = ( ((spi_flash_memspi_data_t *)driver->driver_data)->spi != &SPI1 - || esp_ptr_in_dram(p) ); -#else - //If it is not on real chips, there is no limitation that the data has to be in DRAM. - bool direct_read = true; -#endif - return direct_read; -} \ No newline at end of file +bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p); diff --git a/components/soc/include/hal/spi_flash_types.h b/components/soc/include/hal/spi_flash_types.h index 3e825c2aa6..d68e544aba 100644 --- a/components/soc/include/hal/spi_flash_types.h +++ b/components/soc/include/hal/spi_flash_types.h @@ -23,11 +23,13 @@ extern "C" { /** Definition of a common transaction. Also holds the return value. */ typedef struct { - uint8_t command; ///< Command to send, always 8bits - uint8_t mosi_len; ///< Output data length, in bits - uint8_t miso_len; ///< Input data length, in bits - uint32_t mosi_data; ///< Output data to slave - uint32_t miso_data[2]; ///< [out] Input data from slave, little endian + uint8_t command; ///< Command to send, always 8bits + uint8_t mosi_len; ///< Output data length, in bytes + uint8_t miso_len; ///< Input data length, in bytes + uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address + uint32_t address; ///< Address to perform operation on + const uint8_t *mosi_data; ///< Output data to salve + uint8_t *miso_data; ///< [out] Input data from slave, little endian } spi_flash_trans_t; /** diff --git a/components/soc/include/soc/spi_periph.h b/components/soc/include/soc/spi_periph.h index 7748b6fbec..a6ca2acb0a 100644 --- a/components/soc/include/soc/spi_periph.h +++ b/components/soc/include/soc/spi_periph.h @@ -25,6 +25,7 @@ #include "sdkconfig.h" #if CONFIG_IDF_TARGET_ESP32S2BETA #include "soc/spi_mem_struct.h" +#include "soc/spi_mem_reg.h" #endif #ifdef __cplusplus diff --git a/components/soc/linker.lf b/components/soc/linker.lf index 847ad9086d..9d05e77103 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -19,4 +19,5 @@ entries: spi_flash_hal_iram (noflash) ledc_hal_iram (noflash_text) i2c_hal_iram (noflash) + spi_flash_hal_gpspi (noflash) lldesc (noflash_text) diff --git a/components/soc/src/hal/spi_flash_hal.c b/components/soc/src/hal/spi_flash_hal.c index ee787fd914..123bc756b0 100644 --- a/components/soc/src/hal/spi_flash_hal.c +++ b/components/soc/src/hal/spi_flash_hal.c @@ -36,12 +36,23 @@ static const spi_flash_hal_clock_config_t spi_flash_clk_cfg_reg[ESP_FLASH_SPEED_ {80e6, SPI_FLASH_LL_CLKREG_VAL_80MHZ}, }; +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA +static const spi_flash_hal_clock_config_t spi_flash_gpspi_clk_cfg_reg[ESP_FLASH_SPEED_MAX] = { + {5e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_5MHZ}}, + {10e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_10MHZ}}, + {20e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_20MHZ}}, + {26e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_26MHZ}}, + {40e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_40MHZ}}, + {80e6, {.gpspi=GPSPI_FLASH_LL_CLKREG_VAL_80MHZ}}, +}; +#endif + static inline int get_dummy_n(bool gpio_is_used, int input_delay_ns, int eff_clk) { const int apbclk_kHz = APB_CLK_FREQ / 1000; //calculate how many apb clocks a period has const int apbclk_n = APB_CLK_FREQ / eff_clk; - const int gpio_delay_ns = gpio_is_used ? (APB_CYCLE_NS * 2) : 0; + const int gpio_delay_ns = gpio_is_used ? GPIO_MATRIX_DELAY_NS : 0; //calculate how many apb clocks the delay is, the 1 is to compensate in case ``input_delay_ns`` is rounded off. int apb_period_n = (1 + input_delay_ns + gpio_delay_ns) * apbclk_kHz / 1000 / 1000; @@ -57,13 +68,38 @@ esp_err_t spi_flash_hal_init(spi_flash_memspi_data_t *data_out, const spi_flash_ if (!esp_ptr_internal(data_out)) { return ESP_ERR_INVALID_ARG; } + + spi_flash_hal_clock_config_t clock_cfg = spi_flash_clk_cfg_reg[cfg->speed]; + +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA + if (cfg->host_id > SPI_HOST) { + clock_cfg = spi_flash_gpspi_clk_cfg_reg[cfg->speed]; + } +#endif + *data_out = (spi_flash_memspi_data_t) { .spi = spi_flash_ll_get_hw(cfg->host_id), .cs_num = cfg->cs_num, - .extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, spi_flash_clk_cfg_reg[cfg->speed].freq), - .clock_conf = spi_flash_clk_cfg_reg[cfg->speed].clock_reg_val, + .extra_dummy = get_dummy_n(!cfg->iomux, cfg->input_delay_ns, clock_cfg.freq), + .clock_conf = clock_cfg.clock_reg_val, }; ESP_EARLY_LOGD(TAG, "extra_dummy: %d", data_out->extra_dummy); return ESP_OK; } + +bool spi_flash_hal_supports_direct_write(spi_flash_host_driver_t *host, const void *p) +{ + bool direct_write = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST) + || esp_ptr_in_dram(p) ); + return direct_write; +} + + +bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *host, const void *p) +{ + //currently the host doesn't support to read through dma, no word-aligned requirements + bool direct_read = ( ((spi_flash_memspi_data_t *)host->driver_data)->spi != spi_flash_ll_get_hw(SPI_HOST) + || esp_ptr_in_dram(p) ); + return direct_read; +} diff --git a/components/soc/src/hal/spi_flash_hal_common.inc b/components/soc/src/hal/spi_flash_hal_common.inc new file mode 100644 index 0000000000..fe888b3e23 --- /dev/null +++ b/components/soc/src/hal/spi_flash_hal_common.inc @@ -0,0 +1,102 @@ +// 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. + +#include +#include "hal/spi_flash_hal.h" +#include "string.h" +#include "hal/hal_defs.h" +#include "sdkconfig.h" + +#define ADDRESS_MASK_24BIT 0xFFFFFF +#define COMPUTE_DUMMY_CYCLELEN(host, base) ((base) + ((spi_flash_memspi_data_t *)(host)->driver_data)->extra_dummy) + +static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *host) +{ + return ((spi_flash_memspi_data_t *)host->driver_data)->spi; +} + +void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *host) +{ + while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) { + //nop + } +} + +esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *host) +{ + spi_flash_memspi_data_t *drv_data = (spi_flash_memspi_data_t *)host->driver_data; + spi_dev_t *dev = get_spi_dev(host); + spi_flash_ll_reset(dev); + spi_flash_ll_set_cs_pin(dev, drv_data->cs_num); + spi_flash_ll_set_clock(dev, &drv_data->clock_conf); + return ESP_OK; +} + +esp_err_t spi_flash_hal_configure_host_io_mode( + spi_flash_host_driver_t *host, + uint32_t command, + uint32_t addr_bitlen, + int dummy_cyclelen_base, + esp_flash_io_mode_t io_mode) +{ + spi_dev_t *dev = get_spi_dev(host); + + if (!SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(dev) && io_mode > SPI_FLASH_FASTRD) { + return ESP_ERR_NOT_SUPPORTED; + } + + spi_flash_ll_set_command8(dev, command); + spi_flash_ll_set_addr_bitlen(dev, addr_bitlen); + // Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary... + spi_flash_ll_set_dummy(dev, COMPUTE_DUMMY_CYCLELEN(host, dummy_cyclelen_base)); + //disable all data phases, enable them later if needed + spi_flash_ll_set_miso_bitlen(dev, 0); + spi_flash_ll_set_mosi_bitlen(dev, 0); + spi_flash_ll_set_read_mode(dev, io_mode); + return ESP_OK; +} + +esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *host, spi_flash_trans_t *trans) +{ + host->configure_host_io_mode(host, trans->command, trans->address_bitlen, 0, SPI_FLASH_FASTRD); + + spi_dev_t *dev = get_spi_dev(host); + + //disable dummy if no input phase + if (trans->miso_len == 0) { + spi_flash_ll_set_dummy(dev, 0); + } + + spi_flash_ll_set_address(dev, (trans->address & ADDRESS_MASK_24BIT) << 8); + + spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len * 8); + spi_flash_ll_set_buffer_data(dev, trans->mosi_data, trans->mosi_len); + + spi_flash_ll_set_miso_bitlen(dev, trans->miso_len * 8); + spi_flash_ll_user_start(dev); + host->poll_cmd_done(host); + spi_flash_ll_get_buffer_data(dev, trans->miso_data, trans->miso_len); + return ESP_OK; +} + +esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *host, void *buffer, uint32_t address, uint32_t read_len) +{ + spi_dev_t *dev = get_spi_dev(host); + spi_flash_ll_set_address(dev, address << 8); + spi_flash_ll_set_miso_bitlen(dev, read_len * 8); + spi_flash_ll_user_start(dev); + host->poll_cmd_done(host); + spi_flash_ll_get_buffer_data(dev, buffer, read_len); + return ESP_OK; +} diff --git a/components/soc/src/hal/spi_flash_hal_gpspi.c b/components/soc/src/hal/spi_flash_hal_gpspi.c new file mode 100644 index 0000000000..9ec34120cd --- /dev/null +++ b/components/soc/src/hal/spi_flash_hal_gpspi.c @@ -0,0 +1,39 @@ +// 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. + +#define GPSPI_BUILD + +#define spi_flash_hal_common_command spi_flash_hal_gpspi_common_command +#define spi_flash_hal_poll_cmd_done spi_flash_hal_gpspi_poll_cmd_done +#define spi_flash_hal_device_config spi_flash_hal_gpspi_device_config +#define spi_flash_hal_configure_host_io_mode spi_flash_hal_gpspi_configure_host_io_mode +#define spi_flash_hal_read spi_flash_hal_gpspi_read + +#include "spi_flash_hal_common.inc" + +bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *host, const void *p) +{ + return true; +} + +bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *host, const void *p) +{ + return true; +} + +bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + return spi_flash_ll_host_idle(dev); +} \ No newline at end of file diff --git a/components/soc/src/hal/spi_flash_hal_iram.c b/components/soc/src/hal/spi_flash_hal_iram.c index a6fb23fe5a..ea40460922 100644 --- a/components/soc/src/hal/spi_flash_hal_iram.c +++ b/components/soc/src/hal/spi_flash_hal_iram.c @@ -12,87 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include "hal/spi_flash_hal.h" -#include "string.h" -#include "hal/hal_defs.h" - -#define ADDRESS_MASK_24BIT 0xFFFFFF - -static inline spi_dev_t *get_spi_dev(spi_flash_host_driver_t *host) -{ - return ((spi_flash_memspi_data_t *)host->driver_data)->spi; -} - -void spi_flash_hal_poll_cmd_done(spi_flash_host_driver_t *host) -{ - while (!spi_flash_ll_cmd_is_done(get_spi_dev(host))) { - //nop - } -} - -esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *host) -{ - spi_flash_memspi_data_t *drv_data = (spi_flash_memspi_data_t *)host->driver_data; - spi_dev_t *dev = get_spi_dev(host); - spi_flash_ll_reset(dev); - spi_flash_ll_set_cs_pin(dev, drv_data->cs_num); - spi_flash_ll_set_clock(dev, &drv_data->clock_conf); - - /* - * workaround for the ROM: the ROM, as well as the OpenOCD, don't know the - * clock registers and the dummy are modified this help the ROM to read and - * write correctly according to the new dummy len. - */ - if (dev == &SPI1) { - //0 for cache, 1 for SPI1 - extern uint8_t g_rom_spiflash_dummy_len_plus[]; - g_rom_spiflash_dummy_len_plus[1] = drv_data->extra_dummy; - } - return ESP_OK; -} - -esp_err_t spi_flash_hal_configure_host_io_mode( - spi_flash_host_driver_t *host, - uint32_t command, - uint32_t addr_bitlen, - int dummy_cyclelen_base, - esp_flash_io_mode_t io_mode) -{ - // Add dummy cycles to compensate for latency of GPIO matrix and external delay, if necessary... - int dummy_cyclelen = dummy_cyclelen_base + ((spi_flash_memspi_data_t *)host->driver_data)->extra_dummy; - - spi_dev_t *dev = get_spi_dev(host); - spi_flash_ll_set_command8(dev, command); - spi_flash_ll_set_addr_bitlen(dev, addr_bitlen); - spi_flash_ll_set_dummy(dev, dummy_cyclelen); - //disable all data phases, enable them later if needed - spi_flash_ll_set_miso_bitlen(dev, 0); - spi_flash_ll_set_mosi_bitlen(dev, 0); - spi_flash_ll_set_read_mode(dev, io_mode); - return ESP_OK; -} - -esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *host, spi_flash_trans_t *trans) -{ - host->configure_host_io_mode(host, trans->command, 0, 0, SPI_FLASH_FASTRD); - - spi_dev_t *dev = get_spi_dev(host); - //disable dummy if no input phase - if (trans->miso_len == 0) { - spi_flash_ll_set_dummy(dev, 0); - } - - spi_flash_ll_set_miso_bitlen(dev, trans->miso_len); - spi_flash_ll_set_mosi_bitlen(dev, trans->mosi_len); - - spi_flash_ll_write_word(dev, trans->mosi_data); - - spi_flash_ll_user_start(dev); - host->poll_cmd_done(host); - spi_flash_ll_get_buffer_data(dev, trans->miso_data, 8); - return ESP_OK; -} +#include "spi_flash_hal_common.inc" void spi_flash_hal_erase_chip(spi_flash_host_driver_t *host) { @@ -128,33 +48,6 @@ void spi_flash_hal_program_page(spi_flash_host_driver_t *host, const void *buffe host->poll_cmd_done(host); } -esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *host, void *buffer, uint32_t address, uint32_t read_len) -{ - spi_dev_t *dev = get_spi_dev(host); - //the command is already set by ``spi_flash_hal_configure_host_io_mode`` before. - spi_flash_ll_set_address(dev, address << 8); - spi_flash_ll_set_miso_bitlen(dev, read_len * 8); - spi_flash_ll_user_start(dev); - host->poll_cmd_done(host); - spi_flash_ll_get_buffer_data(dev, buffer, read_len); - return ESP_OK; -} - - -bool spi_flash_hal_host_idle(spi_flash_host_driver_t *host) -{ - spi_dev_t *dev = get_spi_dev(host); - bool idle = spi_flash_ll_host_idle(dev); - - // Not clear if this is necessary, or only necessary if - // chip->spi == SPI1. But probably doesn't hurt... - if (dev == &SPI1) { - idle &= spi_flash_ll_host_idle(&SPI0); - } - - return idle; -} - esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *host, bool wp) { spi_dev_t *dev = get_spi_dev(host); @@ -162,3 +55,21 @@ esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_driver_t *host, bool wp host->poll_cmd_done(host); return ESP_OK; } + +bool spi_flash_hal_host_idle(spi_flash_host_driver_t *chip_drv) +{ + spi_dev_t *dev = get_spi_dev(chip_drv); + bool idle = spi_flash_ll_host_idle(dev); + + // Not clear if this is necessary, or only necessary if + // chip->spi == SPI1. But probably doesn't hurt... + if ((void*) dev == spi_flash_ll_get_hw(SPI_HOST)) { +#if CONFIG_IDF_TARGET_ESP32 + idle &= spi_flash_ll_host_idle(&SPI0); +#elif CONFIG_IDF_TARGET_ESP32S2BETA + idle &= spi_flash_ll_host_idle(&SPIMEM0); +#endif + } + + return idle; +} \ No newline at end of file diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index 69c140a518..c4e047bcf8 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,4 +1,5 @@ set(priv_requires bootloader_support soc) + if(BOOTLOADER_BUILD) if (CONFIG_IDF_TARGET_ESP32) # ESP32 Bootloader needs SPIUnlock from this file, but doesn't @@ -33,18 +34,15 @@ else() "spi_flash_chip_drivers.c" "spi_flash_chip_generic.c" "spi_flash_chip_issi.c" - "spi_flash_chip_gd.c") + "spi_flash_chip_gd.c" + "memspi_host_driver.c") - if (NOT CONFIG_IDF_TARGET_ESP32S2BETA) - # TODO: workaround until ESP32-S2 supports new API, can be always included - list(APPEND srcs - "memspi_host_driver.c") - list(APPEND cache_srcs + list(APPEND cache_srcs "esp_flash_api.c" "esp_flash_spi_init.c" "spi_flash_os_func_app.c" "spi_flash_os_func_noos.c") - endif() + list(APPEND srcs ${cache_srcs}) set(priv_requires bootloader_support app_update soc) endif() diff --git a/components/spi_flash/Kconfig b/components/spi_flash/Kconfig index 206a6d5694..046146e006 100644 --- a/components/spi_flash/Kconfig +++ b/components/spi_flash/Kconfig @@ -77,15 +77,6 @@ menu "SPI Flash driver" bool "Allowed" endchoice - # Force the Legacy implementation to be used on ESP32S2Beta - # - # TODO esp32s2beta: Remove once SPI Flash HAL available on S2 Beta - config SPI_FLASH_FORCE_LEGACY_ESP32S2BETA - bool - default y - depends on IDF_TARGET_ESP32S2BETA - select SPI_FLASH_USE_LEGACY_IMPL - config SPI_FLASH_USE_LEGACY_IMPL bool "Use the legacy implementation before IDF v4.0" default n diff --git a/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c index 6241f399d2..1a6aa109c2 100644 --- a/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c +++ b/components/spi_flash/esp32s2beta/flash_ops_esp32s2beta.c @@ -16,12 +16,12 @@ #include #include "esp_spi_flash.h" -#include "esp_spi_flash_chip.h" -#include "cache_utils.h" #include "soc/system_reg.h" #include "soc/soc_memory_layout.h" #include "esp32s2beta/rom/spi_flash.h" #include "esp32s2beta/rom/cache.h" +#include "hal/spi_flash_hal.h" +#include "esp_flash.h" esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_addr, const void *src, size_t size) { @@ -48,7 +48,7 @@ esp_rom_spiflash_result_t IRAM_ATTR spi_flash_write_encrypted_chip(size_t dest_a return ESP_ROM_SPIFLASH_RESULT_OK; } else { // Already in internal memory - rc = spi_flash_unlock(); + rc = esp_rom_spiflash_unlock(); if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { return rc; } @@ -113,7 +113,7 @@ esp_err_t spi_flash_enable_wrap(uint32_t wrap_size) } } -void spi_flash_disable_wrap() +void spi_flash_disable_wrap(void) { spi_flash_wrap_set(FLASH_WRAP_MODE_DISABLE); } diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 67e7d2064b..7299cb47ba 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -70,17 +70,15 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f int cs_io_num = config->cs_io_num; int spics_in = spi_periph_signal[config->host_id].spics_in; int spics_out = spi_periph_signal[config->host_id].spics_out[config->cs_id]; + int spics_func = spi_periph_signal[config->host_id].func; uint32_t iomux_reg = GPIO_PIN_MUX_REG[cs_io_num]; //To avoid the panic caused by flash data line conflicts during cs line //initialization, disable the cache temporarily chip->os_func->start(chip->os_func_data); if (use_iomux) { - GPIO.func_in_sel_cfg[spics_in].sig_in_sel = 0; - PIN_INPUT_ENABLE(iomux_reg); - GPIO.func_out_sel_cfg[spics_out].oen_sel = 0; - GPIO.func_out_sel_cfg[spics_out].oen_inv_sel = false; - PIN_FUNC_SELECT(iomux_reg, 1); + gpio_iomux_in(cs_io_num, spics_in); + gpio_iomux_out(cs_io_num, spics_func, false); } else { PIN_INPUT_ENABLE(iomux_reg); if (cs_io_num < 32) { diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h index a200f20edd..8832adfcc2 100644 --- a/components/spi_flash/include/memspi_host_driver.h +++ b/components/spi_flash/include/memspi_host_driver.h @@ -99,3 +99,44 @@ esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *o * @return always ESP_OK. */ esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size); + +/** + * Erase contents of entire chip. + * + * @param driver The driver context. + */ +void memspi_host_erase_chip(spi_flash_host_driver_t *driver); + +/** + * Erase a sector starting from a given address. + * + * @param driver The driver context. + * @param start_address Starting address of the sector. + */ +void memspi_host_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Erase a block starting from a given address. + * + * @param driver The driver context. + * @param start_address Starting address of the block. + */ +void memspi_host_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address); + +/** + * Program a page with contents of a buffer. + * + * @param driver The driver context. + * @param buffer Buffer which contains the data to be flashed. + * @param address Starting address of where to flash the data. + * @param length The number of bytes to flash. + */ +void memspi_host_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length); + +/** + * Set ability to write to chip. + * + * @param driver The driver context. + * @param wp Enable or disable write protect (true - enable, false - disable). + */ +esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *driver, bool wp); diff --git a/components/spi_flash/memspi_host_driver.c b/components/spi_flash/memspi_host_driver.c index adc900cd7a..99a0625178 100644 --- a/components/spi_flash/memspi_host_driver.c +++ b/components/spi_flash/memspi_host_driver.c @@ -22,9 +22,56 @@ static const char TAG[] = "memspi"; static const spi_flash_host_driver_t esp_flash_default_host = ESP_FLASH_DEFAULT_HOST_DRIVER(); +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA +extern void spi_flash_hal_gpspi_poll_cmd_done(spi_flash_host_driver_t *driver); +extern esp_err_t spi_flash_hal_gpspi_device_config(spi_flash_host_driver_t *driver); +esp_err_t spi_flash_hal_gpspi_configure_host_io_mode( + spi_flash_host_driver_t *host, + uint32_t command, + uint32_t addr_bitlen, + int dummy_cyclelen_base, + esp_flash_io_mode_t io_mode); +extern esp_err_t spi_flash_hal_gpspi_common_command(spi_flash_host_driver_t *chip_drv, spi_flash_trans_t *trans); +extern esp_err_t spi_flash_hal_gpspi_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len); +extern bool spi_flash_hal_gpspi_host_idle(spi_flash_host_driver_t *chip_drv); +extern bool spi_flash_hal_gpspi_supports_direct_write(spi_flash_host_driver_t *driver, const void *p); +extern bool spi_flash_hal_gpspi_supports_direct_read(spi_flash_host_driver_t *driver, const void *p); + +/** Default configuration for GPSPI */ +static const spi_flash_host_driver_t esp_flash_gpspi_host = { + .dev_config = spi_flash_hal_gpspi_device_config, + .common_command = spi_flash_hal_gpspi_common_command, + .read_id = memspi_host_read_id_hs, + .erase_chip = memspi_host_erase_chip, + .erase_sector = memspi_host_erase_sector, + .erase_block = memspi_host_erase_block, + .read_status = memspi_host_read_status_hs, + .set_write_protect = memspi_host_set_write_protect, + .supports_direct_write = spi_flash_hal_gpspi_supports_direct_write, + .supports_direct_read = spi_flash_hal_gpspi_supports_direct_read, + .program_page = memspi_host_program_page, + .max_write_bytes = SPI_FLASH_HAL_MAX_WRITE_BYTES, + .read = spi_flash_hal_gpspi_read, + .max_read_bytes = SPI_FLASH_HAL_MAX_READ_BYTES, + .host_idle = spi_flash_hal_gpspi_host_idle, + .configure_host_io_mode = spi_flash_hal_gpspi_configure_host_io_mode, + .poll_cmd_done = spi_flash_hal_gpspi_poll_cmd_done, + .flush_cache = NULL, +}; +#endif + esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_data_t *data, const memspi_host_config_t *cfg) { +#ifdef CONFIG_IDF_TARGET_ESP32 memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t)); +#elif CONFIG_IDF_TARGET_ESP32S2BETA + if (cfg->host_id == SPI_HOST) + memcpy(host, &esp_flash_default_host, sizeof(spi_flash_host_driver_t)); + else { + memcpy(host, &esp_flash_gpspi_host, sizeof(spi_flash_host_driver_t)); + } +#endif + esp_err_t err = spi_flash_hal_init(data, cfg); if (err != ESP_OK) { return err; @@ -32,7 +79,7 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d host->driver_data = data; //some functions are not required if not SPI1 - if (data->spi != &SPI1) { + if ((void*)data->spi != (void*)spi_flash_ll_get_hw(SPI_HOST)) { host->flush_cache = NULL; } return ESP_OK; @@ -40,21 +87,20 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id) { - //NOTE: we do have a read id function, however it doesn't work in high freq + uint32_t id_buf = 0; spi_flash_trans_t t = { .command = CMD_RDID, - .mosi_data = 0, - .mosi_len = 0, - .miso_len = 24 + .miso_len = 3, + .miso_data = ((uint8_t*) &id_buf), }; host->common_command(host, &t); - uint32_t raw_flash_id = t.miso_data[0]; + + uint32_t raw_flash_id = id_buf; ESP_EARLY_LOGV(TAG, "raw_chip_id: %X\n", raw_flash_id); if (raw_flash_id == 0xFFFFFF || raw_flash_id == 0) { ESP_EARLY_LOGE(TAG, "no response\n"); return ESP_ERR_FLASH_NO_RESPONSE; } - // Byte swap the flash id as it's usually written the other way around uint8_t mfg_id = raw_flash_id & 0xFF; uint16_t flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00); @@ -66,24 +112,84 @@ esp_err_t memspi_host_read_id_hs(spi_flash_host_driver_t *host, uint32_t *id) esp_err_t memspi_host_read_status_hs(spi_flash_host_driver_t *driver, uint8_t *out_sr) { //NOTE: we do have a read id function, however it doesn't work in high freq + uint32_t stat_buf = 0; spi_flash_trans_t t = { .command = CMD_RDSR, - .mosi_data = 0, - .mosi_len = 0, - .miso_len = 8 + .miso_data = ((uint8_t*) &stat_buf), + .miso_len = 1 }; esp_err_t err = driver->common_command(driver, &t); if (err != ESP_OK) { return err; } - *out_sr = t.miso_data[0]; + *out_sr = stat_buf; return ESP_OK; } esp_err_t memspi_host_flush_cache(spi_flash_host_driver_t* driver, uint32_t addr, uint32_t size) { - if (((memspi_host_data_t*)(driver->driver_data))->spi == &SPI1) { + if ((void*)((memspi_host_data_t*)(driver->driver_data))->spi == (void*) spi_flash_ll_get_hw(SPI_HOST)) { spi_flash_check_and_flush_cache(addr, size); } return ESP_OK; -} \ No newline at end of file +} + +void memspi_host_erase_chip(spi_flash_host_driver_t *chip_drv) +{ + spi_flash_trans_t t = { 0 }; + t.command = CMD_CHIP_ERASE; + chip_drv->common_command(chip_drv, &t); +} + +void memspi_host_erase_sector(spi_flash_host_driver_t *chip_drv, uint32_t start_address) +{ + spi_flash_trans_t t = { + .command = CMD_SECTOR_ERASE, + .address_bitlen = 24, + .address = start_address + }; + chip_drv->common_command(chip_drv, &t); +} + +void memspi_host_erase_block(spi_flash_host_driver_t *chip_drv, uint32_t start_address) +{ + spi_flash_trans_t t = { + .command = CMD_LARGE_BLOCK_ERASE, + .address_bitlen = 24, + .address = start_address, + }; + chip_drv->common_command(chip_drv, &t); +} + +void memspi_host_program_page(spi_flash_host_driver_t *chip_drv, const void *buffer, uint32_t address, uint32_t length) +{ + spi_flash_trans_t t = { + .command = CMD_PROGRAM_PAGE, + .address_bitlen = 24, + .address = address, + .mosi_len = length, + .mosi_data = buffer + }; + chip_drv->common_command(chip_drv, &t); +} + +esp_err_t memspi_host_read(spi_flash_host_driver_t *chip_drv, void *buffer, uint32_t address, uint32_t read_len) +{ + spi_flash_trans_t t = { + .address_bitlen = 24, + .address = address, + .miso_len = read_len, + .miso_data = buffer + }; + chip_drv->common_command(chip_drv, &t); + return ESP_OK; +} + +esp_err_t memspi_host_set_write_protect(spi_flash_host_driver_t *chip_drv, bool wp) +{ + spi_flash_trans_t t = { + .command = wp ? CMD_WRDI : CMD_WREN + }; + chip_drv->common_command(chip_drv, &t); + return ESP_OK; +} diff --git a/components/spi_flash/private_include/spi_flash_defs.h b/components/spi_flash/private_include/spi_flash_defs.h index b210271e74..cd2e77fbb5 100644 --- a/components/spi_flash/private_include/spi_flash_defs.h +++ b/components/spi_flash/private_include/spi_flash_defs.h @@ -19,8 +19,8 @@ */ #define CMD_RDID 0x9F #define CMD_WRSR 0x01 -#define SR_WIP (1<<0) /* Status register write-in-progress bit */ -#define SR_WREN (1<<1) /* Status register write enable bit */ +#define SR_WIP (1<<0) /* Status register write-in-progress bit */ +#define SR_WREN (1<<1) /* Status register write enable bit */ #define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */ #define CMD_WREN 0x06 #define CMD_WRDI 0x04 @@ -37,8 +37,7 @@ #define CMD_CHIP_ERASE 0xC7 #define CMD_SECTOR_ERASE 0x20 #define CMD_LARGE_BLOCK_ERASE 0xD8 /* 64KB block erase command */ +#define CMD_PROGRAM_PAGE 0x02 #define CMD_RST_EN 0x66 #define CMD_RST_DEV 0x99 - - diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 23172fb938..c072b93374 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -140,7 +140,12 @@ esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t { esp_err_t err = ESP_OK; // Configure the host, and return - spi_flash_chip_generic_config_host_io_mode(chip); + err = spi_flash_chip_generic_config_host_io_mode(chip); + + if (err == ESP_ERR_NOT_SUPPORTED) { + ESP_LOGE(TAG, "configure host io mode failed - unsupported"); + return err; + } while (err == ESP_OK && length > 0) { uint32_t read_len = MIN(length, chip->host->max_read_bytes); @@ -386,14 +391,14 @@ const spi_flash_chip_t esp_flash_chip_generic = { static esp_err_t spi_flash_common_read_qe_sr(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_sr_bitwidth, uint32_t *sr) { + uint32_t sr_buf = 0; spi_flash_trans_t t = { .command = qe_rdsr_command, - .mosi_data = 0, - .mosi_len = 0, - .miso_len = qe_sr_bitwidth, + .miso_data = (uint8_t*) &sr_buf, + .miso_len = qe_sr_bitwidth / 8, }; esp_err_t ret = chip->host->common_command(chip->host, &t); - *sr = t.miso_data[0]; + *sr = sr_buf; return ret; } @@ -401,8 +406,8 @@ static esp_err_t spi_flash_common_write_qe_sr(esp_flash_t *chip, uint8_t qe_wrsr { spi_flash_trans_t t = { .command = qe_wrsr_command, - .mosi_data = qe, - .mosi_len = qe_sr_bitwidth, + .mosi_data = ((uint8_t*) &qe), + .mosi_len = qe_sr_bitwidth / 8, .miso_len = 0, }; return chip->host->common_command(chip->host, &t); diff --git a/components/spi_flash/spi_flash_os_func_app.c b/components/spi_flash/spi_flash_os_func_app.c index 655d129404..d1f0d2b210 100644 --- a/components/spi_flash/spi_flash_os_func_app.c +++ b/components/spi_flash/spi_flash_os_func_app.c @@ -17,6 +17,7 @@ #include "esp_spi_flash.h" //for ``g_flash_guard_default_ops`` #include "esp_flash.h" #include "esp_flash_partitions.h" +#include "hal/spi_types.h" #ifdef CONFIG_IDF_TARGET_ESP32 @@ -99,23 +100,29 @@ static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_a } static DRAM_ATTR spi1_app_func_arg_t spi1_arg = { - .host_id = 0, //for SPI1, + .host_id = SPI1_HOST, //for SPI1, .no_protect = true, }; static DRAM_ATTR spi1_app_func_arg_t main_flash_arg = { - .host_id = 0, //for SPI1, + .host_id = SPI1_HOST, //for SPI1, .no_protect = false, }; static app_func_arg_t spi2_arg = { - .host_id = 1, //for SPI2, + .host_id = SPI2_HOST, //for SPI2, }; static app_func_arg_t spi3_arg = { - .host_id = 2, //for SPI3, + .host_id = SPI3_HOST, //for SPI3, }; +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA +static app_func_arg_t spi4_arg = { + .host_id = SPI4_HOST, //for SPI4, +}; +#endif + //for SPI1, we have to disable the cache and interrupts before using the SPI bus const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functions = { .start = spi1_start, @@ -132,14 +139,22 @@ const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = { esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id) { - if (host_id == 0) { + if (host_id == SPI1_HOST) { //SPI1 chip->os_func = &esp_flash_spi1_default_os_functions; chip->os_func_data = &spi1_arg; - } else if (host_id == 1 || host_id == 2) { - //SPI2,3 + } else if (host_id == SPI2_HOST || host_id == SPI3_HOST +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA + || host_id == SPI4_HOST +#endif + ) { + //SPI2,3,4 chip->os_func = &esp_flash_spi23_default_os_functions; - chip->os_func_data = (host_id == 1) ? &spi2_arg : &spi3_arg; +#if CONFIG_IDF_TARGET_ESP32 + chip->os_func_data = (host_id == SPI2_HOST) ? &spi2_arg : &spi3_arg; +#elif CONFIG_IDF_TARGET_ESP32S2BETA + chip->os_func_data = (host_id == SPI2_HOST) ? &spi2_arg : ((host_id == SPI3_HOST) ? &spi3_arg : &spi4_arg); +#endif } else { return ESP_ERR_INVALID_ARG; } diff --git a/components/spi_flash/spi_flash_os_func_noos.c b/components/spi_flash/spi_flash_os_func_noos.c index 6595a4781e..e1fde7db2d 100644 --- a/components/spi_flash/spi_flash_os_func_noos.c +++ b/components/spi_flash/spi_flash_os_func_noos.c @@ -17,28 +17,51 @@ #include "esp_flash.h" #include "esp_attr.h" -#ifdef CONFIG_IDF_TARGET_ESP32 +#if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" #include "esp32/rom/cache.h" -#else +#elif CONFIG_IDF_TARGET_ESP32S2BETA #include "esp32s2beta/rom/ets_sys.h" #include "esp32s2beta/rom/cache.h" #endif +#include "esp_attr.h" + +#if CONFIG_IDF_TARGET_ESP32S2BETA +typedef struct { + uint32_t icache_autoload; + uint32_t dcache_autoload; +} spi_noos_arg_t; + +static DRAM_ATTR spi_noos_arg_t spi_arg = { 0 }; +#endif static IRAM_ATTR esp_err_t start(void *arg) { +#if CONFIG_IDF_TARGET_ESP32 Cache_Read_Disable(0); Cache_Read_Disable(1); +#elif CONFIG_IDF_TARGET_ESP32S2BETA + spi_noos_arg_t *spi_arg = arg; + spi_arg->icache_autoload = Cache_Suspend_ICache(); + spi_arg->dcache_autoload = Cache_Suspend_DCache(); +#endif return ESP_OK; } static IRAM_ATTR esp_err_t end(void *arg) { +#if CONFIG_IDF_TARGET_ESP32 Cache_Flush(0); Cache_Flush(1); Cache_Read_Enable(0); Cache_Read_Enable(1); +#elif CONFIG_IDF_TARGET_ESP32S2BETA + spi_noos_arg_t *spi_arg = arg; + Cache_Invalidate_ICache_All(); + Cache_Resume_ICache(spi_arg->icache_autoload); + Cache_Resume_DCache(spi_arg->dcache_autoload); +#endif return ESP_OK; } @@ -58,5 +81,10 @@ const DRAM_ATTR esp_flash_os_functions_t esp_flash_noos_functions = { esp_err_t IRAM_ATTR esp_flash_app_disable_os_functions(esp_flash_t* chip) { chip->os_func = &esp_flash_noos_functions; + +#if CONFIG_IDF_TARGET_ESP32S2BETA + chip->os_func_data = &spi_arg; +#endif + return ESP_OK; } diff --git a/components/spi_flash/test/CMakeLists.txt b/components/spi_flash/test/CMakeLists.txt index 3980437baf..5a3db1ddaf 100644 --- a/components/spi_flash/test/CMakeLists.txt +++ b/components/spi_flash/test/CMakeLists.txt @@ -1,15 +1,9 @@ -set(src_dirs ".") -set(exclude_srcs) - -if(IDF_TARGET STREQUAL "esp32") - list(APPEND src_dirs "esp32") - if(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) - set(exclude_srcs "esp32/test_esp_flash.c" "esp32/test_partition_ext.c") - endif() +if(CONFIG_SPI_FLASH_USE_LEGACY_IMPL) + set(exclude_srcs "test_esp_flash.c" "test_partition_ext.c") endif() -idf_component_register(SRC_DIRS ${src_dirs} - EXCLUDE_SRCS ${exclude_srcs} +idf_component_register(SRC_DIRS "." + EXCLUDE_SRCS "${exclude_srcs}" INCLUDE_DIRS "." REQUIRES unity test_utils spi_flash bootloader_support app_update) diff --git a/components/spi_flash/test/esp32/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c similarity index 80% rename from components/spi_flash/test/esp32/test_esp_flash.c rename to components/spi_flash/test/test_esp_flash.c index 0e5679f738..c5ca730d62 100644 --- a/components/spi_flash/test/esp32/test_esp_flash.c +++ b/components/spi_flash/test/test_esp_flash.c @@ -18,27 +18,55 @@ #include "soc/io_mux_reg.h" #include "sdkconfig.h" +#include "hal/spi_flash_hal.h" + #define FUNC_SPI 1 static uint8_t sector_buf[4096]; #define TEST_SPI_SPEED ESP_FLASH_10MHZ #define TEST_SPI_READ_MODE SPI_FLASH_FASTRD -//#define FORCE_GPIO_MATRIX +// #define FORCE_GPIO_MATRIX #define EXTRA_SPI1_CLK_IO 17 //the pin which is usually used by the PSRAM clk +#if CONFIG_IDF_TARGET_ESP32 #define HSPI_PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI #define HSPI_PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO #define HSPI_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK #define HSPI_PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD #define HSPI_PIN_NUM_WP HSPI_IOMUX_PIN_NUM_WP +#define HSPI_PIN_NUM_CS HSPI_IOMUX_PIN_NUM_CS #define VSPI_PIN_NUM_MOSI VSPI_IOMUX_PIN_NUM_MOSI #define VSPI_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO #define VSPI_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK #define VSPI_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD #define VSPI_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP +#define VSPI_PIN_NUM_CS VSPI_IOMUX_PIN_NUM_CS +#elif CONFIG_IDF_TARGET_ESP32S2BETA +#define FSPI_PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI +#define FSPI_PIN_NUM_MISO FSPI_IOMUX_PIN_NUM_MISO +#define FSPI_PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK +#define FSPI_PIN_NUM_HD FSPI_IOMUX_PIN_NUM_HD +#define FSPI_PIN_NUM_WP FSPI_IOMUX_PIN_NUM_WP +#define FSPI_PIN_NUM_CS FSPI_IOMUX_PIN_NUM_CS + +// Just use the same pins for HSPI and VSPI +#define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI +#define HSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO +#define HSPI_PIN_NUM_CLK FSPI_PIN_NUM_CLK +#define HSPI_PIN_NUM_HD FSPI_PIN_NUM_HD +#define HSPI_PIN_NUM_WP FSPI_PIN_NUM_WP +#define HSPI_PIN_NUM_CS FSPI_PIN_NUM_CS + +#define VSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI +#define VSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO +#define VSPI_PIN_NUM_CLK FSPI_PIN_NUM_CLK +#define VSPI_PIN_NUM_HD FSPI_PIN_NUM_HD +#define VSPI_PIN_NUM_WP FSPI_PIN_NUM_WP +#define VSPI_PIN_NUM_CS FSPI_PIN_NUM_CS +#endif #define ALL_TEST_NUM (sizeof(config_list)/sizeof(flashtest_config_t)) typedef void (*flash_test_func_t)(esp_flash_t* chip); @@ -50,7 +78,7 @@ typedef void (*flash_test_func_t)(esp_flash_t* chip); #define FLASH_TEST_CASE_3(STR, FUNCT_TO_RUN) #else #define FLASH_TEST_CASE_3(STR, FUNC_TO_RUN) \ - TEST_CASE(STR", 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") {flash_test_func(FUNC_TO_RUN, ALL_TEST_NUM);} + TEST_CASE_ESP32(STR", 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") {flash_test_func(FUNC_TO_RUN, ALL_TEST_NUM);} #endif //currently all the configs are the same with esp_flash_spi_device_config_t, no more information required @@ -58,38 +86,68 @@ typedef esp_flash_spi_device_config_t flashtest_config_t; static const char TAG[] = "test_esp_flash"; +#define FLASHTEST_CONFIG_COMMON \ + /* 0 always reserved for main flash */ \ + { \ + /* no need to init */ \ + .host_id = -1, \ + }, \ + { \ + .io_mode = TEST_SPI_READ_MODE,\ + .speed = TEST_SPI_SPEED, \ + .host_id = SPI_HOST, \ + .cs_id = 1, \ + /* the pin which is usually used by the PSRAM */ \ + .cs_io_num = 16, \ + .input_delay_ns = 0, \ + } + +#if CONFIG_IDF_TARGET_ESP32 flashtest_config_t config_list[] = { - // 0 always reserved for main flash - { - .host_id = -1, // no need to init - }, - { - .io_mode = TEST_SPI_READ_MODE, - .speed = TEST_SPI_SPEED, - .host_id = SPI_HOST, - .cs_id = 1, - .cs_io_num = 16, //the pin which is usually used by the PSRAM - .input_delay_ns = 0, - }, - /* current runner doesn't have a flash on HSPI - { - .io_mode = TEST_SPI_READ_MODE, - .speed = TEST_SPI_SPEED, - .host = HSPI_HOST, - .cs_id = 0, - .cs_io_num = HSPI_IOMUX_PIN_NUM_CS, - .input_delay_ns = 20, - }, - */ + FLASHTEST_CONFIG_COMMON, + /* current runner doesn't have a flash on HSPI */ + // { + // .io_mode = TEST_SPI_READ_MODE, + // .speed = TEST_SPI_SPEED, + // .host_id = HSPI_HOST, + // .cs_id = 0, + // // uses GPIO matrix on esp32s2beta regardles if FORCE_GPIO_MATRIX + // .cs_io_num = HSPI_PIN_NUM_CS, + // .input_delay_ns = 20, + // }, { .io_mode = TEST_SPI_READ_MODE, .speed = TEST_SPI_SPEED, .host_id = VSPI_HOST, .cs_id = 0, - .cs_io_num = VSPI_IOMUX_PIN_NUM_CS, + .cs_io_num = VSPI_PIN_NUM_CS, .input_delay_ns = 0, }, }; +#elif CONFIG_IDF_TARGET_ESP32S2BETA +flashtest_config_t config_list[] = { + FLASHTEST_CONFIG_COMMON, + /* No runners for esp32s2beta for these config yet */ + // { + // .io_mode = TEST_SPI_READ_MODE, + // .speed = TEST_SPI_SPEED, + // .host_id = FSPI_HOST, + // .cs_id = 0, + // .cs_io_num = FSPI_PIN_NUM_CS, + // .input_delay_ns = 0, + // }, + // /* current runner doesn't have a flash on HSPI */ + // { + // .io_mode = TEST_SPI_READ_MODE, + // .speed = TEST_SPI_SPEED, + // .host_id = HSPI_HOST, + // .cs_id = 0, + // // uses GPIO matrix on esp32s2beta regardles if FORCE_GPIO_MATRIX + // .cs_io_num = HSPI_PIN_NUM_CS, + // .input_delay_ns = 20, + // }, +}; +#endif static void setup_bus(spi_host_device_t host_id) { @@ -98,10 +156,27 @@ static void setup_bus(spi_host_device_t host_id) //no need to initialize the bus, however the CLK may need one more output if it's on the usual place of PSRAM #ifdef EXTRA_SPI1_CLK_IO gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0); +#endif +#if CONFIG_IDF_TARGET_ESP32S2BETA + } else if (host_id == FSPI_HOST) { + ESP_LOGI(TAG, "setup flash on SPI%d (FSPI) CS0...\n", host_id + 1); + spi_bus_config_t fspi_bus_cfg = { + .mosi_io_num = FSPI_PIN_NUM_MOSI, + .miso_io_num = FSPI_PIN_NUM_MISO, + .sclk_io_num = FSPI_PIN_NUM_CLK, + .quadhd_io_num = FSPI_PIN_NUM_HD, + .quadwp_io_num = FSPI_PIN_NUM_WP, + .max_transfer_sz = 64, + }; +#ifdef FORCE_GPIO_MATRIX + fspi_bus_cfg.quadhd_io_num = 5; +#endif + esp_err_t ret = spi_bus_initialize(host_id, &fspi_bus_cfg, 0); + TEST_ESP_OK(ret); #endif //currently the SPI bus for main flash chip is initialized through GPIO matrix } else if (host_id == HSPI_HOST) { - ESP_LOGI(TAG, "setup flash on SPI2 (HSPI) CS0...\n"); + ESP_LOGI(TAG, "setup flash on SPI%d (HSPI) CS0...\n", host_id + 1); spi_bus_config_t hspi_bus_cfg = { .mosi_io_num = HSPI_PIN_NUM_MOSI, .miso_io_num = HSPI_PIN_NUM_MISO, @@ -110,13 +185,26 @@ static void setup_bus(spi_host_device_t host_id) .quadwp_io_num = HSPI_PIN_NUM_WP, .max_transfer_sz = 64, }; +#ifdef CONFIG_IDF_TARGET_ESP32 #ifdef FORCE_GPIO_MATRIX hspi_bus_cfg.quadhd_io_num = 23; +#endif #endif esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0); TEST_ESP_OK(ret); - } else if (host_id == VSPI_HOST) { - ESP_LOGI(TAG, "setup flash on SPI3 (VSPI) CS0...\n"); + +#ifdef CONFIG_IDF_TARGET_ESP32S2BETA + // HSPI have no multiline mode, use GPIO to pull those pins up + gpio_set_direction(HSPI_PIN_NUM_HD, GPIO_MODE_OUTPUT); + gpio_set_level(HSPI_PIN_NUM_HD, 1); + + gpio_set_direction(HSPI_PIN_NUM_WP, GPIO_MODE_OUTPUT); + gpio_set_level(HSPI_PIN_NUM_WP, 1); +#endif + } +#if CONFIG_IDF_TARGET_ESP32 + else if (host_id == VSPI_HOST) { + ESP_LOGI(TAG, "setup flash on SPI%d (VSPI) CS0...\n", host_id + 1); spi_bus_config_t vspi_bus_cfg = { .mosi_io_num = VSPI_PIN_NUM_MOSI, .miso_io_num = VSPI_PIN_NUM_MISO, @@ -130,14 +218,20 @@ static void setup_bus(spi_host_device_t host_id) #endif esp_err_t ret = spi_bus_initialize(host_id, &vspi_bus_cfg, 0); TEST_ESP_OK(ret); - } else { + } +#endif // CONFIG_IDF_TARGET_ESP32 + else { ESP_LOGE(TAG, "invalid bus"); } } static void release_bus(int host_id) { +#if CONFIG_IDF_TARGET_ESP32 if (host_id == HSPI_HOST || host_id == VSPI_HOST) { +#elif CONFIG_IDF_TARGET_ESP32S2BETA + if (host_id == FSPI_HOST || host_id == HSPI_HOST || host_id == VSPI_HOST) { +#endif spi_bus_free(host_id); } } @@ -479,7 +573,6 @@ void test_permutations(flashtest_config_t* config) read_and_check(chip, part, source_buf, length); teardown_test_chip(chip, cfg->host_id); - if (config->host_id != -1) { esp_flash_speed_t speed = ESP_FLASH_SPEED_MIN; while (speed != ESP_FLASH_SPEED_MAX) { @@ -487,10 +580,17 @@ void test_permutations(flashtest_config_t* config) //the io mode will switch frequently. esp_flash_io_mode_t io_mode = SPI_FLASH_READ_MODE_MIN; while (io_mode != SPI_FLASH_READ_MODE_MAX) { - ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed); cfg->io_mode = io_mode; cfg->speed = speed; setup_new_chip(cfg, &chip); + + if (io_mode > SPI_FLASH_FASTRD + && !SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(((spi_flash_memspi_data_t *)chip->host->driver_data)->spi)) { + continue; + } + + ESP_LOGI(TAG, "test flash io mode: %d, speed: %d", io_mode, speed); + read_and_check(chip, part, source_buf, length); teardown_test_chip(chip, cfg->host_id); io_mode++; @@ -512,7 +612,7 @@ TEST_CASE("SPI flash test reading with all speed/mode permutations", "[esp_flash } #ifndef CONFIG_ESP32_SPIRAM_SUPPORT -TEST_CASE("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") +TEST_CASE_ESP32("SPI flash test reading with all speed/mode permutations, 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") { for (int i = 0; i < ALL_TEST_NUM; i++) { test_permutations(&config_list[i]); diff --git a/components/spi_flash/test/esp32/test_partition_ext.c b/components/spi_flash/test/test_partition_ext.c similarity index 95% rename from components/spi_flash/test/esp32/test_partition_ext.c rename to components/spi_flash/test/test_partition_ext.c index ead550879d..2bc9802069 100644 --- a/components/spi_flash/test/esp32/test_partition_ext.c +++ b/components/spi_flash/test/test_partition_ext.c @@ -3,7 +3,7 @@ #include "unity.h" -TEST_CASE("Basic handling of a partition in external flash", "[partition]") +TEST_CASE_ESP32("Basic handling of a partition in external flash", "[partition]") { esp_flash_t flash = { .size = 1 * 1024 * 1024, diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults index 087afa8a38..62fcfe4f7c 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_wifi_coexist/sdkconfig.defaults @@ -80,5 +80,7 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_40M=y CONFIG_LWIP_IRAM_OPTIMIZATION=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=n + CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 4f56d83e94..65708f7dd0 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -460,7 +460,7 @@ UT_034: UT_035: extends: .unit_test_template - parallel: 16 + parallel: 38 tags: - ESP32S2BETA_IDF - UT_T1_1 diff --git a/tools/unit-test-app/configs/spi_flash_legacy_s2 b/tools/unit-test-app/configs/spi_flash_legacy_s2 new file mode 100644 index 0000000000..7da54e6baa --- /dev/null +++ b/tools/unit-test-app/configs/spi_flash_legacy_s2 @@ -0,0 +1,4 @@ +TEST_COMPONENTS=spi_flash +CONFIG_ESP32_SPIRAM_SUPPORT=y +CONFIG_SPI_FLASH_USE_LEGACY_IMPL=y +CONFIG_IDF_TARGET="esp32s2beta"