arm: layerscape: Add sfp driver
[platform/kernel/u-boot.git] / drivers / spi / spi-synquacer.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * spi-synquacer.c - Socionext Synquacer SPI driver
4  * Copyright 2021 Linaro Ltd.
5  * Copyright 2021 Socionext, Inc.
6  */
7
8 #include <clk.h>
9 #include <common.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <time.h>
13 #include <dm/device_compat.h>
14 #include <linux/bitfield.h>
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
17 #include <linux/io.h>
18 #include <spi.h>
19 #include <wait_bit.h>
20
21 #define MCTRL   0x0
22 #define MEN     0
23 #define CSEN    1
24 #define IPCLK   3
25 #define MES     4
26 #define SYNCON  5
27
28 #define PCC0            0x4
29 #define PCC(n)          (PCC0 + (n) * 4)
30 #define RTM             3
31 #define ACES            2
32 #define SAFESYNC        16
33 #define CPHA            0
34 #define CPOL            1
35 #define SSPOL           4
36 #define SDIR            7
37 #define SS2CD           5
38 #define SENDIAN         8
39 #define CDRS_SHIFT      9
40 #define CDRS_MASK       0x7f
41
42 #define TXF             0x14
43 #define TXE             0x18
44 #define TXC             0x1c
45 #define RXF             0x20
46 #define RXE             0x24
47 #define RXC             0x28
48 #define TFES            1
49 #define TFLETE          4
50 #define TSSRS           6
51 #define RFMTE           5
52 #define RSSRS           6
53
54 #define FAULTF          0x2c
55 #define FAULTC          0x30
56
57 #define DMCFG           0x34
58 #define SSDC            1
59 #define MSTARTEN        2
60
61 #define DMSTART         0x38
62 #define TRIGGER         0
63 #define DMSTOP          8
64 #define CS_MASK         3
65 #define CS_SHIFT        16
66 #define DATA_TXRX       0
67 #define DATA_RX         1
68 #define DATA_TX         2
69 #define DATA_MASK       3
70 #define DATA_SHIFT      26
71 #define BUS_WIDTH       24
72
73 #define DMBCC           0x3c
74 #define DMSTATUS        0x40
75 #define RX_DATA_MASK    0x1f
76 #define RX_DATA_SHIFT   8
77 #define TX_DATA_MASK    0x1f
78 #define TX_DATA_SHIFT   16
79
80 #define TXBITCNT        0x44
81
82 #define FIFOCFG         0x4c
83 #define BPW_MASK        0x3
84 #define BPW_SHIFT       8
85 #define RX_FLUSH        11
86 #define TX_FLUSH        12
87 #define RX_TRSHLD_MASK          0xf
88 #define RX_TRSHLD_SHIFT         0
89 #define TX_TRSHLD_MASK          0xf
90 #define TX_TRSHLD_SHIFT         4
91
92 #define TXFIFO          0x50
93 #define RXFIFO          0x90
94 #define MID             0xfc
95
96 #define FIFO_DEPTH      16
97 #define TX_TRSHLD       4
98 #define RX_TRSHLD       (FIFO_DEPTH - TX_TRSHLD)
99
100 #define TXBIT   1
101 #define RXBIT   2
102
103 DECLARE_GLOBAL_DATA_PTR;
104
105 struct synquacer_spi_plat {
106         void __iomem *base;
107         bool aces, rtm;
108 };
109
110 struct synquacer_spi_priv {
111         void __iomem *base;
112         bool aces, rtm;
113         int speed, cs, mode, rwflag;
114         void *rx_buf;
115         const void *tx_buf;
116         unsigned int tx_words, rx_words;
117 };
118
119 static void read_fifo(struct synquacer_spi_priv *priv)
120 {
121         u32 len = readl(priv->base + DMSTATUS);
122         u8 *buf = priv->rx_buf;
123         int i;
124
125         len = (len >> RX_DATA_SHIFT) & RX_DATA_MASK;
126         len = min_t(unsigned int, len, priv->rx_words);
127
128         for (i = 0; i < len; i++)
129                 *buf++ = readb(priv->base + RXFIFO);
130
131         priv->rx_buf = buf;
132         priv->rx_words -= len;
133 }
134
135 static void write_fifo(struct synquacer_spi_priv *priv)
136 {
137         u32 len = readl(priv->base + DMSTATUS);
138         const u8 *buf = priv->tx_buf;
139         int i;
140
141         len = (len >> TX_DATA_SHIFT) & TX_DATA_MASK;
142         len = min_t(unsigned int, FIFO_DEPTH - len, priv->tx_words);
143
144         for (i = 0; i < len; i++)
145                 writeb(*buf++, priv->base + TXFIFO);
146
147         priv->tx_buf = buf;
148         priv->tx_words -= len;
149 }
150
151 static void synquacer_cs_set(struct synquacer_spi_priv *priv, bool active)
152 {
153         u32 val;
154
155         val = readl(priv->base + DMSTART);
156         val &= ~(CS_MASK << CS_SHIFT);
157         val |= priv->cs << CS_SHIFT;
158
159         if (active) {
160                 writel(val, priv->base + DMSTART);
161
162                 val = readl(priv->base + DMSTART);
163                 val &= ~BIT(DMSTOP);
164                 writel(val, priv->base + DMSTART);
165         } else {
166                 val |= BIT(DMSTOP);
167                 writel(val, priv->base + DMSTART);
168
169                 if (priv->rx_buf) {
170                         u32 buf[16];
171
172                         priv->rx_buf = buf;
173                         priv->rx_words = 16;
174                         read_fifo(priv);
175                 }
176
177                 /* wait until slave is deselected */
178                 while (!(readl(priv->base + TXF) & BIT(TSSRS)) ||
179                        !(readl(priv->base + RXF) & BIT(RSSRS)))
180                         ;
181         }
182 }
183
184 static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
185 {
186         struct udevice *bus = dev->parent;
187         struct synquacer_spi_priv *priv = dev_get_priv(bus);
188         struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
189         u32 val, div, bus_width;
190         int rwflag;
191
192         rwflag = (rx ? 1 : 0) | (tx ? 2 : 0);
193
194         /* if nothing to do */
195         if (slave_plat->mode == priv->mode &&
196             rwflag == priv->rwflag &&
197             slave_plat->cs == priv->cs &&
198             slave_plat->max_hz == priv->speed)
199                 return;
200
201         priv->rwflag = rwflag;
202         priv->cs = slave_plat->cs;
203         priv->mode = slave_plat->mode;
204         priv->speed = slave_plat->max_hz;
205
206         if (priv->mode & SPI_TX_BYTE)
207                 bus_width = 1;
208         else if (priv->mode & SPI_TX_DUAL)
209                 bus_width = 2;
210         else if (priv->mode & SPI_TX_QUAD)
211                 bus_width = 4;
212         else if (priv->mode & SPI_TX_OCTAL)
213                 bus_width = 8;
214
215         div = DIV_ROUND_UP(125000000, priv->speed);
216
217         val = readl(priv->base + PCC(priv->cs));
218         val &= ~BIT(RTM);
219         val &= ~BIT(ACES);
220         val &= ~BIT(SAFESYNC);
221         if ((priv->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3)
222                 val |= BIT(SAFESYNC);
223         if ((priv->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6)
224                 val |= BIT(SAFESYNC);
225
226         if (priv->mode & SPI_CPHA)
227                 val |= BIT(CPHA);
228         else
229                 val &= ~BIT(CPHA);
230
231         if (priv->mode & SPI_CPOL)
232                 val |= BIT(CPOL);
233         else
234                 val &= ~BIT(CPOL);
235
236         if (priv->mode & SPI_CS_HIGH)
237                 val |= BIT(SSPOL);
238         else
239                 val &= ~BIT(SSPOL);
240
241         if (priv->mode & SPI_LSB_FIRST)
242                 val |= BIT(SDIR);
243         else
244                 val &= ~BIT(SDIR);
245
246         if (priv->aces)
247                 val |= BIT(ACES);
248
249         if (priv->rtm)
250                 val |= BIT(RTM);
251
252         val |= (3 << SS2CD);
253         val |= BIT(SENDIAN);
254
255         val &= ~(CDRS_MASK << CDRS_SHIFT);
256         val |= ((div >> 1) << CDRS_SHIFT);
257
258         writel(val, priv->base + PCC(priv->cs));
259
260         val = readl(priv->base + FIFOCFG);
261         val &= ~(BPW_MASK << BPW_SHIFT);
262         val |= (0 << BPW_SHIFT);
263         writel(val, priv->base + FIFOCFG);
264
265         val = readl(priv->base + DMSTART);
266         val &= ~(DATA_MASK << DATA_SHIFT);
267
268         if (tx && rx)
269                 val |= (DATA_TXRX << DATA_SHIFT);
270         else if (rx)
271                 val |= (DATA_RX << DATA_SHIFT);
272         else
273                 val |= (DATA_TX << DATA_SHIFT);
274
275         val &= ~(3 << BUS_WIDTH);
276         val |= ((bus_width >> 1) << BUS_WIDTH);
277         writel(val, priv->base + DMSTART);
278 }
279
280 static int synquacer_spi_xfer(struct udevice *dev, unsigned int bitlen,
281                               const void *tx_buf, void *rx_buf,
282                               unsigned long flags)
283 {
284         struct udevice *bus = dev->parent;
285         struct synquacer_spi_priv *priv = dev_get_priv(bus);
286         u32 val, words, busy = 0;
287
288         val = readl(priv->base + FIFOCFG);
289         val |= (1 << RX_FLUSH);
290         val |= (1 << TX_FLUSH);
291         writel(val, priv->base + FIFOCFG);
292
293         synquacer_spi_config(dev, rx_buf, tx_buf);
294
295         priv->tx_buf = tx_buf;
296         priv->rx_buf = rx_buf;
297
298         words = bitlen / 8;
299
300         if (tx_buf) {
301                 busy |= BIT(TXBIT);
302                 priv->tx_words = words;
303         } else {
304                 busy &= ~BIT(TXBIT);
305                 priv->tx_words = 0;
306         }
307
308         if (rx_buf) {
309                 busy |= BIT(RXBIT);
310                 priv->rx_words = words;
311         } else {
312                 busy &= ~BIT(RXBIT);
313                 priv->rx_words = 0;
314         }
315
316         if (flags & SPI_XFER_BEGIN)
317                 synquacer_cs_set(priv, true);
318
319         if (tx_buf)
320                 write_fifo(priv);
321
322         if (rx_buf) {
323                 val = readl(priv->base + FIFOCFG);
324                 val &= ~(RX_TRSHLD_MASK << RX_TRSHLD_SHIFT);
325                 val |= ((priv->rx_words > FIFO_DEPTH ?
326                         RX_TRSHLD : priv->rx_words) << RX_TRSHLD_SHIFT);
327                 writel(val, priv->base + FIFOCFG);
328         }
329
330         writel(~0, priv->base + TXC);
331         writel(~0, priv->base + RXC);
332
333         /* Trigger */
334         if (flags & SPI_XFER_BEGIN) {
335                 val = readl(priv->base + DMSTART);
336                 val |= BIT(TRIGGER);
337                 writel(val, priv->base + DMSTART);
338         }
339
340         while (busy & (BIT(RXBIT) | BIT(TXBIT))) {
341                 if (priv->rx_words)
342                         read_fifo(priv);
343                 else
344                         busy &= ~BIT(RXBIT);
345
346                 if (priv->tx_words) {
347                         write_fifo(priv);
348                 } else {
349                         /* wait for shifter to empty out */
350                         while (!(readl(priv->base + TXF) & BIT(TFES)))
351                                 cpu_relax();
352
353                         busy &= ~BIT(TXBIT);
354                 }
355         }
356
357         if (flags & SPI_XFER_END)
358                 synquacer_cs_set(priv, false);
359
360         return 0;
361 }
362
363 static int synquacer_spi_set_speed(struct udevice *bus, uint speed)
364 {
365         return 0;
366 }
367
368 static int synquacer_spi_set_mode(struct udevice *bus, uint mode)
369 {
370         return 0;
371 }
372
373 static int synquacer_spi_claim_bus(struct udevice *dev)
374 {
375         return 0;
376 }
377
378 static int synquacer_spi_release_bus(struct udevice *dev)
379 {
380         return 0;
381 }
382
383 static void synquacer_spi_disable_module(struct synquacer_spi_priv *priv)
384 {
385         writel(0, priv->base + MCTRL);
386         while (readl(priv->base + MCTRL) & BIT(MES))
387                 cpu_relax();
388 }
389
390 static void synquacer_spi_init(struct synquacer_spi_priv *priv)
391 {
392         u32 val;
393
394         synquacer_spi_disable_module(priv);
395
396         writel(0, priv->base + TXE);
397         writel(0, priv->base + RXE);
398         val = readl(priv->base + TXF);
399         writel(val, priv->base + TXC);
400         val = readl(priv->base + RXF);
401         writel(val, priv->base + RXC);
402         val = readl(priv->base + FAULTF);
403         writel(val, priv->base + FAULTC);
404
405         val = readl(priv->base + DMCFG);
406         val &= ~BIT(SSDC);
407         val &= ~BIT(MSTARTEN);
408         writel(val, priv->base + DMCFG);
409
410         /* Enable module with direct mode */
411         val = readl(priv->base + MCTRL);
412         val &= ~BIT(IPCLK);
413         val &= ~BIT(CSEN);
414         val |= BIT(MEN);
415         val |= BIT(SYNCON);
416         writel(val, priv->base + MCTRL);
417 }
418
419 static void synquacer_spi_exit(struct synquacer_spi_priv *priv)
420 {
421         u32 val;
422
423         synquacer_spi_disable_module(priv);
424
425         /* Enable module with command sequence mode */
426         val = readl(priv->base + MCTRL);
427         val &= ~BIT(IPCLK);
428         val |= BIT(CSEN);
429         val |= BIT(MEN);
430         val |= BIT(SYNCON);
431         writel(val, priv->base + MCTRL);
432
433         while (!(readl(priv->base + MCTRL) & BIT(MES)))
434                 cpu_relax();
435 }
436
437 static int synquacer_spi_probe(struct udevice *bus)
438 {
439         struct synquacer_spi_plat *plat = dev_get_plat(bus);
440         struct synquacer_spi_priv *priv = dev_get_priv(bus);
441
442         priv->base = plat->base;
443         priv->aces = plat->aces;
444         priv->rtm = plat->rtm;
445
446         synquacer_spi_init(priv);
447         return 0;
448 }
449
450 static int synquacer_spi_remove(struct udevice *bus)
451 {
452         struct synquacer_spi_priv *priv = dev_get_priv(bus);
453
454         synquacer_spi_exit(priv);
455         return 0;
456 }
457
458 static int synquacer_spi_of_to_plat(struct udevice *bus)
459 {
460         struct synquacer_spi_plat *plat = dev_get_plat(bus);
461         struct clk clk;
462
463         plat->base = dev_read_addr_ptr(bus);
464
465         plat->aces = dev_read_bool(bus, "socionext,set-aces");
466         plat->rtm = dev_read_bool(bus, "socionext,use-rtm");
467
468         clk_get_by_name(bus, "iHCLK", &clk);
469         clk_enable(&clk);
470
471         return 0;
472 }
473
474 static const struct dm_spi_ops synquacer_spi_ops = {
475         .claim_bus      = synquacer_spi_claim_bus,
476         .release_bus    = synquacer_spi_release_bus,
477         .xfer           = synquacer_spi_xfer,
478         .set_speed      = synquacer_spi_set_speed,
479         .set_mode       = synquacer_spi_set_mode,
480 };
481
482 static const struct udevice_id synquacer_spi_ids[] = {
483         { .compatible = "socionext,synquacer-spi" },
484         { /* Sentinel */ }
485 };
486
487 U_BOOT_DRIVER(synquacer_spi) = {
488         .name           = "synquacer_spi",
489         .id             = UCLASS_SPI,
490         .of_match       = synquacer_spi_ids,
491         .ops            = &synquacer_spi_ops,
492         .of_to_plat     = synquacer_spi_of_to_plat,
493         .plat_auto      = sizeof(struct synquacer_spi_plat),
494         .priv_auto      = sizeof(struct synquacer_spi_priv),
495         .probe          = synquacer_spi_probe,
496         .flags          = DM_FLAG_OS_PREPARE,
497         .remove         = synquacer_spi_remove,
498 };