13fda4ef3SStefan Roese /*
23fda4ef3SStefan Roese * Copyright (C) 2015 Marvell International Ltd.
33fda4ef3SStefan Roese *
43fda4ef3SStefan Roese * Copyright (C) 2016 Stefan Roese <sr@denx.de>
53fda4ef3SStefan Roese *
63fda4ef3SStefan Roese * SPDX-License-Identifier: GPL-2.0+
73fda4ef3SStefan Roese */
83fda4ef3SStefan Roese
93fda4ef3SStefan Roese #include <common.h>
103fda4ef3SStefan Roese #include <dm.h>
113fda4ef3SStefan Roese #include <malloc.h>
123fda4ef3SStefan Roese #include <spi.h>
133fda4ef3SStefan Roese #include <wait_bit.h>
143fda4ef3SStefan Roese #include <asm/io.h>
153fda4ef3SStefan Roese
163fda4ef3SStefan Roese DECLARE_GLOBAL_DATA_PTR;
173fda4ef3SStefan Roese
183fda4ef3SStefan Roese #define MVEBU_SPI_A3700_XFER_RDY BIT(1)
193fda4ef3SStefan Roese #define MVEBU_SPI_A3700_FIFO_FLUSH BIT(9)
203fda4ef3SStefan Roese #define MVEBU_SPI_A3700_BYTE_LEN BIT(5)
213fda4ef3SStefan Roese #define MVEBU_SPI_A3700_CLK_PHA BIT(6)
223fda4ef3SStefan Roese #define MVEBU_SPI_A3700_CLK_POL BIT(7)
233fda4ef3SStefan Roese #define MVEBU_SPI_A3700_FIFO_EN BIT(17)
243fda4ef3SStefan Roese #define MVEBU_SPI_A3700_SPI_EN_0 BIT(16)
253fda4ef3SStefan Roese #define MVEBU_SPI_A3700_CLK_PRESCALE_BIT 0
263fda4ef3SStefan Roese #define MVEBU_SPI_A3700_CLK_PRESCALE_MASK \
273fda4ef3SStefan Roese (0x1f << MVEBU_SPI_A3700_CLK_PRESCALE_BIT)
283fda4ef3SStefan Roese
293fda4ef3SStefan Roese /* SPI registers */
303fda4ef3SStefan Roese struct spi_reg {
313fda4ef3SStefan Roese u32 ctrl; /* 0x10600 */
323fda4ef3SStefan Roese u32 cfg; /* 0x10604 */
333fda4ef3SStefan Roese u32 dout; /* 0x10608 */
343fda4ef3SStefan Roese u32 din; /* 0x1060c */
353fda4ef3SStefan Roese };
363fda4ef3SStefan Roese
373fda4ef3SStefan Roese struct mvebu_spi_platdata {
383fda4ef3SStefan Roese struct spi_reg *spireg;
393fda4ef3SStefan Roese unsigned int frequency;
403fda4ef3SStefan Roese unsigned int clock;
413fda4ef3SStefan Roese };
423fda4ef3SStefan Roese
spi_cs_activate(struct spi_reg * reg,int cs)433fda4ef3SStefan Roese static void spi_cs_activate(struct spi_reg *reg, int cs)
443fda4ef3SStefan Roese {
453fda4ef3SStefan Roese setbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
463fda4ef3SStefan Roese }
473fda4ef3SStefan Roese
spi_cs_deactivate(struct spi_reg * reg,int cs)483fda4ef3SStefan Roese static void spi_cs_deactivate(struct spi_reg *reg, int cs)
493fda4ef3SStefan Roese {
503fda4ef3SStefan Roese clrbits_le32(®->ctrl, MVEBU_SPI_A3700_SPI_EN_0 << cs);
513fda4ef3SStefan Roese }
523fda4ef3SStefan Roese
533fda4ef3SStefan Roese /**
543fda4ef3SStefan Roese * spi_legacy_shift_byte() - triggers the real SPI transfer
553fda4ef3SStefan Roese * @bytelen: Indicate how many bytes to transfer.
563fda4ef3SStefan Roese * @dout: Buffer address of what to send.
573fda4ef3SStefan Roese * @din: Buffer address of where to receive.
583fda4ef3SStefan Roese *
593fda4ef3SStefan Roese * This function triggers the real SPI transfer in legacy mode. It
603fda4ef3SStefan Roese * will shift out char buffer from @dout, and shift in char buffer to
613fda4ef3SStefan Roese * @din, if necessary.
623fda4ef3SStefan Roese *
633fda4ef3SStefan Roese * This function assumes that only one byte is shifted at one time.
643fda4ef3SStefan Roese * However, it is not its responisbility to set the transfer type to
653fda4ef3SStefan Roese * one-byte. Also, it does not guarantee that it will work if transfer
663fda4ef3SStefan Roese * type becomes two-byte. See spi_set_legacy() for details.
673fda4ef3SStefan Roese *
683fda4ef3SStefan Roese * In legacy mode, simply write to the SPI_DOUT register will trigger
693fda4ef3SStefan Roese * the transfer.
703fda4ef3SStefan Roese *
713fda4ef3SStefan Roese * If @dout == NULL, which means no actual data needs to be sent out,
723fda4ef3SStefan Roese * then the function will shift out 0x00 in order to shift in data.
733fda4ef3SStefan Roese * The XFER_RDY flag is checked every time before accessing SPI_DOUT
743fda4ef3SStefan Roese * and SPI_DIN register.
753fda4ef3SStefan Roese *
763fda4ef3SStefan Roese * The number of transfers to be triggerred is decided by @bytelen.
773fda4ef3SStefan Roese *
783fda4ef3SStefan Roese * Return: 0 - cool
793fda4ef3SStefan Roese * -ETIMEDOUT - XFER_RDY flag timeout
803fda4ef3SStefan Roese */
spi_legacy_shift_byte(struct spi_reg * reg,unsigned int bytelen,const void * dout,void * din)813fda4ef3SStefan Roese static int spi_legacy_shift_byte(struct spi_reg *reg, unsigned int bytelen,
823fda4ef3SStefan Roese const void *dout, void *din)
833fda4ef3SStefan Roese {
843fda4ef3SStefan Roese const u8 *dout_8;
853fda4ef3SStefan Roese u8 *din_8;
863fda4ef3SStefan Roese int ret;
873fda4ef3SStefan Roese
883fda4ef3SStefan Roese /* Use 0x00 as dummy dout */
893fda4ef3SStefan Roese const u8 dummy_dout = 0x0;
903fda4ef3SStefan Roese u32 pending_dout = 0x0;
913fda4ef3SStefan Roese
923fda4ef3SStefan Roese /* dout_8: pointer of current dout */
933fda4ef3SStefan Roese dout_8 = dout;
943fda4ef3SStefan Roese /* din_8: pointer of current din */
953fda4ef3SStefan Roese din_8 = din;
963fda4ef3SStefan Roese
973fda4ef3SStefan Roese while (bytelen) {
98*b491b498SJon Lin ret = wait_for_bit_le32(®->ctrl,
99*b491b498SJon Lin MVEBU_SPI_A3700_XFER_RDY,
100*b491b498SJon Lin true,100, false);
1013fda4ef3SStefan Roese if (ret)
1023fda4ef3SStefan Roese return ret;
1033fda4ef3SStefan Roese
1043fda4ef3SStefan Roese if (dout)
1053fda4ef3SStefan Roese pending_dout = (u32)*dout_8;
1063fda4ef3SStefan Roese else
1073fda4ef3SStefan Roese pending_dout = (u32)dummy_dout;
1083fda4ef3SStefan Roese
1093fda4ef3SStefan Roese /* Trigger the xfer */
1103fda4ef3SStefan Roese writel(pending_dout, ®->dout);
1113fda4ef3SStefan Roese
1123fda4ef3SStefan Roese if (din) {
113*b491b498SJon Lin ret = wait_for_bit_le32(®->ctrl,
1143fda4ef3SStefan Roese MVEBU_SPI_A3700_XFER_RDY,
1153fda4ef3SStefan Roese true, 100, false);
1163fda4ef3SStefan Roese if (ret)
1173fda4ef3SStefan Roese return ret;
1183fda4ef3SStefan Roese
1193fda4ef3SStefan Roese /* Read what is transferred in */
1203fda4ef3SStefan Roese *din_8 = (u8)readl(®->din);
1213fda4ef3SStefan Roese }
1223fda4ef3SStefan Roese
1233fda4ef3SStefan Roese /* Don't increment the current pointer if NULL */
1243fda4ef3SStefan Roese if (dout)
1253fda4ef3SStefan Roese dout_8++;
1263fda4ef3SStefan Roese if (din)
1273fda4ef3SStefan Roese din_8++;
1283fda4ef3SStefan Roese
1293fda4ef3SStefan Roese bytelen--;
1303fda4ef3SStefan Roese }
1313fda4ef3SStefan Roese
1323fda4ef3SStefan Roese return 0;
1333fda4ef3SStefan Roese }
1343fda4ef3SStefan Roese
mvebu_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)1353fda4ef3SStefan Roese static int mvebu_spi_xfer(struct udevice *dev, unsigned int bitlen,
1363fda4ef3SStefan Roese const void *dout, void *din, unsigned long flags)
1373fda4ef3SStefan Roese {
1383fda4ef3SStefan Roese struct udevice *bus = dev->parent;
1393fda4ef3SStefan Roese struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
1403fda4ef3SStefan Roese struct spi_reg *reg = plat->spireg;
1413fda4ef3SStefan Roese unsigned int bytelen;
1423fda4ef3SStefan Roese int ret;
1433fda4ef3SStefan Roese
1443fda4ef3SStefan Roese bytelen = bitlen / 8;
1453fda4ef3SStefan Roese
1463fda4ef3SStefan Roese if (dout && din)
1473fda4ef3SStefan Roese debug("This is a duplex transfer.\n");
1483fda4ef3SStefan Roese
1493fda4ef3SStefan Roese /* Activate CS */
1503fda4ef3SStefan Roese if (flags & SPI_XFER_BEGIN) {
1513fda4ef3SStefan Roese debug("SPI: activate cs.\n");
1523fda4ef3SStefan Roese spi_cs_activate(reg, spi_chip_select(dev));
1533fda4ef3SStefan Roese }
1543fda4ef3SStefan Roese
1553fda4ef3SStefan Roese /* Send and/or receive */
1563fda4ef3SStefan Roese if (dout || din) {
1573fda4ef3SStefan Roese ret = spi_legacy_shift_byte(reg, bytelen, dout, din);
1583fda4ef3SStefan Roese if (ret)
1593fda4ef3SStefan Roese return ret;
1603fda4ef3SStefan Roese }
1613fda4ef3SStefan Roese
1623fda4ef3SStefan Roese /* Deactivate CS */
1633fda4ef3SStefan Roese if (flags & SPI_XFER_END) {
164*b491b498SJon Lin ret = wait_for_bit_le32(®->ctrl,
165*b491b498SJon Lin MVEBU_SPI_A3700_XFER_RDY,
166*b491b498SJon Lin true, 100, false);
1673fda4ef3SStefan Roese if (ret)
1683fda4ef3SStefan Roese return ret;
1693fda4ef3SStefan Roese
1703fda4ef3SStefan Roese debug("SPI: deactivate cs.\n");
1713fda4ef3SStefan Roese spi_cs_deactivate(reg, spi_chip_select(dev));
1723fda4ef3SStefan Roese }
1733fda4ef3SStefan Roese
1743fda4ef3SStefan Roese return 0;
1753fda4ef3SStefan Roese }
1763fda4ef3SStefan Roese
mvebu_spi_set_speed(struct udevice * bus,uint hz)1773fda4ef3SStefan Roese static int mvebu_spi_set_speed(struct udevice *bus, uint hz)
1783fda4ef3SStefan Roese {
1793fda4ef3SStefan Roese struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
1803fda4ef3SStefan Roese struct spi_reg *reg = plat->spireg;
1813fda4ef3SStefan Roese u32 data;
1823fda4ef3SStefan Roese
1833fda4ef3SStefan Roese data = readl(®->cfg);
1843fda4ef3SStefan Roese
1853fda4ef3SStefan Roese /* Set Prescaler */
1863fda4ef3SStefan Roese data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK;
1873fda4ef3SStefan Roese
1883fda4ef3SStefan Roese /* Calculate Prescaler = (spi_input_freq / spi_max_freq) */
1893fda4ef3SStefan Roese if (hz > plat->frequency)
1903fda4ef3SStefan Roese hz = plat->frequency;
1913fda4ef3SStefan Roese data |= plat->clock / hz;
1923fda4ef3SStefan Roese
1933fda4ef3SStefan Roese writel(data, ®->cfg);
1943fda4ef3SStefan Roese
1953fda4ef3SStefan Roese return 0;
1963fda4ef3SStefan Roese }
1973fda4ef3SStefan Roese
mvebu_spi_set_mode(struct udevice * bus,uint mode)1983fda4ef3SStefan Roese static int mvebu_spi_set_mode(struct udevice *bus, uint mode)
1993fda4ef3SStefan Roese {
2003fda4ef3SStefan Roese struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
2013fda4ef3SStefan Roese struct spi_reg *reg = plat->spireg;
2023fda4ef3SStefan Roese
2033fda4ef3SStefan Roese /*
2043fda4ef3SStefan Roese * Set SPI polarity
2053fda4ef3SStefan Roese * 0: Serial interface clock is low when inactive
2063fda4ef3SStefan Roese * 1: Serial interface clock is high when inactive
2073fda4ef3SStefan Roese */
2083fda4ef3SStefan Roese if (mode & SPI_CPOL)
2093fda4ef3SStefan Roese setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL);
2103fda4ef3SStefan Roese else
2113fda4ef3SStefan Roese clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_POL);
2123fda4ef3SStefan Roese if (mode & SPI_CPHA)
2133fda4ef3SStefan Roese setbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA);
2143fda4ef3SStefan Roese else
2153fda4ef3SStefan Roese clrbits_le32(®->cfg, MVEBU_SPI_A3700_CLK_PHA);
2163fda4ef3SStefan Roese
2173fda4ef3SStefan Roese return 0;
2183fda4ef3SStefan Roese }
2193fda4ef3SStefan Roese
mvebu_spi_probe(struct udevice * bus)2203fda4ef3SStefan Roese static int mvebu_spi_probe(struct udevice *bus)
2213fda4ef3SStefan Roese {
2223fda4ef3SStefan Roese struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
2233fda4ef3SStefan Roese struct spi_reg *reg = plat->spireg;
2243fda4ef3SStefan Roese u32 data;
2253fda4ef3SStefan Roese int ret;
2263fda4ef3SStefan Roese
2273fda4ef3SStefan Roese /*
2283fda4ef3SStefan Roese * Settings SPI controller to be working in legacy mode, which
2293fda4ef3SStefan Roese * means use only DO pin (I/O 1) for Data Out, and DI pin (I/O 0)
2303fda4ef3SStefan Roese * for Data In.
2313fda4ef3SStefan Roese */
2323fda4ef3SStefan Roese
2333fda4ef3SStefan Roese /* Flush read/write FIFO */
2343fda4ef3SStefan Roese data = readl(®->cfg);
2353fda4ef3SStefan Roese writel(data | MVEBU_SPI_A3700_FIFO_FLUSH, ®->cfg);
236*b491b498SJon Lin ret = wait_for_bit_le32(®->cfg, MVEBU_SPI_A3700_FIFO_FLUSH,
2373fda4ef3SStefan Roese false, 1000, false);
2383fda4ef3SStefan Roese if (ret)
2393fda4ef3SStefan Roese return ret;
2403fda4ef3SStefan Roese
2413fda4ef3SStefan Roese /* Disable FIFO mode */
2423fda4ef3SStefan Roese data &= ~MVEBU_SPI_A3700_FIFO_EN;
2433fda4ef3SStefan Roese
2443fda4ef3SStefan Roese /* Always shift 1 byte at a time */
2453fda4ef3SStefan Roese data &= ~MVEBU_SPI_A3700_BYTE_LEN;
2463fda4ef3SStefan Roese
2473fda4ef3SStefan Roese writel(data, ®->cfg);
2483fda4ef3SStefan Roese
2493fda4ef3SStefan Roese return 0;
2503fda4ef3SStefan Roese }
2513fda4ef3SStefan Roese
mvebu_spi_ofdata_to_platdata(struct udevice * bus)2523fda4ef3SStefan Roese static int mvebu_spi_ofdata_to_platdata(struct udevice *bus)
2533fda4ef3SStefan Roese {
2543fda4ef3SStefan Roese struct mvebu_spi_platdata *plat = dev_get_platdata(bus);
2553fda4ef3SStefan Roese
256a821c4afSSimon Glass plat->spireg = (struct spi_reg *)devfdt_get_addr(bus);
2573fda4ef3SStefan Roese
2583fda4ef3SStefan Roese /*
2593fda4ef3SStefan Roese * FIXME
2603fda4ef3SStefan Roese * Right now, mvebu does not have a clock infrastructure in U-Boot
2613fda4ef3SStefan Roese * which should be used to query the input clock to the SPI
2623fda4ef3SStefan Roese * controller. Once this clock driver is integrated into U-Boot
2633fda4ef3SStefan Roese * it should be used to read the input clock and the DT property
2643fda4ef3SStefan Roese * can be removed.
2653fda4ef3SStefan Roese */
266e160f7d4SSimon Glass plat->clock = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
2673fda4ef3SStefan Roese "clock-frequency", 160000);
268e160f7d4SSimon Glass plat->frequency = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus),
2693fda4ef3SStefan Roese "spi-max-frequency", 40000);
2703fda4ef3SStefan Roese
2713fda4ef3SStefan Roese return 0;
2723fda4ef3SStefan Roese }
2733fda4ef3SStefan Roese
2743fda4ef3SStefan Roese static const struct dm_spi_ops mvebu_spi_ops = {
2753fda4ef3SStefan Roese .xfer = mvebu_spi_xfer,
2763fda4ef3SStefan Roese .set_speed = mvebu_spi_set_speed,
2773fda4ef3SStefan Roese .set_mode = mvebu_spi_set_mode,
2783fda4ef3SStefan Roese /*
2793fda4ef3SStefan Roese * cs_info is not needed, since we require all chip selects to be
2803fda4ef3SStefan Roese * in the device tree explicitly
2813fda4ef3SStefan Roese */
2823fda4ef3SStefan Roese };
2833fda4ef3SStefan Roese
2843fda4ef3SStefan Roese static const struct udevice_id mvebu_spi_ids[] = {
2853fda4ef3SStefan Roese { .compatible = "marvell,armada-3700-spi" },
2863fda4ef3SStefan Roese { }
2873fda4ef3SStefan Roese };
2883fda4ef3SStefan Roese
2893fda4ef3SStefan Roese U_BOOT_DRIVER(mvebu_spi) = {
2903fda4ef3SStefan Roese .name = "mvebu_spi",
2913fda4ef3SStefan Roese .id = UCLASS_SPI,
2923fda4ef3SStefan Roese .of_match = mvebu_spi_ids,
2933fda4ef3SStefan Roese .ops = &mvebu_spi_ops,
2943fda4ef3SStefan Roese .ofdata_to_platdata = mvebu_spi_ofdata_to_platdata,
2953fda4ef3SStefan Roese .platdata_auto_alloc_size = sizeof(struct mvebu_spi_platdata),
2963fda4ef3SStefan Roese .probe = mvebu_spi_probe,
2973fda4ef3SStefan Roese };
298