drivers: spi: esp32xx: Fix word size issue

This commit fixes the word size configuration issue
described in #54746 by considering the data frame size
when trasmitting in case the configuration is applied.

It also fixes an heap corruption problem when using
SPI DMA with a buffer that is not multiple of 32 bits
in lenght and GDMA instance in initialization.

Signed-off-by: Lucas Tamborrino <lucas.tamborrino@espressif.com>
This commit is contained in:
Lucas Tamborrino 2023-03-24 10:26:05 -03:00 committed by Anas Nashif
parent 08d1b33d07
commit b100ffb1df
2 changed files with 19 additions and 22 deletions

View file

@ -70,29 +70,31 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
size_t max_buf_sz =
cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE;
chunk_len = MIN(chunk_len, max_buf_sz);
size_t bit_len = chunk_len << 3;
size_t transfer_len = data->word_size ? data->dfs : MIN(chunk_len, max_buf_sz);
size_t bit_len = transfer_len << 3;
uint8_t *rx_temp = NULL;
uint8_t *tx_temp = NULL;
uint8_t dma_len_tx = data->word_size ? data->dfs : ctx->tx_len;
uint8_t dma_len_rx = data->word_size ? data->dfs : ctx->rx_len;
if (cfg->dma_enabled) {
/* bit_len needs to be at least one byte long when using DMA */
bit_len = !bit_len ? 8 : bit_len;
if (ctx->tx_buf && !esp_ptr_dma_capable((uint32_t *)&ctx->tx_buf[0])) {
tx_temp = k_malloc(ctx->tx_len);
tx_temp = k_malloc(dma_len_tx);
if (!tx_temp) {
LOG_ERR("Error allocating temp buffer Tx");
return -ENOMEM;
}
memcpy(tx_temp, &ctx->tx_buf[0], ctx->tx_len);
memcpy(tx_temp, &ctx->tx_buf[0], dma_len_tx);
}
if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) ||
((int)&ctx->rx_buf[0] % 4 != 0))) {
((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_tx % 4 != 0))) {
/* The rx buffer need to be length of
* multiples of 32 bits to avoid heap
* corruption.
*/
rx_temp = k_calloc(((ctx->rx_len << 3) + 31) / 8, sizeof(uint8_t));
rx_temp = k_calloc(((dma_len_rx << 3) + 31) / 8, sizeof(uint8_t));
if (!rx_temp) {
LOG_ERR("Error allocating temp buffer Rx");
k_free(tx_temp);
@ -118,7 +120,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
/* send data */
spi_hal_user_start(hal);
spi_context_update_tx(&data->ctx, data->dfs, chunk_len);
spi_context_update_tx(&data->ctx, data->dfs, transfer_len/data->dfs);
while (!spi_hal_usr_is_done(hal)) {
/* nop */
@ -128,10 +130,10 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
spi_hal_fetch_result(hal);
if (rx_temp) {
memcpy(&ctx->rx_buf[0], rx_temp, chunk_len);
memcpy(&ctx->rx_buf[0], rx_temp, transfer_len);
}
spi_context_update_rx(&data->ctx, data->dfs, chunk_len);
spi_context_update_rx(&data->ctx, data->dfs, transfer_len/data->dfs);
k_free(tx_temp);
k_free(rx_temp);
@ -166,7 +168,7 @@ static int spi_esp32_init_dma(const struct device *dev)
}
#ifdef SOC_GDMA_SUPPORTED
gdma_hal_init(&data->hal_gdma, cfg->dma_host);
gdma_hal_init(&data->hal_gdma, 0);
gdma_ll_enable_clock(data->hal_gdma.dev, true);
gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
@ -324,8 +326,6 @@ static int IRAM_ATTR spi_esp32_configure(const struct device *dev,
data->trans_config.line_mode.addr_lines = 1;
data->trans_config.line_mode.cmd_lines = 1;
hal_dev->cs_setup = 1;
/* SPI mode */
hal_dev->mode = 0;
if (SPI_MODE_GET(spi_cfg->operation) & SPI_MODE_CPOL) {
@ -351,18 +351,14 @@ static int IRAM_ATTR spi_esp32_configure(const struct device *dev,
return 0;
}
static inline uint8_t spi_esp32_get_frame_size(const struct spi_config *spi_cfg)
static inline uint8_t spi_esp32_get_frame_size(const struct device *dev,
const struct spi_config *spi_cfg)
{
uint8_t dfs = SPI_WORD_SIZE_GET(spi_cfg->operation);
struct spi_esp32_data *data = dev->data;
dfs /= 8;
data->word_size = SPI_WORD_SIZE_GET(spi_cfg->operation);
if ((dfs == 0) || (dfs > 4)) {
LOG_WRN("Unsupported dfs, 1-byte size will be used");
dfs = 1;
}
return dfs;
return data->word_size ? data->word_size >> 3 : 1;
}
static int transceive(const struct device *dev,
@ -393,7 +389,7 @@ static int transceive(const struct device *dev,
goto done;
}
data->dfs = spi_esp32_get_frame_size(spi_cfg);
data->dfs = spi_esp32_get_frame_size(dev, spi_cfg);
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);

View file

@ -52,6 +52,7 @@ struct spi_esp32_data {
int irq_line;
lldesc_t dma_desc_tx;
lldesc_t dma_desc_rx;
uint8_t word_size;
};
#endif /* ZEPHYR_DRIVERS_SPI_ESP32_SPIM_H_ */