2023-11-02 19:38:54

by Ben Wolsieffer

[permalink] [raw]
Subject: [PATCH v2 0/5] Add STM32F7 SPI support

This series adds support for SPI on STM32F7 processors. The STM32F7 SPI
peripheral is nearly identical to the STM32F4, with the only significant
differences being that it supports a wider range of word sizes, and the
addition of 32-bit transmit and receive FIFOs.

v2:
- Add missing commit body

Ben Wolsieffer (5):
spi: stm32: rename stm32f4_* to stm32fx_*
spi: stm32: use callbacks for read_rx and write_tx
dt-bindings: spi: add stm32f7-spi compatible
spi: stm32: add STM32F7 support
ARM: dts: stm32: add SPI support on STM32F746

.../devicetree/bindings/spi/st,stm32-spi.yaml | 1 +
arch/arm/boot/dts/st/stm32f746.dtsi | 60 +++
drivers/spi/spi-stm32.c | 455 ++++++++++++------
3 files changed, 367 insertions(+), 149 deletions(-)

--
2.42.0


2023-11-02 19:39:18

by Ben Wolsieffer

[permalink] [raw]
Subject: [PATCH v2 4/5] spi: stm32: add STM32F7 support

The STM32F7 SPI peripheral is similar to the STM32F4, except it allows
arbitrary word lengths between 4 and 16 bits, and has a small 32-bit
FIFO that allows two 8-bit or smaller words to be transferred with a
single 16-bit read/write.

Signed-off-by: Ben Wolsieffer <[email protected]>
---
drivers/spi/spi-stm32.c | 149 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 149 insertions(+)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 427788d18532..94df3836834c 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -41,6 +41,7 @@
#define STM32FX_SPI_CR1_SSM BIT(9)
#define STM32FX_SPI_CR1_RXONLY BIT(10)
#define STM32F4_SPI_CR1_DFF BIT(11)
+#define STM32F7_SPI_CR1_CRCL BIT(11)
#define STM32FX_SPI_CR1_CRCNEXT BIT(12)
#define STM32FX_SPI_CR1_CRCEN BIT(13)
#define STM32FX_SPI_CR1_BIDIOE BIT(14)
@@ -56,6 +57,10 @@
#define STM32FX_SPI_CR2_ERRIE BIT(5)
#define STM32FX_SPI_CR2_RXNEIE BIT(6)
#define STM32FX_SPI_CR2_TXEIE BIT(7)
+#define STM32F7_SPI_CR2_DS GENMASK(11, 8)
+#define STM32F7_SPI_CR2_FRXTH BIT(12)
+#define STM32F7_SPI_CR2_LDMA_RX BIT(13)
+#define STM32F7_SPI_CR2_LDMA_TX BIT(14)

/* STM32FX_SPI_SR bit fields */
#define STM32FX_SPI_SR_RXNE BIT(0)
@@ -67,6 +72,8 @@
#define STM32FX_SPI_SR_OVR BIT(6)
#define STM32FX_SPI_SR_BSY BIT(7)
#define STM32FX_SPI_SR_FRE BIT(8)
+#define STM32F7_SPI_SR_FRLVL GENMASK(10, 9)
+#define STM32F7_SPI_SR_FTLVL GENMASK(12, 11)

/* STM32FX_SPI_I2SCFGR bit fields */
#define STM32FX_SPI_I2SCFGR_I2SMOD BIT(11)
@@ -413,6 +420,16 @@ static int stm32f4_spi_get_bpw_mask(struct stm32_spi *spi)
return SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
}

+/**
+ * stm32f7_spi_get_bpw_mask - Return bits per word mask
+ * @spi: pointer to the spi controller data structure
+ */
+static int stm32f7_spi_get_bpw_mask(struct stm32_spi *spi)
+{
+ dev_dbg(spi->dev, "16-bit maximum data frame\n");
+ return SPI_BPW_RANGE_MASK(4, 16);
+}
+
/**
* stm32h7_spi_get_bpw_mask - Return bits per word mask
* @spi: pointer to the spi controller data structure
@@ -526,6 +543,35 @@ static void stm32f4_spi_write_tx(struct stm32_spi *spi)
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
}

+/**
+ * stm32f7_spi_write_tx - Write bytes to Transmit Data Register
+ * @spi: pointer to the spi controller data structure
+ *
+ * Read from tx_buf depends on remaining bytes to avoid to read beyond
+ * tx_buf end.
+ */
+static void stm32f7_spi_write_tx(struct stm32_spi *spi)
+{
+ if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
+ STM32FX_SPI_SR_TXE)) {
+ u32 offs = spi->cur_xferlen - spi->tx_len;
+
+ if (spi->tx_len >= sizeof(u16)) {
+ const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs);
+
+ writew_relaxed(*tx_buf16, spi->base + STM32FX_SPI_DR);
+ spi->tx_len -= sizeof(u16);
+ } else {
+ const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs);
+
+ writeb_relaxed(*tx_buf8, spi->base + STM32FX_SPI_DR);
+ spi->tx_len -= sizeof(u8);
+ }
+ }
+
+ dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
+}
+
/**
* stm32h7_spi_write_txfifo - Write bytes in Transmit Data Register
* @spi: pointer to the spi controller data structure
@@ -590,6 +636,46 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi)
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->rx_len);
}

+/**
+ * stm32f7_spi_read_rx - Read bytes from Receive Data Register
+ * @spi: pointer to the spi controller data structure
+ *
+ * Write in rx_buf depends on remaining bytes to avoid to write beyond
+ * rx_buf end.
+ */
+static void stm32f7_spi_read_rx(struct stm32_spi *spi)
+{
+ u32 sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
+ u32 frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
+
+ while ((spi->rx_len > 0) && (frlvl > 0)) {
+ u32 offs = spi->cur_xferlen - spi->rx_len;
+
+ if ((spi->rx_len >= sizeof(u16)) && (frlvl >= 2)) {
+ u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs);
+
+ *rx_buf16 = readw_relaxed(spi->base + STM32FX_SPI_DR);
+ spi->rx_len -= sizeof(u16);
+ } else {
+ u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
+
+ *rx_buf8 = readb_relaxed(spi->base + STM32FX_SPI_DR);
+ spi->rx_len -= sizeof(u8);
+ }
+
+ sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
+ frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
+ }
+
+ if (spi->rx_len >= sizeof(u16))
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+ else
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+
+ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n",
+ __func__, spi->rx_len, sr);
+}
+
/**
* stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register
* @spi: pointer to the spi controller data structure
@@ -1224,6 +1310,22 @@ static void stm32fx_spi_transfer_one_dma_start(struct stm32_spi *spi)
stm32_spi_enable(spi);
}

+/**
+ * stm32f7_spi_transfer_one_dma_start - Set SPI driver registers to start
+ * transfer using DMA
+ * @spi: pointer to the spi controller data structure
+ */
+static void stm32f7_spi_transfer_one_dma_start(struct stm32_spi *spi)
+{
+ /* Configure DMA request trigger threshold according to DMA width */
+ if (spi->cur_bpw <= 8)
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+ else
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+
+ stm32fx_spi_transfer_one_dma_start(spi);
+}
+
/**
* stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
* transfer using DMA
@@ -1362,6 +1464,31 @@ static void stm32f4_spi_set_bpw(struct stm32_spi *spi)
stm32_spi_clr_bits(spi, STM32FX_SPI_CR1, STM32F4_SPI_CR1_DFF);
}

+/**
+ * stm32f7_spi_set_bpw - Configure bits per word
+ * @spi: pointer to the spi controller data structure
+ */
+static void stm32f7_spi_set_bpw(struct stm32_spi *spi)
+{
+ u32 bpw;
+ u32 cr2_clrb = 0, cr2_setb = 0;
+
+ bpw = spi->cur_bpw - 1;
+
+ cr2_clrb |= STM32F7_SPI_CR2_DS;
+ cr2_setb |= FIELD_PREP(STM32F7_SPI_CR2_DS, bpw);
+
+ if (spi->rx_len >= sizeof(u16))
+ cr2_clrb |= STM32F7_SPI_CR2_FRXTH;
+ else
+ cr2_setb |= STM32F7_SPI_CR2_FRXTH;
+
+ writel_relaxed(
+ (readl_relaxed(spi->base + STM32FX_SPI_CR2) &
+ ~cr2_clrb) | cr2_setb,
+ spi->base + STM32FX_SPI_CR2);
+}
+
/**
* stm32h7_spi_set_bpw - configure bits per word
* @spi: pointer to the spi controller data structure
@@ -1771,6 +1898,27 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
.flags = SPI_CONTROLLER_MUST_TX,
};

+static const struct stm32_spi_cfg stm32f7_spi_cfg = {
+ .regs = &stm32fx_spi_regspec,
+ .get_bpw_mask = stm32f7_spi_get_bpw_mask,
+ .disable = stm32fx_spi_disable,
+ .config = stm32fx_spi_config,
+ .set_bpw = stm32f7_spi_set_bpw,
+ .set_mode = stm32fx_spi_set_mode,
+ .write_tx = stm32f7_spi_write_tx,
+ .read_rx = stm32f7_spi_read_rx,
+ .transfer_one_dma_start = stm32f7_spi_transfer_one_dma_start,
+ .dma_tx_cb = stm32fx_spi_dma_tx_cb,
+ .dma_rx_cb = stm32_spi_dma_rx_cb,
+ .transfer_one_irq = stm32fx_spi_transfer_one_irq,
+ .irq_handler_event = stm32fx_spi_irq_event,
+ .irq_handler_thread = stm32fx_spi_irq_thread,
+ .baud_rate_div_min = STM32FX_SPI_BR_DIV_MIN,
+ .baud_rate_div_max = STM32FX_SPI_BR_DIV_MAX,
+ .has_fifo = false,
+ .flags = SPI_CONTROLLER_MUST_TX,
+};
+
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
.regs = &stm32h7_spi_regspec,
.get_fifo_size = stm32h7_spi_get_fifo_size,
@@ -1800,6 +1948,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
static const struct of_device_id stm32_spi_of_match[] = {
{ .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg },
{ .compatible = "st,stm32f4-spi", .data = (void *)&stm32f4_spi_cfg },
+ { .compatible = "st,stm32f7-spi", .data = (void *)&stm32f7_spi_cfg },
{},
};
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
--
2.42.0