blob: ddb410a94c010360879fd74637e0cb10060e9aed [file] [log] [blame]
Patrice Chotarda2a89b22019-04-30 18:08:28 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4 *
5 * Driver for STMicroelectronics Serial peripheral interface (SPI)
6 */
Patrick Delaunay7a41cb52020-11-06 19:01:52 +01007
8#define LOG_CATEGORY UCLASS_SPI
9
Tom Rinid678a592024-05-18 20:20:43 -060010#include <common.h>
Patrice Chotarda2a89b22019-04-30 18:08:28 +020011#include <clk.h>
12#include <dm.h>
13#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060014#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070015#include <malloc.h>
Patrice Chotarda2a89b22019-04-30 18:08:28 +020016#include <reset.h>
17#include <spi.h>
Simon Glass336d4612020-02-03 07:36:16 -070018#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060019#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060020#include <linux/delay.h>
Simon Glass1e94b462023-09-14 18:21:46 -060021#include <linux/printk.h>
Patrice Chotarda2a89b22019-04-30 18:08:28 +020022
23#include <asm/io.h>
24#include <asm/gpio.h>
25#include <linux/bitfield.h>
26#include <linux/iopoll.h>
27
28/* STM32 SPI registers */
29#define STM32_SPI_CR1 0x00
30#define STM32_SPI_CR2 0x04
31#define STM32_SPI_CFG1 0x08
32#define STM32_SPI_CFG2 0x0C
33#define STM32_SPI_SR 0x14
34#define STM32_SPI_IFCR 0x18
35#define STM32_SPI_TXDR 0x20
36#define STM32_SPI_RXDR 0x30
37#define STM32_SPI_I2SCFGR 0x50
38
39/* STM32_SPI_CR1 bit fields */
40#define SPI_CR1_SPE BIT(0)
41#define SPI_CR1_MASRX BIT(8)
42#define SPI_CR1_CSTART BIT(9)
43#define SPI_CR1_CSUSP BIT(10)
44#define SPI_CR1_HDDIR BIT(11)
45#define SPI_CR1_SSI BIT(12)
46
47/* STM32_SPI_CR2 bit fields */
48#define SPI_CR2_TSIZE GENMASK(15, 0)
49
50/* STM32_SPI_CFG1 bit fields */
51#define SPI_CFG1_DSIZE GENMASK(4, 0)
52#define SPI_CFG1_DSIZE_MIN 3
53#define SPI_CFG1_FTHLV_SHIFT 5
54#define SPI_CFG1_FTHLV GENMASK(8, 5)
55#define SPI_CFG1_MBR_SHIFT 28
56#define SPI_CFG1_MBR GENMASK(30, 28)
57#define SPI_CFG1_MBR_MIN 0
58#define SPI_CFG1_MBR_MAX FIELD_GET(SPI_CFG1_MBR, SPI_CFG1_MBR)
59
60/* STM32_SPI_CFG2 bit fields */
61#define SPI_CFG2_COMM_SHIFT 17
62#define SPI_CFG2_COMM GENMASK(18, 17)
63#define SPI_CFG2_MASTER BIT(22)
64#define SPI_CFG2_LSBFRST BIT(23)
65#define SPI_CFG2_CPHA BIT(24)
66#define SPI_CFG2_CPOL BIT(25)
67#define SPI_CFG2_SSM BIT(26)
68#define SPI_CFG2_AFCNTR BIT(31)
69
70/* STM32_SPI_SR bit fields */
71#define SPI_SR_RXP BIT(0)
72#define SPI_SR_TXP BIT(1)
73#define SPI_SR_EOT BIT(3)
74#define SPI_SR_TXTF BIT(4)
75#define SPI_SR_OVR BIT(6)
76#define SPI_SR_SUSP BIT(11)
77#define SPI_SR_RXPLVL_SHIFT 13
78#define SPI_SR_RXPLVL GENMASK(14, 13)
79#define SPI_SR_RXWNE BIT(15)
80
81/* STM32_SPI_IFCR bit fields */
82#define SPI_IFCR_ALL GENMASK(11, 3)
83
84/* STM32_SPI_I2SCFGR bit fields */
85#define SPI_I2SCFGR_I2SMOD BIT(0)
86
87#define MAX_CS_COUNT 4
88
89/* SPI Master Baud Rate min/max divisor */
90#define STM32_MBR_DIV_MIN (2 << SPI_CFG1_MBR_MIN)
91#define STM32_MBR_DIV_MAX (2 << SPI_CFG1_MBR_MAX)
92
93#define STM32_SPI_TIMEOUT_US 100000
94
95/* SPI Communication mode */
96#define SPI_FULL_DUPLEX 0
97#define SPI_SIMPLEX_TX 1
98#define SPI_SIMPLEX_RX 2
99#define SPI_HALF_DUPLEX 3
100
Patrice Chotard81b24452021-08-03 11:16:40 +0200101struct stm32_spi_plat {
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200102 void __iomem *base;
103 struct clk clk;
104 struct reset_ctl rst_ctl;
105 struct gpio_desc cs_gpios[MAX_CS_COUNT];
Patrice Chotard81b24452021-08-03 11:16:40 +0200106};
107
108struct stm32_spi_priv {
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200109 ulong bus_clk_rate;
110 unsigned int fifo_size;
111 unsigned int cur_bpw;
112 unsigned int cur_hz;
113 unsigned int cur_xferlen; /* current transfer length in bytes */
Patrick Delaunay54ef8fb2019-06-21 15:26:58 +0200114 unsigned int tx_len; /* number of data to be written in bytes */
115 unsigned int rx_len; /* number of data to be read in bytes */
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200116 const void *tx_buf; /* data to be written, or NULL */
117 void *rx_buf; /* data to be read, or NULL */
118 u32 cur_mode;
119 bool cs_high;
120};
121
Patrice Chotard81b24452021-08-03 11:16:40 +0200122static void stm32_spi_write_txfifo(struct udevice *bus)
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200123{
Patrice Chotard81b24452021-08-03 11:16:40 +0200124 struct stm32_spi_priv *priv = dev_get_priv(bus);
125 struct stm32_spi_plat *plat = dev_get_plat(bus);
126 void __iomem *base = plat->base;
127
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200128 while ((priv->tx_len > 0) &&
Patrice Chotard81b24452021-08-03 11:16:40 +0200129 (readl(base + STM32_SPI_SR) & SPI_SR_TXP)) {
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200130 u32 offs = priv->cur_xferlen - priv->tx_len;
131
132 if (priv->tx_len >= sizeof(u32) &&
133 IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) {
134 const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs);
135
Patrice Chotard81b24452021-08-03 11:16:40 +0200136 writel(*tx_buf32, base + STM32_SPI_TXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200137 priv->tx_len -= sizeof(u32);
138 } else if (priv->tx_len >= sizeof(u16) &&
139 IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) {
140 const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs);
141
Patrice Chotard81b24452021-08-03 11:16:40 +0200142 writew(*tx_buf16, base + STM32_SPI_TXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200143 priv->tx_len -= sizeof(u16);
144 } else {
145 const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs);
146
Patrice Chotard81b24452021-08-03 11:16:40 +0200147 writeb(*tx_buf8, base + STM32_SPI_TXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200148 priv->tx_len -= sizeof(u8);
149 }
150 }
151
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100152 log_debug("%d bytes left\n", priv->tx_len);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200153}
154
Patrice Chotard81b24452021-08-03 11:16:40 +0200155static void stm32_spi_read_rxfifo(struct udevice *bus)
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200156{
Patrice Chotard81b24452021-08-03 11:16:40 +0200157 struct stm32_spi_priv *priv = dev_get_priv(bus);
158 struct stm32_spi_plat *plat = dev_get_plat(bus);
159 void __iomem *base = plat->base;
160 u32 sr = readl(base + STM32_SPI_SR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200161 u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT;
162
163 while ((priv->rx_len > 0) &&
164 ((sr & SPI_SR_RXP) ||
165 ((sr & SPI_SR_EOT) && ((sr & SPI_SR_RXWNE) || (rxplvl > 0))))) {
166 u32 offs = priv->cur_xferlen - priv->rx_len;
167
168 if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u32)) &&
169 (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) {
170 u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs);
171
Patrice Chotard81b24452021-08-03 11:16:40 +0200172 *rx_buf32 = readl(base + STM32_SPI_RXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200173 priv->rx_len -= sizeof(u32);
174 } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) &&
175 (priv->rx_len >= sizeof(u16) ||
176 (!(sr & SPI_SR_RXWNE) &&
177 (rxplvl >= 2 || priv->cur_bpw > 8)))) {
178 u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs);
179
Patrice Chotard81b24452021-08-03 11:16:40 +0200180 *rx_buf16 = readw(base + STM32_SPI_RXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200181 priv->rx_len -= sizeof(u16);
182 } else {
183 u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs);
184
Patrice Chotard81b24452021-08-03 11:16:40 +0200185 *rx_buf8 = readb(base + STM32_SPI_RXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200186 priv->rx_len -= sizeof(u8);
187 }
188
Patrice Chotard81b24452021-08-03 11:16:40 +0200189 sr = readl(base + STM32_SPI_SR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200190 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT;
191 }
192
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100193 log_debug("%d bytes left\n", priv->rx_len);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200194}
195
Patrice Chotard81b24452021-08-03 11:16:40 +0200196static int stm32_spi_enable(void __iomem *base)
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200197{
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100198 log_debug("\n");
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200199
200 /* Enable the SPI hardware */
Patrice Chotard81b24452021-08-03 11:16:40 +0200201 setbits_le32(base + STM32_SPI_CR1, SPI_CR1_SPE);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200202
203 return 0;
204}
205
Patrice Chotard81b24452021-08-03 11:16:40 +0200206static int stm32_spi_disable(void __iomem *base)
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200207{
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100208 log_debug("\n");
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200209
210 /* Disable the SPI hardware */
Patrice Chotard81b24452021-08-03 11:16:40 +0200211 clrbits_le32(base + STM32_SPI_CR1, SPI_CR1_SPE);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200212
213 return 0;
214}
215
216static int stm32_spi_claim_bus(struct udevice *slave)
217{
218 struct udevice *bus = dev_get_parent(slave);
Patrice Chotard81b24452021-08-03 11:16:40 +0200219 struct stm32_spi_plat *plat = dev_get_plat(bus);
220 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200221
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100222 dev_dbg(slave, "\n");
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200223
224 /* Enable the SPI hardware */
Patrice Chotard81b24452021-08-03 11:16:40 +0200225 return stm32_spi_enable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200226}
227
228static int stm32_spi_release_bus(struct udevice *slave)
229{
230 struct udevice *bus = dev_get_parent(slave);
Patrice Chotard81b24452021-08-03 11:16:40 +0200231 struct stm32_spi_plat *plat = dev_get_plat(bus);
232 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200233
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100234 dev_dbg(slave, "\n");
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200235
236 /* Disable the SPI hardware */
Patrice Chotard81b24452021-08-03 11:16:40 +0200237 return stm32_spi_disable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200238}
239
240static void stm32_spi_stopxfer(struct udevice *dev)
241{
Patrice Chotard81b24452021-08-03 11:16:40 +0200242 struct stm32_spi_plat *plat = dev_get_plat(dev);
243 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200244 u32 cr1, sr;
245 int ret;
246
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100247 dev_dbg(dev, "\n");
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200248
Patrice Chotard81b24452021-08-03 11:16:40 +0200249 cr1 = readl(base + STM32_SPI_CR1);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200250
251 if (!(cr1 & SPI_CR1_SPE))
252 return;
253
254 /* Wait on EOT or suspend the flow */
Patrice Chotard81b24452021-08-03 11:16:40 +0200255 ret = readl_poll_timeout(base + STM32_SPI_SR, sr,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200256 !(sr & SPI_SR_EOT), 100000);
257 if (ret < 0) {
258 if (cr1 & SPI_CR1_CSTART) {
Patrice Chotard81b24452021-08-03 11:16:40 +0200259 writel(cr1 | SPI_CR1_CSUSP, base + STM32_SPI_CR1);
260 if (readl_poll_timeout(base + STM32_SPI_SR,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200261 sr, !(sr & SPI_SR_SUSP),
262 100000) < 0)
263 dev_err(dev, "Suspend request timeout\n");
264 }
265 }
266
267 /* clear status flags */
Patrice Chotard81b24452021-08-03 11:16:40 +0200268 setbits_le32(base + STM32_SPI_IFCR, SPI_IFCR_ALL);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200269}
270
271static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable)
272{
Patrice Chotard81b24452021-08-03 11:16:40 +0200273 struct stm32_spi_plat *plat = dev_get_plat(dev);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200274 struct stm32_spi_priv *priv = dev_get_priv(dev);
275
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100276 dev_dbg(dev, "cs=%d enable=%d\n", cs, enable);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200277
278 if (cs >= MAX_CS_COUNT)
279 return -ENODEV;
280
Patrice Chotard81b24452021-08-03 11:16:40 +0200281 if (!dm_gpio_is_valid(&plat->cs_gpios[cs]))
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200282 return -EINVAL;
283
284 if (priv->cs_high)
285 enable = !enable;
286
Patrice Chotard81b24452021-08-03 11:16:40 +0200287 return dm_gpio_set_value(&plat->cs_gpios[cs], enable ? 1 : 0);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200288}
289
290static int stm32_spi_set_mode(struct udevice *bus, uint mode)
291{
292 struct stm32_spi_priv *priv = dev_get_priv(bus);
Patrice Chotard81b24452021-08-03 11:16:40 +0200293 struct stm32_spi_plat *plat = dev_get_plat(bus);
294 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200295 u32 cfg2_clrb = 0, cfg2_setb = 0;
296
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100297 dev_dbg(bus, "mode=%d\n", mode);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200298
299 if (mode & SPI_CPOL)
300 cfg2_setb |= SPI_CFG2_CPOL;
301 else
302 cfg2_clrb |= SPI_CFG2_CPOL;
303
304 if (mode & SPI_CPHA)
305 cfg2_setb |= SPI_CFG2_CPHA;
306 else
307 cfg2_clrb |= SPI_CFG2_CPHA;
308
309 if (mode & SPI_LSB_FIRST)
310 cfg2_setb |= SPI_CFG2_LSBFRST;
311 else
312 cfg2_clrb |= SPI_CFG2_LSBFRST;
313
314 if (cfg2_clrb || cfg2_setb)
Patrice Chotard81b24452021-08-03 11:16:40 +0200315 clrsetbits_le32(base + STM32_SPI_CFG2,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200316 cfg2_clrb, cfg2_setb);
317
318 if (mode & SPI_CS_HIGH)
319 priv->cs_high = true;
320 else
321 priv->cs_high = false;
322 return 0;
323}
324
325static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len)
326{
327 struct stm32_spi_priv *priv = dev_get_priv(dev);
Patrice Chotard81b24452021-08-03 11:16:40 +0200328 struct stm32_spi_plat *plat = dev_get_plat(dev);
329 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200330 u32 fthlv, half_fifo;
331
332 /* data packet should not exceed 1/2 of fifo space */
333 half_fifo = (priv->fifo_size / 2);
334
335 /* data_packet should not exceed transfer length */
336 fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo;
337
338 /* align packet size with data registers access */
339 fthlv -= (fthlv % 4);
340
341 if (!fthlv)
342 fthlv = 1;
Patrice Chotard81b24452021-08-03 11:16:40 +0200343 clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_FTHLV,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200344 (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT);
345
346 return 0;
347}
348
349static int stm32_spi_set_speed(struct udevice *bus, uint hz)
350{
351 struct stm32_spi_priv *priv = dev_get_priv(bus);
Patrice Chotard81b24452021-08-03 11:16:40 +0200352 struct stm32_spi_plat *plat = dev_get_plat(bus);
353 void __iomem *base = plat->base;
Patrick Delaunay54ef8fb2019-06-21 15:26:58 +0200354 u32 mbrdiv;
355 long div;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200356
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100357 dev_dbg(bus, "hz=%d\n", hz);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200358
359 if (priv->cur_hz == hz)
360 return 0;
361
362 div = DIV_ROUND_UP(priv->bus_clk_rate, hz);
363
364 if (div < STM32_MBR_DIV_MIN ||
365 div > STM32_MBR_DIV_MAX)
366 return -EINVAL;
367
368 /* Determine the first power of 2 greater than or equal to div */
369 if (div & (div - 1))
370 mbrdiv = fls(div);
371 else
372 mbrdiv = fls(div) - 1;
373
Patrick Delaunay54ef8fb2019-06-21 15:26:58 +0200374 if (!mbrdiv)
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200375 return -EINVAL;
376
Patrice Chotard81b24452021-08-03 11:16:40 +0200377 clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_MBR,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200378 (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT);
379
380 priv->cur_hz = hz;
381
382 return 0;
383}
384
385static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
386 const void *dout, void *din, unsigned long flags)
387{
388 struct udevice *bus = dev_get_parent(slave);
Simon Glass8a8d24b2020-12-03 16:55:23 -0700389 struct dm_spi_slave_plat *slave_plat;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200390 struct stm32_spi_priv *priv = dev_get_priv(bus);
Patrice Chotard81b24452021-08-03 11:16:40 +0200391 struct stm32_spi_plat *plat = dev_get_plat(bus);
392 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200393 u32 sr;
394 u32 ifcr = 0;
395 u32 xferlen;
396 u32 mode;
397 int xfer_status = 0;
398
399 xferlen = bitlen / 8;
400
401 if (xferlen <= SPI_CR2_TSIZE)
Patrice Chotard81b24452021-08-03 11:16:40 +0200402 writel(xferlen, base + STM32_SPI_CR2);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200403 else
404 return -EMSGSIZE;
405
406 priv->tx_buf = dout;
407 priv->rx_buf = din;
408 priv->tx_len = priv->tx_buf ? bitlen / 8 : 0;
409 priv->rx_len = priv->rx_buf ? bitlen / 8 : 0;
410
411 mode = SPI_FULL_DUPLEX;
412 if (!priv->tx_buf)
413 mode = SPI_SIMPLEX_RX;
414 else if (!priv->rx_buf)
415 mode = SPI_SIMPLEX_TX;
416
417 if (priv->cur_xferlen != xferlen || priv->cur_mode != mode) {
418 priv->cur_mode = mode;
419 priv->cur_xferlen = xferlen;
420
421 /* Disable the SPI hardware to unlock CFG1/CFG2 registers */
Patrice Chotard81b24452021-08-03 11:16:40 +0200422 stm32_spi_disable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200423
Patrice Chotard81b24452021-08-03 11:16:40 +0200424 clrsetbits_le32(base + STM32_SPI_CFG2, SPI_CFG2_COMM,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200425 mode << SPI_CFG2_COMM_SHIFT);
426
427 stm32_spi_set_fthlv(bus, xferlen);
428
429 /* Enable the SPI hardware */
Patrice Chotard81b24452021-08-03 11:16:40 +0200430 stm32_spi_enable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200431 }
432
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100433 dev_dbg(bus, "priv->tx_len=%d priv->rx_len=%d\n",
434 priv->tx_len, priv->rx_len);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200435
Simon Glasscaa4daa2020-12-03 16:55:18 -0700436 slave_plat = dev_get_parent_plat(slave);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200437 if (flags & SPI_XFER_BEGIN)
438 stm32_spi_set_cs(bus, slave_plat->cs, false);
439
440 /* Be sure to have data in fifo before starting data transfer */
441 if (priv->tx_buf)
Patrice Chotard81b24452021-08-03 11:16:40 +0200442 stm32_spi_write_txfifo(bus);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200443
Patrice Chotard81b24452021-08-03 11:16:40 +0200444 setbits_le32(base + STM32_SPI_CR1, SPI_CR1_CSTART);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200445
446 while (1) {
Patrice Chotard81b24452021-08-03 11:16:40 +0200447 sr = readl(base + STM32_SPI_SR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200448
449 if (sr & SPI_SR_OVR) {
450 dev_err(bus, "Overrun: RX data lost\n");
451 xfer_status = -EIO;
452 break;
453 }
454
455 if (sr & SPI_SR_SUSP) {
456 dev_warn(bus, "System too slow is limiting data throughput\n");
457
458 if (priv->rx_buf && priv->rx_len > 0)
Patrice Chotard81b24452021-08-03 11:16:40 +0200459 stm32_spi_read_rxfifo(bus);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200460
461 ifcr |= SPI_SR_SUSP;
462 }
463
464 if (sr & SPI_SR_TXTF)
465 ifcr |= SPI_SR_TXTF;
466
467 if (sr & SPI_SR_TXP)
468 if (priv->tx_buf && priv->tx_len > 0)
Patrice Chotard81b24452021-08-03 11:16:40 +0200469 stm32_spi_write_txfifo(bus);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200470
471 if (sr & SPI_SR_RXP)
472 if (priv->rx_buf && priv->rx_len > 0)
Patrice Chotard81b24452021-08-03 11:16:40 +0200473 stm32_spi_read_rxfifo(bus);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200474
475 if (sr & SPI_SR_EOT) {
476 if (priv->rx_buf && priv->rx_len > 0)
Patrice Chotard81b24452021-08-03 11:16:40 +0200477 stm32_spi_read_rxfifo(bus);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200478 break;
479 }
480
Patrice Chotard81b24452021-08-03 11:16:40 +0200481 writel(ifcr, base + STM32_SPI_IFCR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200482 }
483
484 /* clear status flags */
Patrice Chotard81b24452021-08-03 11:16:40 +0200485 setbits_le32(base + STM32_SPI_IFCR, SPI_IFCR_ALL);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200486 stm32_spi_stopxfer(bus);
487
488 if (flags & SPI_XFER_END)
489 stm32_spi_set_cs(bus, slave_plat->cs, true);
490
491 return xfer_status;
492}
493
494static int stm32_spi_get_fifo_size(struct udevice *dev)
495{
Patrice Chotard81b24452021-08-03 11:16:40 +0200496 struct stm32_spi_plat *plat = dev_get_plat(dev);
497 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200498 u32 count = 0;
499
Patrice Chotard81b24452021-08-03 11:16:40 +0200500 stm32_spi_enable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200501
Patrice Chotard81b24452021-08-03 11:16:40 +0200502 while (readl(base + STM32_SPI_SR) & SPI_SR_TXP)
503 writeb(++count, base + STM32_SPI_TXDR);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200504
Patrice Chotard81b24452021-08-03 11:16:40 +0200505 stm32_spi_disable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200506
Patrick Delaunay7a41cb52020-11-06 19:01:52 +0100507 dev_dbg(dev, "%d x 8-bit fifo size\n", count);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200508
509 return count;
510}
511
Patrice Chotard81b24452021-08-03 11:16:40 +0200512static int stm32_spi_of_to_plat(struct udevice *dev)
513{
514 struct stm32_spi_plat *plat = dev_get_plat(dev);
515 int ret;
516
517 plat->base = dev_read_addr_ptr(dev);
518 if (!plat->base) {
519 dev_err(dev, "can't get registers base address\n");
520 return -ENOENT;
521 }
522
523 ret = clk_get_by_index(dev, 0, &plat->clk);
524 if (ret < 0)
525 return ret;
526
527 ret = reset_get_by_index(dev, 0, &plat->rst_ctl);
528 if (ret < 0)
Sean Andersonc9309f42023-12-16 14:38:42 -0500529 return ret;
Patrice Chotard81b24452021-08-03 11:16:40 +0200530
531 ret = gpio_request_list_by_name(dev, "cs-gpios", plat->cs_gpios,
532 ARRAY_SIZE(plat->cs_gpios), 0);
533 if (ret < 0) {
534 dev_err(dev, "Can't get %s cs gpios: %d", dev->name, ret);
Sean Andersonc9309f42023-12-16 14:38:42 -0500535 return -ENOENT;
Patrice Chotard81b24452021-08-03 11:16:40 +0200536 }
537
538 return 0;
Patrice Chotard81b24452021-08-03 11:16:40 +0200539}
540
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200541static int stm32_spi_probe(struct udevice *dev)
542{
Patrice Chotard81b24452021-08-03 11:16:40 +0200543 struct stm32_spi_plat *plat = dev_get_plat(dev);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200544 struct stm32_spi_priv *priv = dev_get_priv(dev);
Patrice Chotard81b24452021-08-03 11:16:40 +0200545 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200546 unsigned long clk_rate;
547 int ret;
Patrick Delaunay54ef8fb2019-06-21 15:26:58 +0200548 unsigned int i;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200549
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200550 /* enable clock */
Patrice Chotard81b24452021-08-03 11:16:40 +0200551 ret = clk_enable(&plat->clk);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200552 if (ret < 0)
553 return ret;
554
Patrice Chotard81b24452021-08-03 11:16:40 +0200555 clk_rate = clk_get_rate(&plat->clk);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200556 if (!clk_rate) {
557 ret = -EINVAL;
558 goto clk_err;
559 }
560
561 priv->bus_clk_rate = clk_rate;
562
563 /* perform reset */
Patrice Chotard81b24452021-08-03 11:16:40 +0200564 reset_assert(&plat->rst_ctl);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200565 udelay(2);
Patrice Chotard81b24452021-08-03 11:16:40 +0200566 reset_deassert(&plat->rst_ctl);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200567
568 priv->fifo_size = stm32_spi_get_fifo_size(dev);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200569 priv->cur_mode = SPI_FULL_DUPLEX;
570 priv->cur_xferlen = 0;
571 priv->cur_bpw = SPI_DEFAULT_WORDLEN;
Patrice Chotard81b24452021-08-03 11:16:40 +0200572 clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200573 priv->cur_bpw - 1);
574
Patrice Chotard81b24452021-08-03 11:16:40 +0200575 for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
576 if (!dm_gpio_is_valid(&plat->cs_gpios[i]))
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200577 continue;
578
Patrice Chotard81b24452021-08-03 11:16:40 +0200579 dm_gpio_set_dir_flags(&plat->cs_gpios[i],
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200580 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
581 }
582
583 /* Ensure I2SMOD bit is kept cleared */
Patrice Chotard81b24452021-08-03 11:16:40 +0200584 clrbits_le32(base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200585
586 /*
587 * - SS input value high
588 * - transmitter half duplex direction
589 * - automatic communication suspend when RX-Fifo is full
590 */
Patrice Chotard81b24452021-08-03 11:16:40 +0200591 setbits_le32(base + STM32_SPI_CR1,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200592 SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX);
593
594 /*
595 * - Set the master mode (default Motorola mode)
596 * - Consider 1 master/n slaves configuration and
597 * SS input value is determined by the SSI bit
598 * - keep control of all associated GPIOs
599 */
Patrice Chotard81b24452021-08-03 11:16:40 +0200600 setbits_le32(base + STM32_SPI_CFG2,
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200601 SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR);
602
603 return 0;
604
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200605clk_err:
Patrice Chotard81b24452021-08-03 11:16:40 +0200606 clk_disable(&plat->clk);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200607
608 return ret;
609};
610
611static int stm32_spi_remove(struct udevice *dev)
612{
Patrice Chotard81b24452021-08-03 11:16:40 +0200613 struct stm32_spi_plat *plat = dev_get_plat(dev);
614 void __iomem *base = plat->base;
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200615 int ret;
616
617 stm32_spi_stopxfer(dev);
Patrice Chotard81b24452021-08-03 11:16:40 +0200618 stm32_spi_disable(base);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200619
Patrice Chotard81b24452021-08-03 11:16:40 +0200620 ret = reset_assert(&plat->rst_ctl);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200621 if (ret < 0)
622 return ret;
623
Patrice Chotard81b24452021-08-03 11:16:40 +0200624 reset_free(&plat->rst_ctl);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200625
Sean Andersonc9309f42023-12-16 14:38:42 -0500626 return clk_disable(&plat->clk);
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200627};
628
629static const struct dm_spi_ops stm32_spi_ops = {
630 .claim_bus = stm32_spi_claim_bus,
631 .release_bus = stm32_spi_release_bus,
632 .set_mode = stm32_spi_set_mode,
633 .set_speed = stm32_spi_set_speed,
634 .xfer = stm32_spi_xfer,
635};
636
637static const struct udevice_id stm32_spi_ids[] = {
638 { .compatible = "st,stm32h7-spi", },
639 { }
640};
641
642U_BOOT_DRIVER(stm32_spi) = {
643 .name = "stm32_spi",
644 .id = UCLASS_SPI,
645 .of_match = stm32_spi_ids,
646 .ops = &stm32_spi_ops,
Patrice Chotard81b24452021-08-03 11:16:40 +0200647 .of_to_plat = stm32_spi_of_to_plat,
648 .plat_auto = sizeof(struct stm32_spi_plat),
649 .priv_auto = sizeof(struct stm32_spi_priv),
Patrice Chotarda2a89b22019-04-30 18:08:28 +0200650 .probe = stm32_spi_probe,
651 .remove = stm32_spi_remove,
652};