Merge branch 'refactor/spi_hal_iram_rm_dma_ll' into 'master'

refactor(spi): replace dma_ll related in spi hal by using gdma driver (part2)

See merge request espressif/esp-idf!27238
This commit is contained in:
Wan Lei 2024-01-09 15:13:12 +08:00
commit 85bdf22973
12 changed files with 189 additions and 211 deletions

View File

@ -26,6 +26,7 @@ menu "ESP-Driver:SPI Configurations"
select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_MASTER_FUNC_IN_IRAM
select ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
select GDMA_CTRL_FUNC_IN_IRAM if SOC_GDMA_SUPPORTED
help
Place the SPI master ISR in to IRAM to avoid possible cache miss.

View File

@ -102,6 +102,16 @@ esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma
*/
esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *actual_max_sz);
/**
* Setupt/Configure dma descriptor link list
*
* @param dmadesc start of dma descriptor memory
* @param data start of data buffer to be configured in
* @param len length of data buffer, in byte
* @param is_rx if descriptor is for rx/receive direction
*/
void spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx);
/**
* @brief Free DMA for SPI
*

View File

@ -1,7 +1,7 @@
[mapping:gpspi_driver]
archive: libesp_driver_spi.a
entries:
if SOC_GDMA_SUPPORTED = n:
if SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y:
spi_dma: spi_dma_reset (noflash)
spi_dma: spi_dma_start (noflash)
# SOC_GDMA_SUPPORTED is undeclared if GDMA not support, so use `SOC_GDMA_SUPPORTED != y` instead
if SOC_GDMA_SUPPORTED != y && (SPI_MASTER_ISR_IN_IRAM = y || SPI_SLAVE_ISR_IN_IRAM = y):
spi_dma: spi_dma_reset (noflash)
spi_dma: spi_dma_start (noflash)

View File

@ -14,6 +14,7 @@
#include "esp_rom_gpio.h"
#include "esp_heap_caps.h"
#include "soc/spi_periph.h"
#include "soc/ext_mem_defs.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_private/periph_ctrl.h"
@ -304,6 +305,43 @@ esp_err_t spicommon_dma_desc_alloc(spi_dma_ctx_t *dma_ctx, int cfg_max_sz, int *
*actual_max_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
return ESP_OK;
}
#if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
void SPI_MASTER_ISR_ATTR spicommon_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
{
dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
}
//----------------------------------------------------------free dma periph-------------------------------------------------------//
esp_err_t spicommon_dma_chan_free(spi_dma_ctx_t *dma_ctx)
{

View File

@ -261,29 +261,10 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
}
}
//assign the SPI, RX DMA and TX DMA peripheral registers beginning address
spi_hal_config_t hal_config = { .dma_enabled = bus_attr->dma_enabled, };
if (bus_attr->dma_enabled && dma_ctx) {
hal_config.dmadesc_tx = dma_ctx->dmadesc_tx;
hal_config.dmadesc_rx = dma_ctx->dmadesc_rx;
hal_config.dmadesc_n = dma_ctx->dma_desc_num;
#if SOC_GDMA_SUPPORTED
//temporary used for gdma_ll alias in hal layer
gdma_get_channel_id(dma_ctx->tx_dma_chan, (int *)&hal_config.tx_dma_chan);
gdma_get_channel_id(dma_ctx->rx_dma_chan, (int *)&hal_config.rx_dma_chan);
#else
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. Pass the registers of SPI peripheral to control it.
hal_config.dma_in = SPI_LL_GET_HW(host_id);
hal_config.dma_out = SPI_LL_GET_HW(host_id);
hal_config.tx_dma_chan = dma_ctx->tx_dma_chan.chan_id;
hal_config.rx_dma_chan = dma_ctx->rx_dma_chan.chan_id;
#endif
}
SPI_MASTER_PERI_CLOCK_ATOMIC() {
spi_ll_enable_clock(host_id, true);
}
spi_hal_init(&host->hal, host_id, &hal_config);
spi_hal_init(&host->hal, host_id);
if (host_id != SPI1_HOST) {
//SPI1 attributes are already initialized at start up.
@ -625,6 +606,56 @@ static void SPI_MASTER_ISR_ATTR spi_bus_intr_disable(void *host)
esp_intr_disable(((spi_host_t*)host)->intr);
}
#if SOC_GDMA_SUPPORTED // AHB_DMA_V1 and AXI_DMA
// dma is provided by gdma driver on these targets
#define spi_dma_reset gdma_reset
#define spi_dma_start(chan, addr) gdma_start(chan, (intptr_t)(addr))
#endif
static void SPI_MASTER_ISR_ATTR s_spi_dma_prepare_data(spi_host_t *host, spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
{
const spi_dma_ctx_t *dma_ctx = host->dma_ctx;
if (trans->rcv_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spi_dma_reset(dma_ctx->rx_dma_chan);
spi_hal_hw_prepare_rx(hal->hw);
spi_dma_start(dma_ctx->rx_dma_chan, dma_ctx->dmadesc_rx);
}
#if CONFIG_IDF_TARGET_ESP32
else if (!dev->half_duplex) {
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_start(dma_ctx->rx_dma_chan, NULL);
}
#endif
if (trans->send_buffer) {
spicommon_dma_desc_setup_link(dma_ctx->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spi_dma_reset(dma_ctx->tx_dma_chan);
spi_hal_hw_prepare_tx(hal->hw);
spi_dma_start(dma_ctx->tx_dma_chan, dma_ctx->dmadesc_tx);
}
}
static void SPI_MASTER_ISR_ATTR s_spi_prepare_data(spi_device_t *dev, const spi_hal_trans_config_t *hal_trans)
{
spi_host_t *host = dev->host;
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
spi_hal_context_t *hal = &(host->hal);
if (host->bus_attr->dma_enabled) {
s_spi_dma_prepare_data(host, hal, hal_dev, hal_trans);
} else {
//Need to copy data to registers manually
spi_hal_push_tx_buffer(hal, hal_trans);
}
//in ESP32 these registers should be configured after the DMA is set
spi_hal_enable_data_line(hal->hw, (!hal_dev->half_duplex && hal_trans->rcv_buffer) || hal_trans->send_buffer, !!hal_trans->rcv_buffer);
}
// The function is called to send a new transaction, in ISR or in the task.
// Setup the transaction-specified registers and linked-list used by the DMA (or FIFO if DMA is not used)
static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf)
@ -677,7 +708,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
}
spi_hal_setup_trans(hal, hal_dev, &hal_trans);
spi_hal_prepare_data(hal, hal_dev, &hal_trans);
s_spi_prepare_data(dev, &hal_trans);
//Call pre-transmission callback, if any
if (dev->cfg.pre_cb) {
@ -693,7 +724,9 @@ static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
{
spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
spi_hal_fetch_result(&host->hal);
if (!host->bus_attr->dma_enabled) {
spi_hal_fetch_result(&host->hal);
}
//Call post-transaction callback, if any
spi_device_t* dev = host->device[host->cur_cs];
if (dev->cfg.post_cb) {

View File

@ -288,6 +288,7 @@ static inline void spi_ll_dma_rx_fifo_reset(spi_dev_t *hw)
*
* @param hw Beginning address of the peripheral registers.
*/
__attribute__((always_inline))
static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
{
//This is not used in esp32
@ -298,6 +299,7 @@ static inline void spi_ll_infifo_full_clr(spi_dev_t *hw)
*
* @param hw Beginning address of the peripheral registers.
*/
__attribute__((always_inline))
static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
{
//This is not used in esp32
@ -313,6 +315,7 @@ static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
* @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable
*/
__attribute__((always_inline))
static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
{
//This is not used in esp32
@ -324,6 +327,7 @@ static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
* @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable
*/
__attribute__((always_inline))
static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable)
{
//This is not used in esp32
@ -1090,6 +1094,7 @@ static inline void spi_dma_ll_reset_register(spi_host_device_t host_id) {
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
* @param channel DMA channel, for chip version compatibility, not used.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
{
//Reset RX DMA peripheral
@ -1104,6 +1109,7 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
{
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
@ -1140,6 +1146,7 @@ static inline void spi_dma_ll_rx_enable_burst_desc(spi_dma_dev_t *dma_in, uint32
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
* @param channel DMA channel, for chip version compatibility, not used.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
{
//Reset TX DMA peripheral
@ -1154,6 +1161,7 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
{
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;

View File

@ -388,6 +388,7 @@ static inline void spi_ll_outfifo_empty_clr(spi_dev_t *hw)
* @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable
*/
__attribute__((always_inline))
static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
{
//This is not used in esp32s2
@ -399,6 +400,7 @@ static inline void spi_ll_dma_rx_enable(spi_dev_t *hw, bool enable)
* @param hw Beginning address of the peripheral registers.
* @param enable 1: enable; 2: disable
*/
__attribute__((always_inline))
static inline void spi_ll_dma_tx_enable(spi_dev_t *hw, bool enable)
{
//This is not used in esp32s2
@ -1266,6 +1268,7 @@ static inline void spi_dma_ll_reset_register(spi_host_device_t host_id) {
* @param dma_in Beginning address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
* @param channel DMA channel, for chip version compatibility, not used.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
{
dma_in->dma_conf.in_rst = 1;
@ -1279,6 +1282,7 @@ static inline void spi_dma_ll_rx_reset(spi_dma_dev_t *dma_in, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_rx_start(spi_dma_dev_t *dma_in, uint32_t channel, lldesc_t *addr)
{
dma_in->dma_in_link.addr = (int) addr & 0xFFFFF;
@ -1340,6 +1344,7 @@ static inline uint32_t spi_dma_ll_get_in_suc_eof_desc_addr(spi_dma_dev_t *dma_in
* @param dma_out Beginning address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
* @param channel DMA channel, for chip version compatibility, not used.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
{
//Reset TX DMA peripheral
@ -1354,6 +1359,7 @@ static inline void spi_dma_ll_tx_reset(spi_dma_dev_t *dma_out, uint32_t channel)
* @param channel DMA channel, for chip version compatibility, not used.
* @param addr Address of the beginning DMA descriptor.
*/
__attribute__((always_inline))
static inline void spi_dma_ll_tx_start(spi_dma_dev_t *dma_out, uint32_t channel, lldesc_t *addr)
{
dma_out->dma_out_link.addr = (int) addr & 0xFFFFF;

View File

@ -12,16 +12,15 @@
// The HAL layer for SPI master (common part)
// SPI HAL usages:
// SPI HAL usages (without DMA):
// 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used
// 3. setup the clock speed (since this takes long time)
// 4. call setup_device to update parameters for the specific device
// 5. call setup_trans to update parameters for the specific transaction
// 6. prepare data to send, and prepare the receiving buffer
// 7. trigger user defined SPI transaction to start
// 8. wait until the user transaction is done
// 9. fetch the received data
// 2. setup the clock speed (since this takes long time)
// 3. call setup_device to update parameters for the specific device
// 4. call setup_trans to update parameters for the specific transaction
// 5. prepare data to send into hw registers
// 6. trigger user defined SPI transaction to start
// 7. wait until the user transaction is done
// 8. fetch the received data
// Parameter to be updated only during ``setup_device`` will be highlighted in the
// field comments.
@ -75,27 +74,6 @@ typedef struct {
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
} spi_hal_timing_conf_t;
/**
* DMA configuration structure
* Should be set by driver at initialization
*/
typedef struct {
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
spi_dma_desc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
} spi_hal_config_t;
/**
* Transaction configuration structure, this should be assigned by driver each time.
* All these parameters will be updated to the peripheral every transaction.
@ -118,25 +96,9 @@ typedef struct {
* Context that should be maintained by both the driver and the HAL.
*/
typedef struct {
/* These two need to be malloced by the driver first */
spi_dma_desc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
spi_dma_desc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
/* Configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM (DMA -> RAM).
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
/* Internal parameters, don't touch */
spi_hal_trans_config_t trans_config; ///< Transaction configuration
} spi_hal_context_t;
@ -172,9 +134,8 @@ typedef struct {
*
* @param hal Context of the HAL layer.
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for SPI2 and 2 for SPI3.
* @param hal_config Configuration of the hal defined by the upper layer.
*/
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config);
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id);
/**
* Deinit the peripheral (and the context if needed).
@ -201,13 +162,27 @@ void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *ha
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/**
* Prepare the data for the current transaction.
* Enable/Disable miso/mosi signals on peripheral side
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
* @param hal_trans Transaction configuration
* @param hw Beginning address of the peripheral registers.
* @param mosi_ena enable/disable mosi line
* @param miso_ena enable/disable miso line
*/
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
void spi_hal_enable_data_line(spi_dev_t *hw, bool mosi_ena, bool miso_ena);
/**
* Prepare tx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_hal_hw_prepare_rx(spi_dev_t *hw);
/**
* Prepare tx hardware for a new DMA trans
*
* @param hw Beginning address of the peripheral registers.
*/
void spi_hal_hw_prepare_tx(spi_dev_t *hw);
/**
* Trigger start a user-defined transaction.
@ -223,6 +198,14 @@ void spi_hal_user_start(const spi_hal_context_t *hal);
*/
bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
/**
* Setup transaction operations, write tx buffer to HW registers
*
* @param hal Context of the HAL layer.
* @param hal_trans Transaction configuration.
*/
void spi_hal_push_tx_buffer(const spi_hal_context_t *hal, const spi_hal_trans_config_t *hal_trans);
/**
* Post transaction operations, mainly fetch data from the buffer.
*

View File

@ -21,19 +21,11 @@ static const __attribute__((unused)) char SPI_HAL_TAG[] = "spi_hal";
return (ret_val); \
}
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *config)
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id)
{
memset(hal, 0, sizeof(spi_hal_context_t));
spi_dev_t *hw = SPI_LL_GET_HW(host_id);
hal->hw = hw;
hal->dma_in = config->dma_in;
hal->dma_out = config->dma_out;
hal->dma_enabled = config->dma_enabled;
hal->dmadesc_tx = config->dmadesc_tx;
hal->dmadesc_rx = config->dmadesc_rx;
hal->tx_dma_chan = config->tx_dma_chan;
hal->rx_dma_chan = config->rx_dma_chan;
hal->dmadesc_n = config->dmadesc_n;
#if SPI_LL_MOSI_FREE_LEVEL
// Change default data line level to low which same as esp32

View File

@ -12,37 +12,6 @@
#include "soc/ext_mem_defs.h"
#include "soc/soc_caps.h"
//This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
#if SOC_GDMA_SUPPORTED
#if (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB) && (SOC_AHB_GDMA_VERSION == 1)
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) gdma_ll_rx_reset_channel(&GDMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) gdma_ll_tx_reset_channel(&GDMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_rx_start(&GDMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
gdma_ll_tx_start(&GDMA, chan);\
} while (0)
#elif (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI) //TODO: IDF-6152, refactor spi hal layer
#include "hal/axi_dma_ll.h"
#define spi_dma_ll_rx_reset(dev, chan) axi_dma_ll_rx_reset_channel(&AXI_DMA, chan)
#define spi_dma_ll_tx_reset(dev, chan) axi_dma_ll_tx_reset_channel(&AXI_DMA, chan);
#define spi_dma_ll_rx_start(dev, chan, addr) do {\
axi_dma_ll_rx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_rx_start(&AXI_DMA, chan);\
} while (0)
#define spi_dma_ll_tx_start(dev, chan, addr) do {\
axi_dma_ll_tx_set_desc_addr(&AXI_DMA, chan, (uint32_t)addr);\
axi_dma_ll_tx_start(&AXI_DMA, chan);\
} while (0)
#endif
#endif //SOC_GDMA_SUPPORTED
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev)
{
//Configure clock settings
@ -145,94 +114,24 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev
memcpy(&hal->trans_config, trans, sizeof(spi_hal_trans_config_t));
}
#if SOC_NON_CACHEABLE_OFFSET
#define ADDR_DMA_2_CPU(addr) ((typeof(addr))((uint32_t)(addr) + SOC_NON_CACHEABLE_OFFSET))
#define ADDR_CPU_2_DMA(addr) ((typeof(addr))((uint32_t)(addr) - SOC_NON_CACHEABLE_OFFSET))
#else
#define ADDR_DMA_2_CPU(addr) (addr)
#define ADDR_CPU_2_DMA(addr) (addr)
#endif
//TODO: IDF-6152, refactor spi hal layer
static void s_spi_hal_dma_desc_setup_link(spi_dma_desc_t *dmadesc, const void *data, int len, bool is_rx)
void spi_hal_enable_data_line(spi_dev_t *hw, bool mosi_ena, bool miso_ena)
{
dmadesc = ADDR_DMA_2_CPU(dmadesc);
int n = 0;
while (len) {
int dmachunklen = len;
if (dmachunklen > DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
dmachunklen = DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
}
if (is_rx) {
//Receive needs DMA length rounded to next 32-bit boundary
dmadesc[n].dw0.size = (dmachunklen + 3) & (~3);
dmadesc[n].dw0.length = (dmachunklen + 3) & (~3);
} else {
dmadesc[n].dw0.size = dmachunklen;
dmadesc[n].dw0.length = dmachunklen;
}
dmadesc[n].buffer = (uint8_t *)data;
dmadesc[n].dw0.suc_eof = 0;
dmadesc[n].dw0.owner = 1;
dmadesc[n].next = ADDR_CPU_2_DMA(&dmadesc[n + 1]);
len -= dmachunklen;
data += dmachunklen;
n++;
}
dmadesc[n - 1].dw0.suc_eof = 1; //Mark last DMA desc as end of stream.
dmadesc[n - 1].next = NULL;
spi_ll_enable_mosi(hw, mosi_ena);
spi_ll_enable_miso(hw, miso_ena);
}
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev, const spi_hal_trans_config_t *trans)
void spi_hal_hw_prepare_rx(spi_dev_t *hw)
{
spi_dev_t *hw = hal->hw;
spi_ll_dma_rx_fifo_reset(hw);
spi_ll_infifo_full_clr(hw);
spi_ll_dma_rx_enable(hw, 1);
}
//Fill DMA descriptors
if (trans->rcv_buffer) {
if (!hal->dma_enabled) {
//No need to setup anything; we'll copy the result out of the work registers directly later.
} else {
s_spi_hal_dma_desc_setup_link(hal->dmadesc_rx, trans->rcv_buffer, ((trans->rx_bitlen + 7) / 8), true);
spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
spi_ll_dma_rx_fifo_reset(hal->hw);
spi_ll_infifo_full_clr(hal->hw);
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, (lldesc_t *)hal->dmadesc_rx);
}
}
#if CONFIG_IDF_TARGET_ESP32
else {
//DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon
if (hal->dma_enabled && !dev->half_duplex) {
spi_ll_dma_rx_enable(hal->hw, 1);
spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, 0);
}
}
#endif
if (trans->send_buffer) {
if (!hal->dma_enabled) {
//Need to copy data to registers manually
spi_ll_write_buffer(hw, trans->send_buffer, trans->tx_bitlen);
} else {
s_spi_hal_dma_desc_setup_link(hal->dmadesc_tx, trans->send_buffer, (trans->tx_bitlen + 7) / 8, false);
spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
spi_ll_dma_tx_fifo_reset(hal->hw);
spi_ll_outfifo_empty_clr(hal->hw);
spi_ll_dma_tx_enable(hal->hw, 1);
spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (lldesc_t *)hal->dmadesc_tx);
}
}
//in ESP32 these registers should be configured after the DMA is set
if ((!dev->half_duplex && trans->rcv_buffer) || trans->send_buffer) {
spi_ll_enable_mosi(hw, 1);
} else {
spi_ll_enable_mosi(hw, 0);
}
spi_ll_enable_miso(hw, (trans->rcv_buffer) ? 1 : 0);
void spi_hal_hw_prepare_tx(spi_dev_t *hw)
{
spi_ll_dma_tx_fifo_reset(hw);
spi_ll_outfifo_empty_clr(hw);
spi_ll_dma_tx_enable(hw, 1);
}
void spi_hal_user_start(const spi_hal_context_t *hal)
@ -246,11 +145,19 @@ bool spi_hal_usr_is_done(const spi_hal_context_t *hal)
return spi_ll_usr_is_done(hal->hw);
}
void spi_hal_push_tx_buffer(const spi_hal_context_t *hal, const spi_hal_trans_config_t *hal_trans)
{
if (hal_trans->send_buffer) {
spi_ll_write_buffer(hal->hw, hal_trans->send_buffer, hal_trans->tx_bitlen);
}
//No need to setup anything for RX, we'll copy the result out of the work registers directly later.
}
void spi_hal_fetch_result(const spi_hal_context_t *hal)
{
const spi_hal_trans_config_t *trans = &hal->trans_config;
if (trans->rcv_buffer && !hal->dma_enabled) {
if (trans->rcv_buffer) {
//Need to copy from SPI regs to result buffer.
spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen);
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -28,10 +28,10 @@
#define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 49000
#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 40*1000*1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 20
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 16
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 45
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 41
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 23
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 18
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 47
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 42
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)
#define IDF_PERFORMANCE_MAX_CYCLES_PER_DIV 70

View File

@ -27,9 +27,9 @@
#define IDF_PERFORMANCE_MAX_ECDSA_P256_VERIFY_OP 67000
#define IDF_PERFORMANCE_MAX_SPI_CLK_FREQ 26*1000*1000
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 28
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 24
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 58
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING 32
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_POLLING_NO_DMA 25
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING 61
#define IDF_PERFORMANCE_MAX_SPI_PER_TRANS_NO_POLLING_NO_DMA 54
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)