mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/esp32s2beta_spi_flash_driver' into 'master'
Use new SPI flash driver abstraction layers See merge request espressif/esp-idf!5504
This commit is contained in:
commit
b8af7dd7cb
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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}"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
319
components/soc/esp32s2beta/include/hal/gpspi_flash_ll.h
Normal file
319
components/soc/esp32s2beta/include/hal/gpspi_flash_ll.h
Normal file
@ -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 <stdlib.h>
|
||||
#include "soc/spi_periph.h"
|
||||
#include "hal/spi_types.h"
|
||||
#include "hal/spi_flash_types.h"
|
||||
#include <sys/param.h> // For MIN/MAX
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
85
components/soc/esp32s2beta/include/hal/spi_flash_ll.h
Normal file
85
components/soc/esp32s2beta/include/hal/spi_flash_ll.h
Normal file
@ -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
|
354
components/soc/esp32s2beta/include/hal/spimem_flash_ll.h
Normal file
354
components/soc/esp32s2beta/include/hal/spimem_flash_ll.h
Normal file
@ -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 <stdlib.h>
|
||||
#include <sys/param.h> // For MIN/MAX
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
}
|
||||
bool spi_flash_hal_supports_direct_read(spi_flash_host_driver_t *driver, const void *p);
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
102
components/soc/src/hal/spi_flash_hal_common.inc
Normal file
102
components/soc/src/hal/spi_flash_hal_common.inc
Normal file
@ -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 <stdlib.h>
|
||||
#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;
|
||||
}
|
39
components/soc/src/hal/spi_flash_hal_gpspi.c
Normal file
39
components/soc/src/hal/spi_flash_hal_gpspi.c
Normal file
@ -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);
|
||||
}
|
@ -12,87 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -16,12 +16,12 @@
|
||||
#include <sys/param.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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]);
|
@ -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,
|
@ -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
|
||||
|
@ -460,7 +460,7 @@ UT_034:
|
||||
|
||||
UT_035:
|
||||
extends: .unit_test_template
|
||||
parallel: 16
|
||||
parallel: 38
|
||||
tags:
|
||||
- ESP32S2BETA_IDF
|
||||
- UT_T1_1
|
||||
|
4
tools/unit-test-app/configs/spi_flash_legacy_s2
Normal file
4
tools/unit-test-app/configs/spi_flash_legacy_s2
Normal file
@ -0,0 +1,4 @@
|
||||
TEST_COMPONENTS=spi_flash
|
||||
CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPI_FLASH_USE_LEGACY_IMPL=y
|
||||
CONFIG_IDF_TARGET="esp32s2beta"
|
Loading…
Reference in New Issue
Block a user