xref: /openbmc/u-boot/drivers/spi/xilinx_spi.c (revision 1adbf296)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
209aac75eSStephan Linz /*
309aac75eSStephan Linz  * Xilinx SPI driver
409aac75eSStephan Linz  *
5a7b6ef05SJagan Teki  * Supports 8 bit SPI transfers only, with or w/o FIFO
609aac75eSStephan Linz  *
7a7b6ef05SJagan Teki  * Based on bfin_spi.c, by way of altera_spi.c
89505c36eSJagan Teki  * Copyright (c) 2015 Jagan Teki <jteki@openedev.com>
909aac75eSStephan Linz  * Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
10a7b6ef05SJagan Teki  * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
11a7b6ef05SJagan Teki  * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
12a7b6ef05SJagan Teki  * Copyright (c) 2005-2008 Analog Devices Inc.
1309aac75eSStephan Linz  */
14a7b6ef05SJagan Teki 
1509aac75eSStephan Linz #include <config.h>
1609aac75eSStephan Linz #include <common.h>
179505c36eSJagan Teki #include <dm.h>
189505c36eSJagan Teki #include <errno.h>
1909aac75eSStephan Linz #include <malloc.h>
2009aac75eSStephan Linz #include <spi.h>
215f24d123SJagan Teki #include <asm/io.h>
220c0de58fSVipul Kumar #include <wait_bit.h>
2309aac75eSStephan Linz 
24f93542a8SJagan Teki /*
25a7b6ef05SJagan Teki  * [0]: http://www.xilinx.com/support/documentation
26f93542a8SJagan Teki  *
27a7b6ef05SJagan Teki  * Xilinx SPI Register Definitions
28f93542a8SJagan Teki  * [1]:	[0]/ip_documentation/xps_spi.pdf
29f93542a8SJagan Teki  *	page 8, Register Descriptions
30f93542a8SJagan Teki  * [2]:	[0]/ip_documentation/axi_spi_ds742.pdf
31f93542a8SJagan Teki  *	page 7, Register Overview Table
32f93542a8SJagan Teki  */
33f93542a8SJagan Teki 
34f93542a8SJagan Teki /* SPI Control Register (spicr), [1] p9, [2] p8 */
355ea392d4SJagan Teki #define SPICR_LSB_FIRST		BIT(9)
365ea392d4SJagan Teki #define SPICR_MASTER_INHIBIT	BIT(8)
375ea392d4SJagan Teki #define SPICR_MANUAL_SS		BIT(7)
385ea392d4SJagan Teki #define SPICR_RXFIFO_RESEST	BIT(6)
395ea392d4SJagan Teki #define SPICR_TXFIFO_RESEST	BIT(5)
405ea392d4SJagan Teki #define SPICR_CPHA		BIT(4)
415ea392d4SJagan Teki #define SPICR_CPOL		BIT(3)
425ea392d4SJagan Teki #define SPICR_MASTER_MODE	BIT(2)
435ea392d4SJagan Teki #define SPICR_SPE		BIT(1)
445ea392d4SJagan Teki #define SPICR_LOOP		BIT(0)
45f93542a8SJagan Teki 
46f93542a8SJagan Teki /* SPI Status Register (spisr), [1] p11, [2] p10 */
475ea392d4SJagan Teki #define SPISR_SLAVE_MODE_SELECT	BIT(5)
485ea392d4SJagan Teki #define SPISR_MODF		BIT(4)
495ea392d4SJagan Teki #define SPISR_TX_FULL		BIT(3)
505ea392d4SJagan Teki #define SPISR_TX_EMPTY		BIT(2)
515ea392d4SJagan Teki #define SPISR_RX_FULL		BIT(1)
525ea392d4SJagan Teki #define SPISR_RX_EMPTY		BIT(0)
53f93542a8SJagan Teki 
54f93542a8SJagan Teki /* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
55d2436301SJagan Teki #define SPIDTR_8BIT_MASK	GENMASK(7, 0)
56d2436301SJagan Teki #define SPIDTR_16BIT_MASK	GENMASK(15, 0)
57d2436301SJagan Teki #define SPIDTR_32BIT_MASK	GENMASK(31, 0)
58f93542a8SJagan Teki 
59f93542a8SJagan Teki /* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
60d2436301SJagan Teki #define SPIDRR_8BIT_MASK	GENMASK(7, 0)
61d2436301SJagan Teki #define SPIDRR_16BIT_MASK	GENMASK(15, 0)
62d2436301SJagan Teki #define SPIDRR_32BIT_MASK	GENMASK(31, 0)
63f93542a8SJagan Teki 
64f93542a8SJagan Teki /* SPI Slave Select Register (spissr), [1] p13, [2] p13 */
65f93542a8SJagan Teki #define SPISSR_MASK(cs)		(1 << (cs))
66f93542a8SJagan Teki #define SPISSR_ACT(cs)		~SPISSR_MASK(cs)
67f93542a8SJagan Teki #define SPISSR_OFF		~0UL
68f93542a8SJagan Teki 
69f93542a8SJagan Teki /* SPI Software Reset Register (ssr) */
70f93542a8SJagan Teki #define SPISSR_RESET_VALUE	0x0a
71f93542a8SJagan Teki 
72a7b6ef05SJagan Teki #define XILSPI_MAX_XFER_BITS	8
73a7b6ef05SJagan Teki #define XILSPI_SPICR_DFLT_ON	(SPICR_MANUAL_SS | SPICR_MASTER_MODE | \
74a7b6ef05SJagan Teki 				SPICR_SPE)
75a7b6ef05SJagan Teki #define XILSPI_SPICR_DFLT_OFF	(SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS)
76a7b6ef05SJagan Teki 
77a7b6ef05SJagan Teki #ifndef CONFIG_XILINX_SPI_IDLE_VAL
78d2436301SJagan Teki #define CONFIG_XILINX_SPI_IDLE_VAL	GENMASK(7, 0)
79a7b6ef05SJagan Teki #endif
80a7b6ef05SJagan Teki 
810c0de58fSVipul Kumar #define XILINX_SPISR_TIMEOUT	10000 /* in milliseconds */
820c0de58fSVipul Kumar 
83a7b6ef05SJagan Teki /* xilinx spi register set */
849505c36eSJagan Teki struct xilinx_spi_regs {
85a7b6ef05SJagan Teki 	u32 __space0__[7];
86a7b6ef05SJagan Teki 	u32 dgier;	/* Device Global Interrupt Enable Register (DGIER) */
87a7b6ef05SJagan Teki 	u32 ipisr;	/* IP Interrupt Status Register (IPISR) */
88a7b6ef05SJagan Teki 	u32 __space1__;
89a7b6ef05SJagan Teki 	u32 ipier;	/* IP Interrupt Enable Register (IPIER) */
90a7b6ef05SJagan Teki 	u32 __space2__[5];
91a7b6ef05SJagan Teki 	u32 srr;	/* Softare Reset Register (SRR) */
92a7b6ef05SJagan Teki 	u32 __space3__[7];
93a7b6ef05SJagan Teki 	u32 spicr;	/* SPI Control Register (SPICR) */
94a7b6ef05SJagan Teki 	u32 spisr;	/* SPI Status Register (SPISR) */
95a7b6ef05SJagan Teki 	u32 spidtr;	/* SPI Data Transmit Register (SPIDTR) */
96a7b6ef05SJagan Teki 	u32 spidrr;	/* SPI Data Receive Register (SPIDRR) */
97a7b6ef05SJagan Teki 	u32 spissr;	/* SPI Slave Select Register (SPISSR) */
98a7b6ef05SJagan Teki 	u32 spitfor;	/* SPI Transmit FIFO Occupancy Register (SPITFOR) */
99a7b6ef05SJagan Teki 	u32 spirfor;	/* SPI Receive FIFO Occupancy Register (SPIRFOR) */
100a7b6ef05SJagan Teki };
101a7b6ef05SJagan Teki 
1029505c36eSJagan Teki /* xilinx spi priv */
1039505c36eSJagan Teki struct xilinx_spi_priv {
1049505c36eSJagan Teki 	struct xilinx_spi_regs *regs;
105f93542a8SJagan Teki 	unsigned int freq;
106f93542a8SJagan Teki 	unsigned int mode;
1070c0de58fSVipul Kumar 	unsigned int fifo_depth;
10883ce6469SVipul Kumar 	u8 startup;
109f93542a8SJagan Teki };
110f93542a8SJagan Teki 
xilinx_spi_probe(struct udevice * bus)1119505c36eSJagan Teki static int xilinx_spi_probe(struct udevice *bus)
11209aac75eSStephan Linz {
1139505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1149505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
11509aac75eSStephan Linz 
116*6e9d9fcbSVipul Kumar 	priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus);
11709aac75eSStephan Linz 
118*6e9d9fcbSVipul Kumar 	priv->fifo_depth = dev_read_u32_default(bus, "fifo-size", 0);
1190c0de58fSVipul Kumar 
1209505c36eSJagan Teki 	writel(SPISSR_RESET_VALUE, &regs->srr);
12109aac75eSStephan Linz 
12209aac75eSStephan Linz 	return 0;
12309aac75eSStephan Linz }
12409aac75eSStephan Linz 
spi_cs_activate(struct udevice * dev,uint cs)1259505c36eSJagan Teki static void spi_cs_activate(struct udevice *dev, uint cs)
12609aac75eSStephan Linz {
1279505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1289505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1299505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
13009aac75eSStephan Linz 
1319505c36eSJagan Teki 	writel(SPISSR_ACT(cs), &regs->spissr);
13209aac75eSStephan Linz }
13309aac75eSStephan Linz 
spi_cs_deactivate(struct udevice * dev)1349505c36eSJagan Teki static void spi_cs_deactivate(struct udevice *dev)
13509aac75eSStephan Linz {
1369505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1379505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1389505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1399505c36eSJagan Teki 
1409505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1419505c36eSJagan Teki }
1429505c36eSJagan Teki 
xilinx_spi_claim_bus(struct udevice * dev)1439505c36eSJagan Teki static int xilinx_spi_claim_bus(struct udevice *dev)
1449505c36eSJagan Teki {
1459505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1469505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1479505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1489505c36eSJagan Teki 
1499505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1509505c36eSJagan Teki 	writel(XILSPI_SPICR_DFLT_ON, &regs->spicr);
1519505c36eSJagan Teki 
1529505c36eSJagan Teki 	return 0;
1539505c36eSJagan Teki }
1549505c36eSJagan Teki 
xilinx_spi_release_bus(struct udevice * dev)1559505c36eSJagan Teki static int xilinx_spi_release_bus(struct udevice *dev)
1569505c36eSJagan Teki {
1579505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1589505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1599505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1609505c36eSJagan Teki 
1619505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1629505c36eSJagan Teki 	writel(XILSPI_SPICR_DFLT_OFF, &regs->spicr);
1639505c36eSJagan Teki 
1649505c36eSJagan Teki 	return 0;
1659505c36eSJagan Teki }
1669505c36eSJagan Teki 
xilinx_spi_fill_txfifo(struct udevice * bus,const u8 * txp,u32 txbytes)1670c0de58fSVipul Kumar static u32 xilinx_spi_fill_txfifo(struct udevice *bus, const u8 *txp,
1680c0de58fSVipul Kumar 				  u32 txbytes)
1690c0de58fSVipul Kumar {
1700c0de58fSVipul Kumar 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1710c0de58fSVipul Kumar 	struct xilinx_spi_regs *regs = priv->regs;
1720c0de58fSVipul Kumar 	unsigned char d;
1730c0de58fSVipul Kumar 	u32 i = 0;
1740c0de58fSVipul Kumar 
1750c0de58fSVipul Kumar 	while (txbytes && !(readl(&regs->spisr) & SPISR_TX_FULL) &&
1760c0de58fSVipul Kumar 	       i < priv->fifo_depth) {
1770c0de58fSVipul Kumar 		d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
1780c0de58fSVipul Kumar 		debug("spi_xfer: tx:%x ", d);
1790c0de58fSVipul Kumar 		/* write out and wait for processing (receive data) */
1800c0de58fSVipul Kumar 		writel(d & SPIDTR_8BIT_MASK, &regs->spidtr);
1810c0de58fSVipul Kumar 		txbytes--;
1820c0de58fSVipul Kumar 		i++;
1830c0de58fSVipul Kumar 	}
1840c0de58fSVipul Kumar 
1850c0de58fSVipul Kumar 	return i;
1860c0de58fSVipul Kumar }
1870c0de58fSVipul Kumar 
xilinx_spi_read_rxfifo(struct udevice * bus,u8 * rxp,u32 rxbytes)1880c0de58fSVipul Kumar static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes)
1890c0de58fSVipul Kumar {
1900c0de58fSVipul Kumar 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1910c0de58fSVipul Kumar 	struct xilinx_spi_regs *regs = priv->regs;
1920c0de58fSVipul Kumar 	unsigned char d;
1930c0de58fSVipul Kumar 	unsigned int i = 0;
1940c0de58fSVipul Kumar 
1950c0de58fSVipul Kumar 	while (rxbytes && !(readl(&regs->spisr) & SPISR_RX_EMPTY)) {
1960c0de58fSVipul Kumar 		d = readl(&regs->spidrr) & SPIDRR_8BIT_MASK;
1970c0de58fSVipul Kumar 		if (rxp)
1980c0de58fSVipul Kumar 			*rxp++ = d;
1990c0de58fSVipul Kumar 		debug("spi_xfer: rx:%x\n", d);
2000c0de58fSVipul Kumar 		rxbytes--;
2010c0de58fSVipul Kumar 		i++;
2020c0de58fSVipul Kumar 	}
2030c0de58fSVipul Kumar 	debug("Rx_done\n");
2040c0de58fSVipul Kumar 
2050c0de58fSVipul Kumar 	return i;
2060c0de58fSVipul Kumar }
2070c0de58fSVipul Kumar 
xilinx_spi_startup_block(struct udevice * dev,unsigned int bytes,const void * dout,void * din)20883ce6469SVipul Kumar static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes,
20983ce6469SVipul Kumar 				     const void *dout, void *din)
21083ce6469SVipul Kumar {
21183ce6469SVipul Kumar 	struct udevice *bus = dev_get_parent(dev);
21283ce6469SVipul Kumar 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
21383ce6469SVipul Kumar 	struct xilinx_spi_regs *regs = priv->regs;
21483ce6469SVipul Kumar 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
21583ce6469SVipul Kumar 	const unsigned char *txp = dout;
21683ce6469SVipul Kumar 	unsigned char *rxp = din;
21783ce6469SVipul Kumar 	u32 reg, count;
21883ce6469SVipul Kumar 	u32 txbytes = bytes;
21983ce6469SVipul Kumar 	u32 rxbytes = bytes;
22083ce6469SVipul Kumar 
22183ce6469SVipul Kumar 	/*
22283ce6469SVipul Kumar 	 * This loop runs two times. First time to send the command.
22383ce6469SVipul Kumar 	 * Second time to transfer data. After transferring data,
22483ce6469SVipul Kumar 	 * it sets txp to the initial value for the normal operation.
22583ce6469SVipul Kumar 	 */
22683ce6469SVipul Kumar 	for ( ; priv->startup < 2; priv->startup++) {
22783ce6469SVipul Kumar 		count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
22883ce6469SVipul Kumar 		reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
22983ce6469SVipul Kumar 		writel(reg, &regs->spicr);
23083ce6469SVipul Kumar 		count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
23183ce6469SVipul Kumar 		txp = din;
23283ce6469SVipul Kumar 
23383ce6469SVipul Kumar 		if (priv->startup) {
23483ce6469SVipul Kumar 			spi_cs_deactivate(dev);
23583ce6469SVipul Kumar 			spi_cs_activate(dev, slave_plat->cs);
23683ce6469SVipul Kumar 			txp = dout;
23783ce6469SVipul Kumar 		}
23883ce6469SVipul Kumar 	}
23983ce6469SVipul Kumar }
24083ce6469SVipul Kumar 
xilinx_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)2419505c36eSJagan Teki static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
2429505c36eSJagan Teki 			    const void *dout, void *din, unsigned long flags)
2439505c36eSJagan Teki {
2449505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
2459505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
2469505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
2479505c36eSJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
24809aac75eSStephan Linz 	/* assume spi core configured to do 8 bit transfers */
24909aac75eSStephan Linz 	unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
25009aac75eSStephan Linz 	const unsigned char *txp = dout;
25109aac75eSStephan Linz 	unsigned char *rxp = din;
2520c0de58fSVipul Kumar 	u32 txbytes = bytes;
2530c0de58fSVipul Kumar 	u32 rxbytes = bytes;
2540c0de58fSVipul Kumar 	u32 reg, count, timeout;
2550c0de58fSVipul Kumar 	int ret;
25609aac75eSStephan Linz 
257a7b6ef05SJagan Teki 	debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
2589505c36eSJagan Teki 	      bus->seq, slave_plat->cs, bitlen, bytes, flags);
259a7b6ef05SJagan Teki 
26009aac75eSStephan Linz 	if (bitlen == 0)
26109aac75eSStephan Linz 		goto done;
26209aac75eSStephan Linz 
26309aac75eSStephan Linz 	if (bitlen % XILSPI_MAX_XFER_BITS) {
264a7b6ef05SJagan Teki 		printf("XILSPI warning: Not a multiple of %d bits\n",
265a7b6ef05SJagan Teki 		       XILSPI_MAX_XFER_BITS);
26609aac75eSStephan Linz 		flags |= SPI_XFER_END;
26709aac75eSStephan Linz 		goto done;
26809aac75eSStephan Linz 	}
26909aac75eSStephan Linz 
27009aac75eSStephan Linz 	if (flags & SPI_XFER_BEGIN)
2719505c36eSJagan Teki 		spi_cs_activate(dev, slave_plat->cs);
27209aac75eSStephan Linz 
27383ce6469SVipul Kumar 	/*
27483ce6469SVipul Kumar 	 * This is the work around for the startup block issue in
27583ce6469SVipul Kumar 	 * the spi controller. SPI clock is passing through STARTUP
27683ce6469SVipul Kumar 	 * block to FLASH. STARTUP block don't provide clock as soon
27783ce6469SVipul Kumar 	 * as QSPI provides command. So first command fails.
27883ce6469SVipul Kumar 	 */
27983ce6469SVipul Kumar 	xilinx_spi_startup_block(dev, bytes, dout, din);
28009aac75eSStephan Linz 
2810c0de58fSVipul Kumar 	while (txbytes && rxbytes) {
2820c0de58fSVipul Kumar 		count = xilinx_spi_fill_txfifo(bus, txp, txbytes);
2830c0de58fSVipul Kumar 		reg = readl(&regs->spicr) & ~SPICR_MASTER_INHIBIT;
2840c0de58fSVipul Kumar 		writel(reg, &regs->spicr);
2850c0de58fSVipul Kumar 		txbytes -= count;
2860c0de58fSVipul Kumar 		if (txp)
2870c0de58fSVipul Kumar 			txp += count;
28809aac75eSStephan Linz 
2890c0de58fSVipul Kumar 		ret = wait_for_bit_le32(&regs->spisr, SPISR_TX_EMPTY, true,
2900c0de58fSVipul Kumar 					XILINX_SPISR_TIMEOUT, false);
2910c0de58fSVipul Kumar 		if (ret < 0) {
292a7b6ef05SJagan Teki 			printf("XILSPI error: Xfer timeout\n");
2930c0de58fSVipul Kumar 			return ret;
29409aac75eSStephan Linz 		}
29509aac75eSStephan Linz 
2960c0de58fSVipul Kumar 		debug("txbytes:0x%x,txp:0x%p\n", txbytes, txp);
2970c0de58fSVipul Kumar 		count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes);
2980c0de58fSVipul Kumar 		rxbytes -= count;
29909aac75eSStephan Linz 		if (rxp)
3000c0de58fSVipul Kumar 			rxp += count;
3010c0de58fSVipul Kumar 		debug("rxbytes:0x%x rxp:0x%p\n", rxbytes, rxp);
30209aac75eSStephan Linz 	}
30309aac75eSStephan Linz 
30409aac75eSStephan Linz  done:
30509aac75eSStephan Linz 	if (flags & SPI_XFER_END)
3069505c36eSJagan Teki 		spi_cs_deactivate(dev);
30709aac75eSStephan Linz 
30809aac75eSStephan Linz 	return 0;
30909aac75eSStephan Linz }
3109505c36eSJagan Teki 
xilinx_spi_set_speed(struct udevice * bus,uint speed)3119505c36eSJagan Teki static int xilinx_spi_set_speed(struct udevice *bus, uint speed)
3129505c36eSJagan Teki {
3139505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
3149505c36eSJagan Teki 
3159505c36eSJagan Teki 	priv->freq = speed;
3169505c36eSJagan Teki 
317d5f60737SJagan Teki 	debug("xilinx_spi_set_speed: regs=%p, speed=%d\n", priv->regs,
3189505c36eSJagan Teki 	      priv->freq);
3199505c36eSJagan Teki 
3209505c36eSJagan Teki 	return 0;
3219505c36eSJagan Teki }
3229505c36eSJagan Teki 
xilinx_spi_set_mode(struct udevice * bus,uint mode)3239505c36eSJagan Teki static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
3249505c36eSJagan Teki {
3259505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
3269505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
3279505c36eSJagan Teki 	uint32_t spicr;
3289505c36eSJagan Teki 
3299505c36eSJagan Teki 	spicr = readl(&regs->spicr);
330d5f60737SJagan Teki 	if (mode & SPI_LSB_FIRST)
3319505c36eSJagan Teki 		spicr |= SPICR_LSB_FIRST;
332d5f60737SJagan Teki 	if (mode & SPI_CPHA)
3339505c36eSJagan Teki 		spicr |= SPICR_CPHA;
334d5f60737SJagan Teki 	if (mode & SPI_CPOL)
3359505c36eSJagan Teki 		spicr |= SPICR_CPOL;
336d5f60737SJagan Teki 	if (mode & SPI_LOOP)
3379505c36eSJagan Teki 		spicr |= SPICR_LOOP;
3389505c36eSJagan Teki 
3399505c36eSJagan Teki 	writel(spicr, &regs->spicr);
3409505c36eSJagan Teki 	priv->mode = mode;
3419505c36eSJagan Teki 
3429505c36eSJagan Teki 	debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs,
3439505c36eSJagan Teki 	      priv->mode);
3449505c36eSJagan Teki 
3459505c36eSJagan Teki 	return 0;
3469505c36eSJagan Teki }
3479505c36eSJagan Teki 
3489505c36eSJagan Teki static const struct dm_spi_ops xilinx_spi_ops = {
3499505c36eSJagan Teki 	.claim_bus	= xilinx_spi_claim_bus,
3509505c36eSJagan Teki 	.release_bus	= xilinx_spi_release_bus,
3519505c36eSJagan Teki 	.xfer		= xilinx_spi_xfer,
3529505c36eSJagan Teki 	.set_speed	= xilinx_spi_set_speed,
3539505c36eSJagan Teki 	.set_mode	= xilinx_spi_set_mode,
3549505c36eSJagan Teki };
3559505c36eSJagan Teki 
3569505c36eSJagan Teki static const struct udevice_id xilinx_spi_ids[] = {
35776de51a6SMichal Simek 	{ .compatible = "xlnx,xps-spi-2.00.a" },
35876de51a6SMichal Simek 	{ .compatible = "xlnx,xps-spi-2.00.b" },
3599505c36eSJagan Teki 	{ }
3609505c36eSJagan Teki };
3619505c36eSJagan Teki 
3629505c36eSJagan Teki U_BOOT_DRIVER(xilinx_spi) = {
3639505c36eSJagan Teki 	.name	= "xilinx_spi",
3649505c36eSJagan Teki 	.id	= UCLASS_SPI,
3659505c36eSJagan Teki 	.of_match = xilinx_spi_ids,
3669505c36eSJagan Teki 	.ops	= &xilinx_spi_ops,
3679505c36eSJagan Teki 	.priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
3689505c36eSJagan Teki 	.probe	= xilinx_spi_probe,
3699505c36eSJagan Teki };
370