Skip to content

Commit

Permalink
Merged in BUG/UVSMART-screen-glitches (pull request zephyrproject-rto…
Browse files Browse the repository at this point in the history
…s#16)

Make SPI work with DMA enabled, I/O buffers must be non-cached.

Approved-by: Fabian van den IJssel
Approved-by: Bas van Loon
  • Loading branch information
Chris Desjardins authored and Bas van Loon committed Sep 3, 2024
2 parents 46cce3d + 3520e17 commit b334a0b
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 8 deletions.
74 changes: 66 additions & 8 deletions drivers/spi/spi_ll_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
#ifdef CONFIG_SPI_STM32_DMA
#include <zephyr/drivers/dma/dma_stm32.h>
#include <zephyr/drivers/dma.h>
#ifdef CONFIG_SOC_SERIES_STM32H7X
#include <zephyr/cache.h>
#endif
#endif
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
Expand Down Expand Up @@ -105,6 +108,9 @@ static void spi_stm32_pm_policy_state_lock_put(const struct device *dev)
}

#ifdef CONFIG_SPI_STM32_DMA
#ifdef CONFIG_SOC_SERIES_STM32H7X
static bool buf_in_nocache(uintptr_t buf, size_t len_bytes);
#endif
static uint32_t bits2bytes(uint32_t bits)
{
return bits / 8;
Expand Down Expand Up @@ -273,6 +279,36 @@ static int spi_stm32_dma_rx_load(const struct device *dev, uint8_t *buf,
return dma_start(data->dma_rx.dma_dev, data->dma_rx.channel);
}

#ifdef CONFIG_SOC_SERIES_STM32H7X
static int spi_dma_get_bounce_buffer(struct spi_stm32_data *data, size_t dma_len)
{
int ret = 0;
size_t dma_segment_len = dma_len * data->dma_rx.dma_cfg.dest_data_size;
data->rx_buf_cached = NULL;
if ((dma_segment_len > 0) && (data->ctx.rx_buf != NULL) &&
!buf_in_nocache((uintptr_t)data->ctx.rx_buf,
dma_segment_len)) {
if (dma_segment_len > data->bounce_buf_size) {
ret = -EFAULT;
} else {
data->rx_buf_cached = data->ctx.rx_buf;
data->ctx.rx_buf = data->rx_buf_non_cached;
}
}
return ret;
}

static void spi_dma_release_bounce_buffer(struct spi_stm32_data *data, size_t dma_len)
{
if (data->rx_buf_cached != NULL) {
memcpy(data->rx_buf_cached, data->ctx.rx_buf,
dma_len * data->dma_rx.dma_cfg.dest_data_size);
data->ctx.rx_buf = data->rx_buf_cached;
data->rx_buf_cached = NULL;
}
}
#endif

static int spi_dma_move_buffers(const struct device *dev, size_t len)
{
struct spi_stm32_data *data = dev->data;
Expand Down Expand Up @@ -956,16 +992,17 @@ static bool is_dummy_buffer(const struct spi_buf *buf)
return buf->buf == NULL;
}

static bool spi_buf_set_in_nocache(const struct spi_buf_set *bufs)
static bool spi_buf_set_flush_cache(const struct spi_buf_set *bufs)
{
for (size_t i = 0; i < bufs->count; i++) {
const struct spi_buf *buf = &bufs->buffers[i];

if (!is_dummy_buffer(buf) &&
!buf_in_nocache((uintptr_t)buf->buf, buf->len)) {
return false;
sys_cache_data_flush_and_invd_range(buf->buf, buf->len);
}
}

return true;
}
#endif /* CONFIG_DCACHE */
Expand All @@ -992,12 +1029,11 @@ static int transceive_dma(const struct device *dev,
return -ENOTSUP;
}

#ifdef CONFIG_DCACHE
if ((tx_bufs != NULL && !spi_buf_set_in_nocache(tx_bufs)) ||
(rx_bufs != NULL && !spi_buf_set_in_nocache(rx_bufs))) {
#ifdef CONFIG_SOC_SERIES_STM32H7X
if (tx_bufs != NULL && !spi_buf_set_flush_cache(tx_bufs)) {
return -EFAULT;
}
#endif /* CONFIG_DCACHE */
#endif /* CONFIG_SOC_SERIES_STM32H7X */

spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);

Expand Down Expand Up @@ -1045,7 +1081,12 @@ static int transceive_dma(const struct device *dev,
}

data->status_flags = 0;

#ifdef CONFIG_SOC_SERIES_STM32H7X
ret = spi_dma_get_bounce_buffer(data, dma_len);
if (ret != 0) {
break;
}
#endif
ret = spi_dma_move_buffers(dev, dma_len);
if (ret != 0) {
break;
Expand Down Expand Up @@ -1086,7 +1127,9 @@ static int transceive_dma(const struct device *dev,

uint8_t frame_size_bytes = bits2bytes(
SPI_WORD_SIZE_GET(config->operation));

#ifdef CONFIG_SOC_SERIES_STM32H7X
spi_dma_release_bounce_buffer(data, dma_len);
#endif
spi_context_update_tx(&data->ctx, frame_size_bytes, dma_len);
spi_context_update_rx(&data->ctx, frame_size_bytes, dma_len);
}
Expand Down Expand Up @@ -1344,6 +1387,17 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \


#ifdef CONFIG_SPI_STM32_DMA
#ifdef CONFIG_SOC_SERIES_STM32H7X
#define SPI_RX_BOUNCE_BUF_POINTER(id) \
.rx_buf_non_cached = spi_stm32_rx_bounce_buf_##id, \
.bounce_buf_size = DT_INST_PROP(id, bounce_buf_size),
#define SPI_RX_BOUNCE_BUF(id) \
static uint8_t spi_stm32_rx_bounce_buf_##id[DT_INST_PROP(id, bounce_buf_size)] __nocache;\
BUILD_ASSERT(DT_INST_PROP(id, bounce_buf_size) > 0);
#else
#define SPI_RX_BOUNCE_BUF_POINTER(id)
#define SPI_RX_BOUNCE_BUF(id)
#endif /* CONFIG_SOC_SERIES_STM32H7X */
#define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) \
.dma_##dir = { \
COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \
Expand All @@ -1356,6 +1410,8 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \
#else
#define SPI_DMA_CHANNEL(id, dir, DIR, src, dest)
#define SPI_DMA_STATUS_SEM(id)
#define SPI_RX_BOUNCE_BUF_POINTER(id)
#define SPI_RX_BOUNCE_BUF(id)
#endif /* CONFIG_SPI_STM32_DMA */

#define SPI_SUPPORTS_FIFO(id) DT_INST_NODE_HAS_PROP(id, fifo_enable)
Expand All @@ -1370,6 +1426,7 @@ PINCTRL_DT_INST_DEFINE(id); \
static const struct stm32_pclken pclken_##id[] = \
STM32_DT_INST_CLOCKS(id);\
\
SPI_RX_BOUNCE_BUF(id) \
static const struct spi_stm32_config spi_stm32_cfg_##id = { \
.spi = (SPI_TypeDef *) DT_INST_REG_ADDR(id), \
.pclken = pclken_##id, \
Expand All @@ -1395,6 +1452,7 @@ static struct spi_stm32_data spi_stm32_dev_data_##id = { \
SPI_DMA_CHANNEL(id, tx, TX, MEMORY, PERIPHERAL) \
SPI_DMA_STATUS_SEM(id) \
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx) \
SPI_RX_BOUNCE_BUF_POINTER(id) \
}; \
\
PM_DEVICE_DT_INST_DEFINE(id, spi_stm32_pm_action); \
Expand Down
5 changes: 5 additions & 0 deletions drivers/spi/spi_ll_stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ struct spi_stm32_data {
volatile uint32_t status_flags;
struct stream dma_rx;
struct stream dma_tx;
#ifdef CONFIG_SOC_SERIES_STM32H7X
uint8_t *rx_buf_cached;
uint8_t *rx_buf_non_cached;
int bounce_buf_size;
#endif
#endif /* CONFIG_SPI_STM32_DMA */
bool pm_policy_state_on;
};
Expand Down
6 changes: 6 additions & 0 deletions dts/bindings/spi/st,stm32h7-spi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ properties:
fifo-enable:
type: boolean
description: Enable the SPI FIFO usage for performance improvement.

bounce-buf-size:
type: int
default: 256
description: |
Size of the bounce buffer used by the SPI DMA driver for RX to cached memory.

0 comments on commit b334a0b

Please sign in to comment.