Skip to content

Commit 1d84c8b

Browse files
Raffael Rostagnofabiobaltieri
authored andcommitted
drivers: spi: esp32: DMA operations via GDMA driver
Perform DMA operations using GDMA driver instead of relying on HAL functions. Prevents eventual conflicts between SPI and GDMA drivers when other peripherals also use DMA. Signed-off-by: Raffael Rostagno <[email protected]>
1 parent 366c64e commit 1d84c8b

File tree

2 files changed

+144
-29
lines changed

2 files changed

+144
-29
lines changed

drivers/spi/spi_esp32_spim.c

Lines changed: 137 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@ LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL);
1919
#include <zephyr/drivers/spi.h>
2020
#include <zephyr/drivers/interrupt_controller/intc_esp32.h>
2121
#ifdef SOC_GDMA_SUPPORTED
22-
#include <hal/gdma_hal.h>
23-
#include <hal/gdma_ll.h>
22+
#include <zephyr/drivers/dma.h>
23+
#include <zephyr/drivers/dma/dma_esp32.h>
2424
#endif
2525
#include <zephyr/drivers/clock_control.h>
2626
#include "spi_context.h"
2727
#include "spi_esp32_spim.h"
2828

2929
#define SPI_DMA_MAX_BUFFER_SIZE 4092
3030

31+
#define SPI_DMA_RX 0
32+
#define SPI_DMA_TX 1
33+
3134
static bool spi_esp32_transfer_ongoing(struct spi_esp32_data *data)
3235
{
3336
return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx);
@@ -47,8 +50,67 @@ static inline void spi_esp32_complete(const struct device *dev,
4750
#ifdef CONFIG_SPI_ESP32_INTERRUPT
4851
spi_context_complete(&data->ctx, dev, status);
4952
#endif
53+
}
54+
55+
#ifdef SOC_GDMA_SUPPORTED
56+
static int spi_esp32_gdma_start(const struct device *dev, uint8_t dir, uint8_t *buf, size_t len)
57+
{
58+
const struct spi_esp32_config *cfg = dev->config;
59+
60+
struct dma_config dma_cfg = {};
61+
struct dma_status dma_status = {};
62+
struct dma_block_config dma_blk = {};
63+
int err = 0;
64+
65+
uint8_t dma_channel = (dir == SPI_DMA_RX) ? cfg->dma_rx_ch : cfg->dma_tx_ch;
66+
67+
if (dma_channel == 0xFF) {
68+
LOG_ERR("DMA channel is not configured in device tree");
69+
return -EINVAL;
70+
}
71+
72+
err = dma_get_status(cfg->dma_dev, dma_channel, &dma_status);
73+
if (err) {
74+
return -EINVAL;
75+
}
76+
77+
if (dma_status.busy) {
78+
LOG_ERR("DMA channel %d is busy", dma_channel);
79+
return -EBUSY;
80+
}
81+
82+
unsigned int key = irq_lock();
83+
84+
if (dir == SPI_DMA_RX) {
85+
dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY;
86+
dma_blk.dest_address = (uint32_t)buf;
87+
} else {
88+
dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
89+
dma_blk.source_address = (uint32_t)buf;
90+
}
91+
dma_cfg.dma_slot = cfg->dma_host;
92+
dma_cfg.block_count = 1;
93+
dma_cfg.head_block = &dma_blk;
94+
dma_blk.block_size = len;
95+
96+
err = dma_config(cfg->dma_dev, dma_channel, &dma_cfg);
97+
if (err) {
98+
LOG_ERR("Error configuring DMA (%d)", err);
99+
goto unlock;
100+
}
50101

102+
err = dma_start(cfg->dma_dev, dma_channel);
103+
if (err) {
104+
LOG_ERR("Error starting DMA (%d)", err);
105+
goto unlock;
106+
}
107+
108+
unlock:
109+
irq_unlock(key);
110+
111+
return err;
51112
}
113+
#endif
52114

53115
static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
54116
{
@@ -68,6 +130,8 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
68130
uint8_t *tx_temp = NULL;
69131
size_t dma_len_tx = MIN(ctx->tx_len * data->dfs, SPI_DMA_MAX_BUFFER_SIZE);
70132
size_t dma_len_rx = MIN(ctx->rx_len * data->dfs, SPI_DMA_MAX_BUFFER_SIZE);
133+
bool prepare_data = true;
134+
int err = 0;
71135

72136
if (cfg->dma_enabled) {
73137
/* bit_len needs to be at least one byte long when using DMA */
@@ -91,8 +155,8 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
91155
rx_temp = k_calloc(((dma_len_rx << 3) + 31) / 8, sizeof(uint8_t));
92156
if (!rx_temp) {
93157
LOG_ERR("Error allocating temp buffer Rx");
94-
k_free(tx_temp);
95-
return -ENOMEM;
158+
err = -ENOMEM;
159+
goto free;
96160
}
97161
}
98162
}
@@ -119,7 +183,38 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
119183

120184
/* configure SPI */
121185
spi_hal_setup_trans(hal, hal_dev, hal_trans);
122-
spi_hal_prepare_data(hal, hal_dev, hal_trans);
186+
187+
#if defined(SOC_GDMA_SUPPORTED)
188+
if (cfg->dma_enabled && hal_trans->rcv_buffer && hal_trans->send_buffer) {
189+
/* setup DMA channels via DMA driver */
190+
spi_ll_dma_rx_fifo_reset(hal->hw);
191+
spi_ll_infifo_full_clr(hal->hw);
192+
spi_ll_dma_rx_enable(hal->hw, 1);
193+
194+
err = spi_esp32_gdma_start(dev, SPI_DMA_RX, hal_trans->rcv_buffer,
195+
transfer_len_bytes);
196+
if (err) {
197+
goto free;
198+
}
199+
200+
spi_ll_dma_tx_fifo_reset(hal->hw);
201+
spi_ll_outfifo_empty_clr(hal->hw);
202+
spi_ll_dma_tx_enable(hal->hw, 1);
203+
204+
err = spi_esp32_gdma_start(dev, SPI_DMA_TX, hal_trans->send_buffer,
205+
transfer_len_bytes);
206+
if (err) {
207+
goto free;
208+
}
209+
}
210+
211+
prepare_data = !cfg->dma_enabled;
212+
#endif
213+
214+
if (prepare_data) {
215+
/* only for plain transfers or DMA transfers w/o GDMA */
216+
spi_hal_prepare_data(hal, hal_dev, hal_trans);
217+
}
123218

124219
/* send data */
125220
spi_hal_user_start(hal);
@@ -129,19 +224,22 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
129224
/* nop */
130225
}
131226

132-
/* read data */
133-
spi_hal_fetch_result(hal);
227+
if (!cfg->dma_enabled) {
228+
/* read data */
229+
spi_hal_fetch_result(hal);
230+
}
134231

135232
if (rx_temp) {
136233
memcpy(&ctx->rx_buf[0], rx_temp, transfer_len_bytes);
137234
}
138235

139236
spi_context_update_rx(&data->ctx, data->dfs, transfer_len_frames);
140237

238+
free:
141239
k_free(tx_temp);
142240
k_free(rx_temp);
143241

144-
return 0;
242+
return err;
145243
}
146244

147245
#ifdef CONFIG_SPI_ESP32_INTERRUPT
@@ -163,31 +261,24 @@ static int spi_esp32_init_dma(const struct device *dev)
163261
{
164262
const struct spi_esp32_config *cfg = dev->config;
165263
struct spi_esp32_data *data = dev->data;
166-
uint8_t channel_offset;
167264

265+
#ifdef SOC_GDMA_SUPPORTED
266+
if (cfg->dma_dev) {
267+
if (!device_is_ready(cfg->dma_dev)) {
268+
LOG_ERR("DMA device is not ready");
269+
return -ENODEV;
270+
}
271+
}
272+
273+
/* DMA operation won't be handled by HAL */
274+
data->hal_config.dma_enabled = false;
275+
#else
168276
if (clock_control_on(cfg->clock_dev, (clock_control_subsys_t)cfg->dma_clk_src)) {
169277
LOG_ERR("Could not enable DMA clock");
170278
return -EIO;
171279
}
172280

173-
#ifdef SOC_GDMA_SUPPORTED
174-
gdma_hal_init(&data->hal_gdma, 0);
175-
gdma_ll_enable_clock(data->hal_gdma.dev, true);
176-
gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
177-
gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
178-
gdma_ll_tx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, GDMA_TRIG_PERIPH_SPI,
179-
cfg->dma_host);
180-
gdma_ll_rx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, GDMA_TRIG_PERIPH_SPI,
181-
cfg->dma_host);
182-
channel_offset = 0;
183-
#else
184-
channel_offset = 1;
185-
#endif /* SOC_GDMA_SUPPORTED */
186-
#ifdef CONFIG_SOC_SERIES_ESP32
187-
/*Connect SPI and DMA*/
188-
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, cfg->dma_host + 1,
189-
((cfg->dma_host + 1) * 2));
190-
#endif /* CONFIG_SOC_SERIES_ESP32 */
281+
int channel_offset = 1;
191282

192283
data->hal_config.dma_in = (spi_dma_dev_t *)cfg->spi;
193284
data->hal_config.dma_out = (spi_dma_dev_t *)cfg->spi;
@@ -203,8 +294,16 @@ static int spi_esp32_init_dma(const struct device *dev)
203294
k_free(data->hal_config.dmadesc_rx);
204295
return -ENOMEM;
205296
}
297+
#endif /* SOC_GDMA_SUPPORTED */
298+
299+
#ifdef CONFIG_SOC_SERIES_ESP32
300+
/* Connect SPI and DMA */
301+
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, cfg->dma_host + 1,
302+
((cfg->dma_host + 1) * 2));
303+
#endif /* CONFIG_SOC_SERIES_ESP32 */
206304

207305
spi_hal_init(&data->hal, cfg->dma_host + 1, &data->hal_config);
306+
208307
return 0;
209308
}
210309

@@ -511,6 +610,16 @@ static DEVICE_API(spi, spi_api) = {
511610
#define GET_AS_CS(idx)
512611
#endif
513612

613+
#if defined(SOC_GDMA_SUPPORTED)
614+
#define SPI_DMA_CFG(idx) \
615+
.dma_dev = ESP32_DT_INST_DMA_CTLR(idx, tx), \
616+
.dma_tx_ch = ESP32_DT_INST_DMA_CELL(idx, tx, channel), \
617+
.dma_rx_ch = ESP32_DT_INST_DMA_CELL(idx, rx, channel)
618+
#else
619+
#define SPI_DMA_CFG(idx) \
620+
.dma_clk_src = DT_INST_PROP(idx, dma_clk)
621+
#endif /* defined(SOC_GDMA_SUPPORTED) */
622+
514623
#define ESP32_SPI_INIT(idx) \
515624
\
516625
PINCTRL_DT_INST_DEFINE(idx); \
@@ -545,8 +654,8 @@ static DEVICE_API(spi, spi_api) = {
545654
(clock_control_subsys_t)DT_INST_CLOCKS_CELL(idx, offset), \
546655
.use_iomux = DT_INST_PROP(idx, use_iomux), \
547656
.dma_enabled = DT_INST_PROP(idx, dma_enabled), \
548-
.dma_clk_src = DT_INST_PROP(idx, dma_clk), \
549657
.dma_host = DT_INST_PROP(idx, dma_host), \
658+
SPI_DMA_CFG(idx), \
550659
.cs_setup = DT_INST_PROP_OR(idx, cs_setup_time, 0), \
551660
.cs_hold = DT_INST_PROP_OR(idx, cs_hold_time, 0), \
552661
.line_idle_low = DT_INST_PROP(idx, line_idle_low), \

drivers/spi/spi_esp32_spim.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,14 @@ struct spi_esp32_config {
3636
clock_control_subsys_t clock_subsys;
3737
bool use_iomux;
3838
bool dma_enabled;
39-
int dma_clk_src;
4039
int dma_host;
40+
#if defined(SOC_GDMA_SUPPORTED)
41+
const struct device *dma_dev;
42+
uint8_t dma_tx_ch;
43+
uint8_t dma_rx_ch;
44+
#else
45+
int dma_clk_src;
46+
#endif
4147
int cs_setup;
4248
int cs_hold;
4349
bool line_idle_low;

0 commit comments

Comments
 (0)