blob: 4cab0391f7d12cdbee03f64e3c1ae47c13ffed88 [file] [log] [blame]
Bhargav Shah3c34f752019-07-17 04:23:43 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 SiFive, Inc.
4 * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
5 *
6 * SiFive SPI controller driver (master mode only)
7 */
8
9#include <common.h>
10#include <dm.h>
Jagan Teki294b2912020-04-23 22:30:53 +053011#include <dm/device_compat.h>
Bhargav Shah3c34f752019-07-17 04:23:43 +000012#include <malloc.h>
Jagan Teki294b2912020-04-23 22:30:53 +053013#include <spi-mem.h>
Jagan Teki59798822020-04-23 22:30:55 +053014#include <wait_bit.h>
Bhargav Shah3c34f752019-07-17 04:23:43 +000015#include <asm/io.h>
16#include <linux/log2.h>
17#include <clk.h>
18
19#define SIFIVE_SPI_MAX_CS 32
20
21#define SIFIVE_SPI_DEFAULT_DEPTH 8
22#define SIFIVE_SPI_DEFAULT_BITS 8
23
24/* register offsets */
25#define SIFIVE_SPI_REG_SCKDIV 0x00 /* Serial clock divisor */
26#define SIFIVE_SPI_REG_SCKMODE 0x04 /* Serial clock mode */
27#define SIFIVE_SPI_REG_CSID 0x10 /* Chip select ID */
28#define SIFIVE_SPI_REG_CSDEF 0x14 /* Chip select default */
29#define SIFIVE_SPI_REG_CSMODE 0x18 /* Chip select mode */
30#define SIFIVE_SPI_REG_DELAY0 0x28 /* Delay control 0 */
31#define SIFIVE_SPI_REG_DELAY1 0x2c /* Delay control 1 */
32#define SIFIVE_SPI_REG_FMT 0x40 /* Frame format */
33#define SIFIVE_SPI_REG_TXDATA 0x48 /* Tx FIFO data */
34#define SIFIVE_SPI_REG_RXDATA 0x4c /* Rx FIFO data */
35#define SIFIVE_SPI_REG_TXMARK 0x50 /* Tx FIFO watermark */
36#define SIFIVE_SPI_REG_RXMARK 0x54 /* Rx FIFO watermark */
37#define SIFIVE_SPI_REG_FCTRL 0x60 /* SPI flash interface control */
38#define SIFIVE_SPI_REG_FFMT 0x64 /* SPI flash instruction format */
39#define SIFIVE_SPI_REG_IE 0x70 /* Interrupt Enable Register */
40#define SIFIVE_SPI_REG_IP 0x74 /* Interrupt Pendings Register */
41
42/* sckdiv bits */
43#define SIFIVE_SPI_SCKDIV_DIV_MASK 0xfffU
44
45/* sckmode bits */
46#define SIFIVE_SPI_SCKMODE_PHA BIT(0)
47#define SIFIVE_SPI_SCKMODE_POL BIT(1)
48#define SIFIVE_SPI_SCKMODE_MODE_MASK (SIFIVE_SPI_SCKMODE_PHA | \
49 SIFIVE_SPI_SCKMODE_POL)
50
51/* csmode bits */
52#define SIFIVE_SPI_CSMODE_MODE_AUTO 0U
53#define SIFIVE_SPI_CSMODE_MODE_HOLD 2U
54#define SIFIVE_SPI_CSMODE_MODE_OFF 3U
55
56/* delay0 bits */
57#define SIFIVE_SPI_DELAY0_CSSCK(x) ((u32)(x))
58#define SIFIVE_SPI_DELAY0_CSSCK_MASK 0xffU
59#define SIFIVE_SPI_DELAY0_SCKCS(x) ((u32)(x) << 16)
60#define SIFIVE_SPI_DELAY0_SCKCS_MASK (0xffU << 16)
61
62/* delay1 bits */
63#define SIFIVE_SPI_DELAY1_INTERCS(x) ((u32)(x))
64#define SIFIVE_SPI_DELAY1_INTERCS_MASK 0xffU
65#define SIFIVE_SPI_DELAY1_INTERXFR(x) ((u32)(x) << 16)
66#define SIFIVE_SPI_DELAY1_INTERXFR_MASK (0xffU << 16)
67
68/* fmt bits */
69#define SIFIVE_SPI_FMT_PROTO_SINGLE 0U
70#define SIFIVE_SPI_FMT_PROTO_DUAL 1U
71#define SIFIVE_SPI_FMT_PROTO_QUAD 2U
72#define SIFIVE_SPI_FMT_PROTO_MASK 3U
73#define SIFIVE_SPI_FMT_ENDIAN BIT(2)
74#define SIFIVE_SPI_FMT_DIR BIT(3)
75#define SIFIVE_SPI_FMT_LEN(x) ((u32)(x) << 16)
76#define SIFIVE_SPI_FMT_LEN_MASK (0xfU << 16)
77
78/* txdata bits */
79#define SIFIVE_SPI_TXDATA_DATA_MASK 0xffU
80#define SIFIVE_SPI_TXDATA_FULL BIT(31)
81
82/* rxdata bits */
83#define SIFIVE_SPI_RXDATA_DATA_MASK 0xffU
84#define SIFIVE_SPI_RXDATA_EMPTY BIT(31)
85
86/* ie and ip bits */
87#define SIFIVE_SPI_IP_TXWM BIT(0)
88#define SIFIVE_SPI_IP_RXWM BIT(1)
89
Jagan Tekiebca2c32020-04-23 22:30:54 +053090/* format protocol */
91#define SIFIVE_SPI_PROTO_QUAD 4 /* 4 lines I/O protocol transfer */
92#define SIFIVE_SPI_PROTO_DUAL 2 /* 2 lines I/O protocol transfer */
93#define SIFIVE_SPI_PROTO_SINGLE 1 /* 1 line I/O protocol transfer */
94
Bhargav Shah3c34f752019-07-17 04:23:43 +000095struct sifive_spi {
96 void *regs; /* base address of the registers */
97 u32 fifo_depth;
98 u32 bits_per_word;
99 u32 cs_inactive; /* Level of the CS pins when inactive*/
100 u32 freq;
101 u32 num_cs;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530102 u8 fmt_proto;
Bhargav Shah3c34f752019-07-17 04:23:43 +0000103};
104
105static void sifive_spi_prep_device(struct sifive_spi *spi,
Jagan Teki351ce7c2020-04-20 16:03:46 +0530106 struct dm_spi_slave_platdata *slave_plat)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000107{
108 /* Update the chip select polarity */
Jagan Teki351ce7c2020-04-20 16:03:46 +0530109 if (slave_plat->mode & SPI_CS_HIGH)
110 spi->cs_inactive &= ~BIT(slave_plat->cs);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000111 else
Jagan Teki351ce7c2020-04-20 16:03:46 +0530112 spi->cs_inactive |= BIT(slave_plat->cs);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000113 writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
114
115 /* Select the correct device */
Jagan Teki351ce7c2020-04-20 16:03:46 +0530116 writel(slave_plat->cs, spi->regs + SIFIVE_SPI_REG_CSID);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000117}
118
119static int sifive_spi_set_cs(struct sifive_spi *spi,
Jagan Teki351ce7c2020-04-20 16:03:46 +0530120 struct dm_spi_slave_platdata *slave_plat)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000121{
122 u32 cs_mode = SIFIVE_SPI_CSMODE_MODE_HOLD;
123
Jagan Teki351ce7c2020-04-20 16:03:46 +0530124 if (slave_plat->mode & SPI_CS_HIGH)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000125 cs_mode = SIFIVE_SPI_CSMODE_MODE_AUTO;
126
127 writel(cs_mode, spi->regs + SIFIVE_SPI_REG_CSMODE);
128
129 return 0;
130}
131
132static void sifive_spi_clear_cs(struct sifive_spi *spi)
133{
134 writel(SIFIVE_SPI_CSMODE_MODE_AUTO, spi->regs + SIFIVE_SPI_REG_CSMODE);
135}
136
137static void sifive_spi_prep_transfer(struct sifive_spi *spi,
Jagan Teki59798822020-04-23 22:30:55 +0530138 struct dm_spi_slave_platdata *slave_plat,
139 u8 *rx_ptr)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000140{
141 u32 cr;
142
143 /* Modify the SPI protocol mode */
144 cr = readl(spi->regs + SIFIVE_SPI_REG_FMT);
145
146 /* Bits per word ? */
147 cr &= ~SIFIVE_SPI_FMT_LEN_MASK;
148 cr |= SIFIVE_SPI_FMT_LEN(spi->bits_per_word);
149
150 /* LSB first? */
151 cr &= ~SIFIVE_SPI_FMT_ENDIAN;
Jagan Teki351ce7c2020-04-20 16:03:46 +0530152 if (slave_plat->mode & SPI_LSB_FIRST)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000153 cr |= SIFIVE_SPI_FMT_ENDIAN;
154
155 /* Number of wires ? */
156 cr &= ~SIFIVE_SPI_FMT_PROTO_MASK;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530157 switch (spi->fmt_proto) {
158 case SIFIVE_SPI_PROTO_QUAD:
Bhargav Shah3c34f752019-07-17 04:23:43 +0000159 cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530160 break;
161 case SIFIVE_SPI_PROTO_DUAL:
Bhargav Shah3c34f752019-07-17 04:23:43 +0000162 cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530163 break;
164 default:
Bhargav Shah3c34f752019-07-17 04:23:43 +0000165 cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530166 break;
167 }
Bhargav Shah3c34f752019-07-17 04:23:43 +0000168
169 /* SPI direction in/out ? */
170 cr &= ~SIFIVE_SPI_FMT_DIR;
Jagan Teki59798822020-04-23 22:30:55 +0530171 if (!rx_ptr)
Bhargav Shah3c34f752019-07-17 04:23:43 +0000172 cr |= SIFIVE_SPI_FMT_DIR;
173
174 writel(cr, spi->regs + SIFIVE_SPI_REG_FMT);
175}
176
177static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
178{
179 u32 data;
180
181 do {
182 data = readl(spi->regs + SIFIVE_SPI_REG_RXDATA);
183 } while (data & SIFIVE_SPI_RXDATA_EMPTY);
184
185 if (rx_ptr)
186 *rx_ptr = data & SIFIVE_SPI_RXDATA_DATA_MASK;
187}
188
189static void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
190{
191 u32 data;
192 u8 tx_data = (tx_ptr) ? *tx_ptr & SIFIVE_SPI_TXDATA_DATA_MASK :
193 SIFIVE_SPI_TXDATA_DATA_MASK;
194
195 do {
196 data = readl(spi->regs + SIFIVE_SPI_REG_TXDATA);
197 } while (data & SIFIVE_SPI_TXDATA_FULL);
198
199 writel(tx_data, spi->regs + SIFIVE_SPI_REG_TXDATA);
200}
201
Jagan Teki59798822020-04-23 22:30:55 +0530202static int sifive_spi_wait(struct sifive_spi *spi, u32 bit)
203{
204 return wait_for_bit_le32(spi->regs + SIFIVE_SPI_REG_IP,
205 bit, true, 100, false);
206}
207
Bhargav Shah3c34f752019-07-17 04:23:43 +0000208static int sifive_spi_xfer(struct udevice *dev, unsigned int bitlen,
209 const void *dout, void *din, unsigned long flags)
210{
211 struct udevice *bus = dev->parent;
212 struct sifive_spi *spi = dev_get_priv(bus);
Jagan Teki351ce7c2020-04-20 16:03:46 +0530213 struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
Jagan Teki59798822020-04-23 22:30:55 +0530214 const u8 *tx_ptr = dout;
Bhargav Shah3c34f752019-07-17 04:23:43 +0000215 u8 *rx_ptr = din;
216 u32 remaining_len;
217 int ret;
218
219 if (flags & SPI_XFER_BEGIN) {
Jagan Teki351ce7c2020-04-20 16:03:46 +0530220 sifive_spi_prep_device(spi, slave_plat);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000221
Jagan Teki351ce7c2020-04-20 16:03:46 +0530222 ret = sifive_spi_set_cs(spi, slave_plat);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000223 if (ret)
224 return ret;
225 }
226
Jagan Teki59798822020-04-23 22:30:55 +0530227 sifive_spi_prep_transfer(spi, slave_plat, rx_ptr);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000228
229 remaining_len = bitlen / 8;
230
231 while (remaining_len) {
Jagan Teki59798822020-04-23 22:30:55 +0530232 unsigned int n_words = min(remaining_len, spi->fifo_depth);
233 unsigned int tx_words, rx_words;
Bhargav Shah3c34f752019-07-17 04:23:43 +0000234
235 /* Enqueue n_words for transmission */
Jagan Teki59798822020-04-23 22:30:55 +0530236 for (tx_words = 0; tx_words < n_words; tx_words++) {
237 if (!tx_ptr)
238 sifive_spi_tx(spi, NULL);
239 else
240 sifive_spi_tx(spi, tx_ptr++);
Bhargav Shah3c34f752019-07-17 04:23:43 +0000241 }
242
Bhargav Shah3c34f752019-07-17 04:23:43 +0000243 if (rx_ptr) {
Jagan Teki59798822020-04-23 22:30:55 +0530244 /* Wait for transmission + reception to complete */
245 writel(n_words - 1, spi->regs + SIFIVE_SPI_REG_RXMARK);
246 ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_RXWM);
247 if (ret)
248 return ret;
249
250 /* Read out all the data from the RX FIFO */
251 for (rx_words = 0; rx_words < n_words; rx_words++)
252 sifive_spi_rx(spi, rx_ptr++);
253 } else {
254 /* Wait for transmission to complete */
255 ret = sifive_spi_wait(spi, SIFIVE_SPI_IP_TXWM);
256 if (ret)
257 return ret;
Bhargav Shah3c34f752019-07-17 04:23:43 +0000258 }
259
260 remaining_len -= n_words;
261 }
262
263 if (flags & SPI_XFER_END)
264 sifive_spi_clear_cs(spi);
265
266 return 0;
267}
268
Jagan Teki294b2912020-04-23 22:30:53 +0530269static int sifive_spi_exec_op(struct spi_slave *slave,
270 const struct spi_mem_op *op)
271{
272 struct udevice *dev = slave->dev;
Jagan Tekiebca2c32020-04-23 22:30:54 +0530273 struct sifive_spi *spi = dev_get_priv(dev->parent);
Jagan Teki294b2912020-04-23 22:30:53 +0530274 unsigned long flags = SPI_XFER_BEGIN;
275 u8 opcode = op->cmd.opcode;
276 unsigned int pos = 0;
277 const void *tx_buf = NULL;
278 void *rx_buf = NULL;
279 int op_len, i;
280 int ret;
281
282 if (!op->addr.nbytes && !op->dummy.nbytes && !op->data.nbytes)
283 flags |= SPI_XFER_END;
284
Jagan Tekiebca2c32020-04-23 22:30:54 +0530285 spi->fmt_proto = op->cmd.buswidth;
286
Jagan Teki294b2912020-04-23 22:30:53 +0530287 /* send the opcode */
288 ret = sifive_spi_xfer(dev, 8, (void *)&opcode, NULL, flags);
289 if (ret < 0) {
290 dev_err(dev, "failed to xfer opcode\n");
291 return ret;
292 }
293
294 op_len = op->addr.nbytes + op->dummy.nbytes;
295 u8 op_buf[op_len];
296
297 /* send the addr + dummy */
298 if (op->addr.nbytes) {
299 /* fill address */
300 for (i = 0; i < op->addr.nbytes; i++)
301 op_buf[pos + i] = op->addr.val >>
302 (8 * (op->addr.nbytes - i - 1));
303
304 pos += op->addr.nbytes;
305
306 /* fill dummy */
307 if (op->dummy.nbytes)
308 memset(op_buf + pos, 0xff, op->dummy.nbytes);
309
310 /* make sure to set end flag, if no data bytes */
311 if (!op->data.nbytes)
312 flags |= SPI_XFER_END;
313
Jagan Tekiebca2c32020-04-23 22:30:54 +0530314 spi->fmt_proto = op->addr.buswidth;
315
Jagan Teki294b2912020-04-23 22:30:53 +0530316 ret = sifive_spi_xfer(dev, op_len * 8, op_buf, NULL, flags);
317 if (ret < 0) {
318 dev_err(dev, "failed to xfer addr + dummy\n");
319 return ret;
320 }
321 }
322
323 /* send/received the data */
324 if (op->data.nbytes) {
325 if (op->data.dir == SPI_MEM_DATA_IN)
326 rx_buf = op->data.buf.in;
327 else
328 tx_buf = op->data.buf.out;
329
Jagan Tekiebca2c32020-04-23 22:30:54 +0530330 spi->fmt_proto = op->data.buswidth;
331
Jagan Teki294b2912020-04-23 22:30:53 +0530332 ret = sifive_spi_xfer(dev, op->data.nbytes * 8,
333 tx_buf, rx_buf, SPI_XFER_END);
334 if (ret) {
335 dev_err(dev, "failed to xfer data\n");
336 return ret;
337 }
338 }
339
340 return 0;
341}
342
Bhargav Shah3c34f752019-07-17 04:23:43 +0000343static int sifive_spi_set_speed(struct udevice *bus, uint speed)
344{
345 struct sifive_spi *spi = dev_get_priv(bus);
346 u32 scale;
347
348 if (speed > spi->freq)
349 speed = spi->freq;
350
351 /* Cofigure max speed */
352 scale = (DIV_ROUND_UP(spi->freq >> 1, speed) - 1)
353 & SIFIVE_SPI_SCKDIV_DIV_MASK;
354 writel(scale, spi->regs + SIFIVE_SPI_REG_SCKDIV);
355
356 return 0;
357}
358
359static int sifive_spi_set_mode(struct udevice *bus, uint mode)
360{
361 struct sifive_spi *spi = dev_get_priv(bus);
362 u32 cr;
363
364 /* Switch clock mode bits */
365 cr = readl(spi->regs + SIFIVE_SPI_REG_SCKMODE) &
366 ~SIFIVE_SPI_SCKMODE_MODE_MASK;
367 if (mode & SPI_CPHA)
368 cr |= SIFIVE_SPI_SCKMODE_PHA;
369 if (mode & SPI_CPOL)
370 cr |= SIFIVE_SPI_SCKMODE_POL;
371
372 writel(cr, spi->regs + SIFIVE_SPI_REG_SCKMODE);
373
374 return 0;
375}
376
377static int sifive_spi_cs_info(struct udevice *bus, uint cs,
378 struct spi_cs_info *info)
379{
380 struct sifive_spi *spi = dev_get_priv(bus);
381
382 if (cs >= spi->num_cs)
383 return -EINVAL;
384
385 return 0;
386}
387
388static void sifive_spi_init_hw(struct sifive_spi *spi)
389{
390 u32 cs_bits;
391
392 /* probe the number of CS lines */
393 spi->cs_inactive = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
394 writel(0xffffffffU, spi->regs + SIFIVE_SPI_REG_CSDEF);
395 cs_bits = readl(spi->regs + SIFIVE_SPI_REG_CSDEF);
396 writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF);
397 if (!cs_bits) {
398 printf("Could not auto probe CS lines\n");
399 return;
400 }
401
402 spi->num_cs = ilog2(cs_bits) + 1;
403 if (spi->num_cs > SIFIVE_SPI_MAX_CS) {
404 printf("Invalid number of spi slaves\n");
405 return;
406 }
407
408 /* Watermark interrupts are disabled by default */
409 writel(0, spi->regs + SIFIVE_SPI_REG_IE);
410
Jagan Teki59798822020-04-23 22:30:55 +0530411 /* Default watermark FIFO threshold values */
412 writel(1, spi->regs + SIFIVE_SPI_REG_TXMARK);
413 writel(0, spi->regs + SIFIVE_SPI_REG_RXMARK);
414
Bhargav Shah3c34f752019-07-17 04:23:43 +0000415 /* Set CS/SCK Delays and Inactive Time to defaults */
416 writel(SIFIVE_SPI_DELAY0_CSSCK(1) | SIFIVE_SPI_DELAY0_SCKCS(1),
417 spi->regs + SIFIVE_SPI_REG_DELAY0);
418 writel(SIFIVE_SPI_DELAY1_INTERCS(1) | SIFIVE_SPI_DELAY1_INTERXFR(0),
419 spi->regs + SIFIVE_SPI_REG_DELAY1);
420
421 /* Exit specialized memory-mapped SPI flash mode */
422 writel(0, spi->regs + SIFIVE_SPI_REG_FCTRL);
423}
424
425static int sifive_spi_probe(struct udevice *bus)
426{
427 struct sifive_spi *spi = dev_get_priv(bus);
428 struct clk clkdev;
429 int ret;
430
431 spi->regs = (void *)(ulong)dev_remap_addr(bus);
432 if (!spi->regs)
433 return -ENODEV;
434
435 spi->fifo_depth = dev_read_u32_default(bus,
436 "sifive,fifo-depth",
437 SIFIVE_SPI_DEFAULT_DEPTH);
438
439 spi->bits_per_word = dev_read_u32_default(bus,
440 "sifive,max-bits-per-word",
441 SIFIVE_SPI_DEFAULT_BITS);
442
443 ret = clk_get_by_index(bus, 0, &clkdev);
444 if (ret)
445 return ret;
446 spi->freq = clk_get_rate(&clkdev);
447
448 /* init the sifive spi hw */
449 sifive_spi_init_hw(spi);
450
451 return 0;
452}
453
Jagan Teki294b2912020-04-23 22:30:53 +0530454static const struct spi_controller_mem_ops sifive_spi_mem_ops = {
455 .exec_op = sifive_spi_exec_op,
456};
457
Bhargav Shah3c34f752019-07-17 04:23:43 +0000458static const struct dm_spi_ops sifive_spi_ops = {
459 .xfer = sifive_spi_xfer,
460 .set_speed = sifive_spi_set_speed,
461 .set_mode = sifive_spi_set_mode,
462 .cs_info = sifive_spi_cs_info,
Jagan Teki294b2912020-04-23 22:30:53 +0530463 .mem_ops = &sifive_spi_mem_ops,
Bhargav Shah3c34f752019-07-17 04:23:43 +0000464};
465
466static const struct udevice_id sifive_spi_ids[] = {
467 { .compatible = "sifive,spi0" },
468 { }
469};
470
471U_BOOT_DRIVER(sifive_spi) = {
472 .name = "sifive_spi",
473 .id = UCLASS_SPI,
474 .of_match = sifive_spi_ids,
475 .ops = &sifive_spi_ops,
476 .priv_auto_alloc_size = sizeof(struct sifive_spi),
477 .probe = sifive_spi_probe,
478};