1 // SPDX-License-Identifier: GPL-2.0+
3 * spi-synquacer.c - Socionext Synquacer SPI driver
4 * Copyright 2021 Linaro Ltd.
5 * Copyright 2021 Socionext, Inc.
13 #include <dm/device_compat.h>
14 #include <linux/bitfield.h>
15 #include <linux/bitops.h>
16 #include <linux/delay.h>
29 #define PCC(n) (PCC0 + (n) * 4)
40 #define CDRS_MASK 0x7f
75 #define RX_DATA_MASK 0x1f
76 #define RX_DATA_SHIFT 8
77 #define TX_DATA_MASK 0x1f
78 #define TX_DATA_SHIFT 16
87 #define RX_TRSHLD_MASK 0xf
88 #define RX_TRSHLD_SHIFT 0
89 #define TX_TRSHLD_MASK 0xf
90 #define TX_TRSHLD_SHIFT 4
98 #define RX_TRSHLD (FIFO_DEPTH - TX_TRSHLD)
103 DECLARE_GLOBAL_DATA_PTR;
105 struct synquacer_spi_plat {
110 struct synquacer_spi_priv {
113 int speed, cs, mode, rwflag;
116 unsigned int tx_words, rx_words;
119 static void read_fifo(struct synquacer_spi_priv *priv)
121 u32 len = readl(priv->base + DMSTATUS);
122 u8 *buf = priv->rx_buf;
125 len = (len >> RX_DATA_SHIFT) & RX_DATA_MASK;
126 len = min_t(unsigned int, len, priv->rx_words);
128 for (i = 0; i < len; i++)
129 *buf++ = readb(priv->base + RXFIFO);
132 priv->rx_words -= len;
135 static void write_fifo(struct synquacer_spi_priv *priv)
137 u32 len = readl(priv->base + DMSTATUS);
138 const u8 *buf = priv->tx_buf;
141 len = (len >> TX_DATA_SHIFT) & TX_DATA_MASK;
142 len = min_t(unsigned int, FIFO_DEPTH - len, priv->tx_words);
144 for (i = 0; i < len; i++)
145 writeb(*buf++, priv->base + TXFIFO);
148 priv->tx_words -= len;
151 static void synquacer_cs_set(struct synquacer_spi_priv *priv, bool active)
155 val = readl(priv->base + DMSTART);
156 val &= ~(CS_MASK << CS_SHIFT);
157 val |= priv->cs << CS_SHIFT;
160 writel(val, priv->base + DMSTART);
162 val = readl(priv->base + DMSTART);
164 writel(val, priv->base + DMSTART);
167 writel(val, priv->base + DMSTART);
177 /* wait until slave is deselected */
178 while (!(readl(priv->base + TXF) & BIT(TSSRS)) ||
179 !(readl(priv->base + RXF) & BIT(RSSRS)))
184 static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx)
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;
192 rwflag = (rx ? 1 : 0) | (tx ? 2 : 0);
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)
201 priv->rwflag = rwflag;
202 priv->cs = slave_plat->cs;
203 priv->mode = slave_plat->mode;
204 priv->speed = slave_plat->max_hz;
206 if (priv->mode & SPI_TX_BYTE)
208 else if (priv->mode & SPI_TX_DUAL)
210 else if (priv->mode & SPI_TX_QUAD)
212 else if (priv->mode & SPI_TX_OCTAL)
215 div = DIV_ROUND_UP(125000000, priv->speed);
217 val = readl(priv->base + PCC(priv->cs));
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);
226 if (priv->mode & SPI_CPHA)
231 if (priv->mode & SPI_CPOL)
236 if (priv->mode & SPI_CS_HIGH)
241 if (priv->mode & SPI_LSB_FIRST)
255 val &= ~(CDRS_MASK << CDRS_SHIFT);
256 val |= ((div >> 1) << CDRS_SHIFT);
258 writel(val, priv->base + PCC(priv->cs));
260 val = readl(priv->base + FIFOCFG);
261 val &= ~(BPW_MASK << BPW_SHIFT);
262 val |= (0 << BPW_SHIFT);
263 writel(val, priv->base + FIFOCFG);
265 val = readl(priv->base + DMSTART);
266 val &= ~(DATA_MASK << DATA_SHIFT);
269 val |= (DATA_TXRX << DATA_SHIFT);
271 val |= (DATA_RX << DATA_SHIFT);
273 val |= (DATA_TX << DATA_SHIFT);
275 val &= ~(3 << BUS_WIDTH);
276 val |= ((bus_width >> 1) << BUS_WIDTH);
277 writel(val, priv->base + DMSTART);
280 static int synquacer_spi_xfer(struct udevice *dev, unsigned int bitlen,
281 const void *tx_buf, void *rx_buf,
284 struct udevice *bus = dev->parent;
285 struct synquacer_spi_priv *priv = dev_get_priv(bus);
286 u32 val, words, busy = 0;
288 val = readl(priv->base + FIFOCFG);
289 val |= (1 << RX_FLUSH);
290 val |= (1 << TX_FLUSH);
291 writel(val, priv->base + FIFOCFG);
293 synquacer_spi_config(dev, rx_buf, tx_buf);
295 priv->tx_buf = tx_buf;
296 priv->rx_buf = rx_buf;
302 priv->tx_words = words;
310 priv->rx_words = words;
316 if (flags & SPI_XFER_BEGIN)
317 synquacer_cs_set(priv, true);
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);
330 writel(~0, priv->base + TXC);
331 writel(~0, priv->base + RXC);
334 if (flags & SPI_XFER_BEGIN) {
335 val = readl(priv->base + DMSTART);
337 writel(val, priv->base + DMSTART);
340 while (busy & (BIT(RXBIT) | BIT(TXBIT))) {
346 if (priv->tx_words) {
349 /* wait for shifter to empty out */
350 while (!(readl(priv->base + TXF) & BIT(TFES)))
357 if (flags & SPI_XFER_END)
358 synquacer_cs_set(priv, false);
363 static int synquacer_spi_set_speed(struct udevice *bus, uint speed)
368 static int synquacer_spi_set_mode(struct udevice *bus, uint mode)
373 static int synquacer_spi_claim_bus(struct udevice *dev)
378 static int synquacer_spi_release_bus(struct udevice *dev)
383 static void synquacer_spi_disable_module(struct synquacer_spi_priv *priv)
385 writel(0, priv->base + MCTRL);
386 while (readl(priv->base + MCTRL) & BIT(MES))
390 static void synquacer_spi_init(struct synquacer_spi_priv *priv)
394 synquacer_spi_disable_module(priv);
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);
405 val = readl(priv->base + DMCFG);
407 val &= ~BIT(MSTARTEN);
408 writel(val, priv->base + DMCFG);
410 /* Enable module with direct mode */
411 val = readl(priv->base + MCTRL);
416 writel(val, priv->base + MCTRL);
419 static void synquacer_spi_exit(struct synquacer_spi_priv *priv)
423 synquacer_spi_disable_module(priv);
425 /* Enable module with command sequence mode */
426 val = readl(priv->base + MCTRL);
431 writel(val, priv->base + MCTRL);
433 while (!(readl(priv->base + MCTRL) & BIT(MES)))
437 static int synquacer_spi_probe(struct udevice *bus)
439 struct synquacer_spi_plat *plat = dev_get_plat(bus);
440 struct synquacer_spi_priv *priv = dev_get_priv(bus);
442 priv->base = plat->base;
443 priv->aces = plat->aces;
444 priv->rtm = plat->rtm;
446 synquacer_spi_init(priv);
450 static int synquacer_spi_remove(struct udevice *bus)
452 struct synquacer_spi_priv *priv = dev_get_priv(bus);
454 synquacer_spi_exit(priv);
458 static int synquacer_spi_of_to_plat(struct udevice *bus)
460 struct synquacer_spi_plat *plat = dev_get_plat(bus);
463 plat->base = dev_read_addr_ptr(bus);
465 plat->aces = dev_read_bool(bus, "socionext,set-aces");
466 plat->rtm = dev_read_bool(bus, "socionext,use-rtm");
468 clk_get_by_name(bus, "iHCLK", &clk);
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,
482 static const struct udevice_id synquacer_spi_ids[] = {
483 { .compatible = "socionext,synquacer-spi" },
487 U_BOOT_DRIVER(synquacer_spi) = {
488 .name = "synquacer_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,