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