Skip to content

Commit 8f06e76

Browse files
gautierg-stkartben
authored andcommitted
drivers: spi: stm32: add rtio support
Add SPI RTIO support for STM32. SPI RTIO required interrupts. DMA is not supported yet. Signed-off-by: Guillaume Gautier <guillaume.gautier-ext@st.com> Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
1 parent 3b856cc commit 8f06e76

File tree

3 files changed

+210
-3
lines changed

3 files changed

+210
-3
lines changed

drivers/spi/Kconfig.stm32

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ if SPI_STM32
1515

1616
config SPI_STM32_INTERRUPT
1717
bool "STM32 MCU SPI Interrupt Support"
18+
default y if SPI_RTIO
1819
help
1920
Enable Interrupt support for the SPI Driver of STM32 family.
2021

@@ -49,4 +50,30 @@ config SPI_STM32_BUSY_FLAG_TIMEOUT
4950

5051
endif # SPI_STM32_ERRATA_BUSY
5152

53+
if SPI_RTIO
54+
55+
config SPI_STM32_RTIO_SQ_SIZE
56+
int "Number of available submission queue entries"
57+
default 8 # Sensible default that covers most common SPI transactions
58+
help
59+
When RTIO is used with SPI, each driver holds a context whose blocking API
60+
calls are used to perform SPI transactions. This queue needs to be as deep
61+
as the longest set of spi_buf_set used, where normal SPI operations are
62+
used (equal length buffers). It may need to be slightly deeper where the
63+
SPI buffers set for transmit/receive do not always matched equally in
64+
length as these are transformed into normal transceives.
65+
66+
config SPI_STM32_RTIO_CQ_SIZE
67+
int "Number of available completion queue entries"
68+
default 8 # Sensible default that covers most common SPI transactions
69+
help
70+
When RTIO is used with SPI, each driver holds a context whose blocking API
71+
calls are used to perform SPI transactions. This queue needs to be as deep
72+
as the longest set of spi_buf_set used, where normal SPI operations are
73+
used (equal length buffers). It may need to be slightly deeper where the
74+
SPI buffers set for transmit/receive do not always matched equally in
75+
length as these are transformed into normal transceives.
76+
77+
endif # SPI_RTIO
78+
5279
endif # SPI_STM32

drivers/spi/spi_ll_stm32.c

Lines changed: 169 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
2525
#include <zephyr/pm/policy.h>
2626
#include <zephyr/pm/device.h>
2727
#include <zephyr/pm/device_runtime.h>
28+
#include <zephyr/rtio/rtio.h>
2829
#include <zephyr/sys/util.h>
2930
#include <zephyr/toolchain.h>
3031

@@ -538,12 +539,147 @@ static void spi_stm32_msg_start(const struct device *dev, bool is_rx_empty)
538539
#endif /* CONFIG_SPI_STM32_INTERRUPT */
539540
}
540541

542+
#ifdef CONFIG_SPI_RTIO
543+
/* Forward declaration for RTIO handlers conveniance */
544+
static void spi_stm32_iodev_complete(const struct device *dev, int status);
545+
static int spi_stm32_configure(const struct device *dev,
546+
const struct spi_config *config,
547+
bool write);
548+
549+
static void spi_stm32_iodev_msg_start(const struct device *dev, struct spi_config *config,
550+
const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t buf_len)
551+
{
552+
struct spi_stm32_data *data = dev->data;
553+
uint32_t size = buf_len / (SPI_WORD_SIZE_GET(config->operation) / BITS_PER_BYTE);
554+
555+
const struct spi_buf current_tx = {.buf = NULL, .len = size};
556+
const struct spi_buf current_rx = {.buf = NULL, .len = size};
557+
558+
data->ctx.current_tx = &current_tx;
559+
data->ctx.current_rx = &current_rx;
560+
561+
data->ctx.tx_buf = tx_buf;
562+
data->ctx.rx_buf = rx_buf;
563+
data->ctx.tx_len = tx_buf != NULL ? size : 0;
564+
data->ctx.rx_len = rx_buf != NULL ? size : 0;
565+
data->ctx.tx_count = tx_buf != NULL ? 1 : 0;
566+
data->ctx.rx_count = rx_buf != NULL ? 1 : 0;
567+
568+
data->ctx.sync_status = 0;
569+
570+
#ifdef CONFIG_SPI_SLAVE
571+
ctx->recv_frames = 0;
572+
#endif /* CONFIG_SPI_SLAVE */
573+
574+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
575+
const struct spi_stm32_config *cfg = dev->config;
576+
SPI_TypeDef *spi = cfg->spi;
577+
578+
if (cfg->fifo_enabled && SPI_OP_MODE_GET(config->operation) == SPI_OP_MODE_MASTER) {
579+
LL_SPI_SetTransferSize(spi, size);
580+
}
581+
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */
582+
583+
spi_stm32_msg_start(dev, rx_buf == NULL);
584+
}
585+
586+
static void spi_stm32_iodev_start(const struct device *dev)
587+
{
588+
struct spi_stm32_data *data = dev->data;
589+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
590+
struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data;
591+
struct spi_config *spi_config = &spi_dt_spec->config;
592+
struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe;
593+
594+
switch (sqe->op) {
595+
case RTIO_OP_RX:
596+
spi_stm32_iodev_msg_start(dev, spi_config, NULL, sqe->rx.buf, sqe->rx.buf_len);
597+
break;
598+
case RTIO_OP_TX:
599+
spi_stm32_iodev_msg_start(dev, spi_config, sqe->tx.buf, NULL, sqe->tx.buf_len);
600+
break;
601+
case RTIO_OP_TINY_TX:
602+
spi_stm32_iodev_msg_start(dev, spi_config, sqe->tiny_tx.buf, NULL,
603+
sqe->tiny_tx.buf_len);
604+
break;
605+
case RTIO_OP_TXRX:
606+
spi_stm32_iodev_msg_start(dev, spi_config, sqe->txrx.tx_buf, sqe->txrx.rx_buf,
607+
sqe->txrx.buf_len);
608+
break;
609+
default:
610+
LOG_ERR("Invalid op code %d for submission %p", sqe->op, (void *)sqe);
611+
spi_stm32_iodev_complete(dev, -EINVAL);
612+
break;
613+
}
614+
}
615+
616+
static inline int spi_stm32_iodev_prepare_start(const struct device *dev)
617+
{
618+
struct spi_stm32_data *data = dev->data;
619+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
620+
struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data;
621+
struct spi_config *spi_config = &spi_dt_spec->config;
622+
uint8_t op_code = rtio_ctx->txn_curr->sqe.op;
623+
bool write = (op_code == RTIO_OP_TX) ||
624+
(op_code == RTIO_OP_TINY_TX) ||
625+
(op_code == RTIO_OP_TXRX);
626+
627+
return spi_stm32_configure(dev, spi_config, write);
628+
}
629+
630+
static void spi_stm32_iodev_complete(const struct device *dev, int status)
631+
{
632+
struct spi_stm32_data *data = dev->data;
633+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
634+
635+
if (status == 0 && (rtio_ctx->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) != 0) {
636+
rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr);
637+
spi_stm32_iodev_start(dev);
638+
} else {
639+
spi_stm32_cs_control(dev, false);
640+
while (spi_rtio_complete(rtio_ctx, status)) {
641+
status = spi_stm32_iodev_prepare_start(dev);
642+
if (status == 0) {
643+
spi_stm32_iodev_start(dev);
644+
break;
645+
}
646+
647+
/* Clear chip select and loop to mark transfer completed with an error */
648+
spi_stm32_cs_control(dev, false);
649+
}
650+
}
651+
}
652+
653+
static void spi_stm32_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
654+
{
655+
struct spi_stm32_data *data = dev->data;
656+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
657+
int err;
658+
659+
if (spi_rtio_submit(rtio_ctx, iodev_sqe)) {
660+
err = spi_stm32_iodev_prepare_start(dev);
661+
if (err == 0) {
662+
spi_stm32_iodev_start(dev);
663+
} else {
664+
spi_stm32_iodev_complete(dev, err);
665+
}
666+
}
667+
}
668+
#endif /* CONFIG_SPI_RTIO */
669+
541670
static void spi_stm32_complete(const struct device *dev, int status)
542671
{
543672
const struct spi_stm32_config *cfg = dev->config;
544673
SPI_TypeDef *spi = cfg->spi;
545674
struct spi_stm32_data *data = dev->data;
546675

676+
#ifdef CONFIG_SPI_RTIO
677+
if (data->rtio_ctx->txn_head != NULL) {
678+
spi_stm32_iodev_complete(dev, status);
679+
return;
680+
}
681+
#endif /* CONFIG_SPI_RTIO */
682+
547683
#ifdef CONFIG_SPI_STM32_INTERRUPT
548684
ll_func_disable_int_tx_empty(spi);
549685
ll_func_disable_int_rx_not_empty(spi);
@@ -618,6 +754,15 @@ static void spi_stm32_isr(const struct device *dev)
618754
SPI_TypeDef *spi = cfg->spi;
619755
int err;
620756

757+
#if defined(CONFIG_SPI_RTIO)
758+
/* With RTIO, an interrupt can occur even though they
759+
* are all previously disabled. Ignore it then.
760+
*/
761+
if (ll_func_are_int_disabled(spi)) {
762+
return;
763+
}
764+
#endif /* CONFIG_SPI_RTIO */
765+
621766
/* Some spurious interrupts are triggered when SPI is not enabled; ignore them.
622767
* Do it only when fifo is enabled to leave non-fifo functionality untouched for now
623768
*/
@@ -679,6 +824,7 @@ static int spi_stm32_configure(const struct device *dev,
679824
uint32_t clock;
680825
int br;
681826

827+
#ifndef CONFIG_SPI_RTIO
682828
if (spi_context_configured(&data->ctx, config)) {
683829
if (config->operation & SPI_HALF_DUPLEX) {
684830
if (write) {
@@ -689,6 +835,7 @@ static int spi_stm32_configure(const struct device *dev,
689835
}
690836
return 0;
691837
}
838+
#endif /* CONFIG_SPI_RTIO */
692839

693840
if ((SPI_WORD_SIZE_GET(config->operation) != 8) &&
694841
(SPI_WORD_SIZE_GET(config->operation) != 16)) {
@@ -839,6 +986,8 @@ static int spi_stm32_release(const struct device *dev,
839986
return 0;
840987
}
841988

989+
#ifndef CONFIG_SPI_RTIO
990+
842991
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
843992
static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config,
844993
const struct spi_buf_set *bufs)
@@ -957,6 +1106,7 @@ static int spi_stm32_half_duplex_switch_to_receive(const struct spi_stm32_config
9571106

9581107
return 0;
9591108
}
1109+
#endif /* !CONFIG_SPI_RTIO */
9601110

9611111
static int transceive(const struct device *dev,
9621112
const struct spi_config *config,
@@ -966,9 +1116,7 @@ static int transceive(const struct device *dev,
9661116
spi_callback_t cb,
9671117
void *userdata)
9681118
{
969-
const struct spi_stm32_config *cfg = dev->config;
9701119
struct spi_stm32_data *data = dev->data;
971-
SPI_TypeDef *spi = cfg->spi;
9721120
int ret;
9731121

9741122
if (tx_bufs == NULL && rx_bufs == NULL) {
@@ -983,6 +1131,12 @@ static int transceive(const struct device *dev,
9831131

9841132
spi_stm32_pm_policy_state_lock_get(dev);
9851133

1134+
#ifdef CONFIG_SPI_RTIO
1135+
ret = spi_rtio_transceive(data->rtio_ctx, config, tx_bufs, rx_bufs);
1136+
#else /* CONFIG_SPI_RTIO */
1137+
const struct spi_stm32_config *cfg = dev->config;
1138+
SPI_TypeDef *spi = cfg->spi;
1139+
9861140
ret = spi_stm32_configure(dev, config, tx_bufs != NULL);
9871141
if (ret != 0) {
9881142
goto end;
@@ -1050,6 +1204,8 @@ static int transceive(const struct device *dev,
10501204
#endif /* CONFIG_SPI_STM32_INTERRUPT */
10511205

10521206
end:
1207+
#endif /* CONFIG_SPI_RTIO */
1208+
10531209
spi_context_release(&data->ctx, ret);
10541210

10551211
return ret;
@@ -1383,7 +1539,7 @@ static DEVICE_API(spi, api_funcs) = {
13831539
.transceive_async = spi_stm32_transceive_async,
13841540
#endif
13851541
#ifdef CONFIG_SPI_RTIO
1386-
.iodev_submit = spi_rtio_iodev_default_submit,
1542+
.iodev_submit = spi_stm32_iodev_submit,
13871543
#endif
13881544
.release = spi_stm32_release,
13891545
};
@@ -1507,6 +1663,10 @@ static int spi_stm32_init(const struct device *dev)
15071663

15081664
#endif /* CONFIG_SPI_STM32_DMA */
15091665

1666+
#ifdef CONFIG_SPI_RTIO
1667+
spi_rtio_init(data->rtio_ctx, dev);
1668+
#endif /* CONFIG_SPI_RTIO */
1669+
15101670
return pm_device_driver_init(dev, spi_stm32_pm_action);
15111671
}
15121672

@@ -1602,13 +1762,19 @@ static int spi_stm32_init(const struct device *dev)
16021762
(.mssi_clocks = DT_INST_PROP(id, mssi_clock),)) \
16031763
}; \
16041764
\
1765+
IF_ENABLED(CONFIG_SPI_RTIO, \
1766+
(SPI_RTIO_DEFINE(spi_stm32_rtio_##id, \
1767+
CONFIG_SPI_STM32_RTIO_SQ_SIZE, \
1768+
CONFIG_SPI_STM32_RTIO_CQ_SIZE))) \
1769+
\
16051770
static struct spi_stm32_data spi_stm32_dev_data_##id = { \
16061771
SPI_CONTEXT_INIT_LOCK(spi_stm32_dev_data_##id, ctx), \
16071772
SPI_CONTEXT_INIT_SYNC(spi_stm32_dev_data_##id, ctx), \
16081773
SPI_DMA_CHANNEL(id, rx, RX, PERIPHERAL, MEMORY) \
16091774
SPI_DMA_CHANNEL(id, tx, TX, MEMORY, PERIPHERAL) \
16101775
SPI_DMA_STATUS_SEM(id) \
16111776
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx) \
1777+
IF_ENABLED(CONFIG_SPI_RTIO, (.rtio_ctx = &spi_stm32_rtio_##id,))\
16121778
}; \
16131779
\
16141780
PM_DEVICE_DT_INST_DEFINE(id, spi_stm32_pm_action); \

drivers/spi/spi_ll_stm32.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct stream {
6565
#endif
6666

6767
struct spi_stm32_data {
68+
#ifdef CONFIG_SPI_RTIO
69+
struct spi_rtio *rtio_ctx;
70+
#endif /* CONFIG_SPI_RTIO */
6871
struct spi_context ctx;
6972
#ifdef CONFIG_SPI_STM32_DMA
7073
struct k_sem status_sem;
@@ -184,6 +187,17 @@ static inline void ll_func_disable_int_errors(SPI_TypeDef *spi)
184187
#endif /* st_stm32h7_spi */
185188
}
186189

190+
static inline bool ll_func_are_int_disabled(SPI_TypeDef *spi)
191+
{
192+
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
193+
return (spi->IER == 0U);
194+
#else
195+
return !LL_SPI_IsEnabledIT_ERR(spi) &&
196+
!LL_SPI_IsEnabledIT_RXNE(spi) &&
197+
!LL_SPI_IsEnabledIT_TXE(spi);
198+
#endif
199+
}
200+
187201
static inline uint32_t ll_func_spi_is_busy(SPI_TypeDef *spi)
188202
{
189203
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)

0 commit comments

Comments
 (0)