Skip to content

Commit c5cf2be

Browse files
committed
drivers: stm32: SPI: Check that SPI buffers are in a nocache region
DMA only works with non-cached memory regions in H7. Check them and return an error if they don't match this condition. Signed-off-by: Daniel Gaston Ochoa <[email protected]>
1 parent e1e4fcc commit c5cf2be

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

drivers/spi/spi_ll_stm32.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,36 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
5151
#endif /* CONFIG_SOC_SERIES_STM32MP1X */
5252

5353
#ifdef CONFIG_SPI_STM32_DMA
54+
55+
#ifdef CONFIG_SOC_SERIES_STM32H7X
56+
57+
#define IS_NOCACHE_MEM_REGION(node_id) \
58+
COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, zephyr_memory_attr, RAM_NOCACHE), \
59+
(1), \
60+
(0))
61+
62+
#define GET_MEM_REGION(node_id) \
63+
{ \
64+
.start = DT_REG_ADDR(node_id), \
65+
.end = (DT_REG_ADDR(node_id) + DT_REG_SIZE(node_id)) - 1, \
66+
},
67+
68+
#define GET_MEM_REGION_IF_NOCACHE(node_id) \
69+
COND_CODE_1(IS_NOCACHE_MEM_REGION(node_id), \
70+
( \
71+
GET_MEM_REGION(node_id) \
72+
), ())
73+
74+
struct mem_region {
75+
uintptr_t start;
76+
uintptr_t end;
77+
};
78+
79+
static const struct mem_region nocache_mem_regions[] = {
80+
DT_MEMORY_ATTR_FOREACH_NODE(GET_MEM_REGION_IF_NOCACHE)
81+
};
82+
#endif /* CONFIG_SOC_SERIES_STM32H7X */
83+
5484
/* dummy value used for transferring NOP when tx buf is null
5585
* and use as dummy sink for when rx buf is null
5686
*/
@@ -723,6 +753,34 @@ static int wait_dma_rx_tx_done(const struct device *dev)
723753
return res;
724754
}
725755

756+
#ifdef CONFIG_SOC_SERIES_STM32H7X
757+
static bool buf_in_nocache(uintptr_t buf, size_t len_bytes)
758+
{
759+
for (size_t i = 0; i < ARRAY_SIZE(nocache_mem_regions); i++) {
760+
const struct mem_region *mem_reg = &nocache_mem_regions[i];
761+
762+
const bool buf_within_bounds =
763+
(buf >= mem_reg->start) && ((buf + len_bytes - 1) <= mem_reg->end);
764+
if (buf_within_bounds) {
765+
return true;
766+
}
767+
}
768+
return false;
769+
}
770+
771+
static bool spi_buf_set_in_nocache(const struct spi_buf_set *bufs)
772+
{
773+
for (size_t i = 0; i < bufs->count; i++) {
774+
const struct spi_buf *buf = &bufs->buffers[i];
775+
776+
if (!buf_in_nocache((uintptr_t)buf->buf, buf->len)) {
777+
return false;
778+
}
779+
}
780+
return true;
781+
}
782+
#endif /* CONFIG_SOC_SERIES_STM32H7X */
783+
726784
static int transceive_dma(const struct device *dev,
727785
const struct spi_config *config,
728786
const struct spi_buf_set *tx_bufs,
@@ -744,6 +802,13 @@ static int transceive_dma(const struct device *dev,
744802
return -ENOTSUP;
745803
}
746804

805+
#ifdef CONFIG_SOC_SERIES_STM32H7X
806+
if ((tx_bufs != NULL && !spi_buf_set_in_nocache(tx_bufs)) ||
807+
(rx_bufs != NULL && !spi_buf_set_in_nocache(rx_bufs))) {
808+
return -EFAULT;
809+
}
810+
#endif /* CONFIG_SOC_SERIES_STM32H7X */
811+
747812
spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);
748813

749814
k_sem_reset(&data->status_sem);

0 commit comments

Comments
 (0)