xref: /openbmc/u-boot/drivers/spi/xilinx_spi.c (revision 5ea392d4)
109aac75eSStephan Linz /*
209aac75eSStephan Linz  * Xilinx SPI driver
309aac75eSStephan Linz  *
4a7b6ef05SJagan Teki  * Supports 8 bit SPI transfers only, with or w/o FIFO
509aac75eSStephan Linz  *
6a7b6ef05SJagan Teki  * Based on bfin_spi.c, by way of altera_spi.c
79505c36eSJagan Teki  * Copyright (c) 2015 Jagan Teki <jteki@openedev.com>
809aac75eSStephan Linz  * Copyright (c) 2012 Stephan Linz <linz@li-pro.net>
9a7b6ef05SJagan Teki  * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
10a7b6ef05SJagan Teki  * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw>
11a7b6ef05SJagan Teki  * Copyright (c) 2005-2008 Analog Devices Inc.
1209aac75eSStephan Linz  *
13e7b1e452SJagannadha Sutradharudu Teki  * SPDX-License-Identifier:	GPL-2.0+
1409aac75eSStephan Linz  */
15a7b6ef05SJagan Teki 
1609aac75eSStephan Linz #include <config.h>
1709aac75eSStephan Linz #include <common.h>
189505c36eSJagan Teki #include <dm.h>
199505c36eSJagan Teki #include <errno.h>
2009aac75eSStephan Linz #include <malloc.h>
2109aac75eSStephan Linz #include <spi.h>
225f24d123SJagan Teki #include <asm/io.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 */
35*5ea392d4SJagan Teki #define SPICR_LSB_FIRST		BIT(9)
36*5ea392d4SJagan Teki #define SPICR_MASTER_INHIBIT	BIT(8)
37*5ea392d4SJagan Teki #define SPICR_MANUAL_SS		BIT(7)
38*5ea392d4SJagan Teki #define SPICR_RXFIFO_RESEST	BIT(6)
39*5ea392d4SJagan Teki #define SPICR_TXFIFO_RESEST	BIT(5)
40*5ea392d4SJagan Teki #define SPICR_CPHA		BIT(4)
41*5ea392d4SJagan Teki #define SPICR_CPOL		BIT(3)
42*5ea392d4SJagan Teki #define SPICR_MASTER_MODE	BIT(2)
43*5ea392d4SJagan Teki #define SPICR_SPE		BIT(1)
44*5ea392d4SJagan Teki #define SPICR_LOOP		BIT(0)
45f93542a8SJagan Teki 
46f93542a8SJagan Teki /* SPI Status Register (spisr), [1] p11, [2] p10 */
47*5ea392d4SJagan Teki #define SPISR_SLAVE_MODE_SELECT	BIT(5)
48*5ea392d4SJagan Teki #define SPISR_MODF		BIT(4)
49*5ea392d4SJagan Teki #define SPISR_TX_FULL		BIT(3)
50*5ea392d4SJagan Teki #define SPISR_TX_EMPTY		BIT(2)
51*5ea392d4SJagan Teki #define SPISR_RX_FULL		BIT(1)
52*5ea392d4SJagan Teki #define SPISR_RX_EMPTY		BIT(0)
53f93542a8SJagan Teki 
54f93542a8SJagan Teki /* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */
55f93542a8SJagan Teki #define SPIDTR_8BIT_MASK	(0xff << 0)
56f93542a8SJagan Teki #define SPIDTR_16BIT_MASK	(0xffff << 0)
57f93542a8SJagan Teki #define SPIDTR_32BIT_MASK	(0xffffffff << 0)
58f93542a8SJagan Teki 
59f93542a8SJagan Teki /* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */
60f93542a8SJagan Teki #define SPIDRR_8BIT_MASK	(0xff << 0)
61f93542a8SJagan Teki #define SPIDRR_16BIT_MASK	(0xffff << 0)
62f93542a8SJagan Teki #define SPIDRR_32BIT_MASK	(0xffffffff << 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
78a7b6ef05SJagan Teki #define CONFIG_XILINX_SPI_IDLE_VAL	0xff
79a7b6ef05SJagan Teki #endif
80a7b6ef05SJagan Teki 
81a7b6ef05SJagan Teki #ifndef CONFIG_SYS_XILINX_SPI_LIST
82a7b6ef05SJagan Teki #define CONFIG_SYS_XILINX_SPI_LIST	{ CONFIG_SYS_SPI_BASE }
83a7b6ef05SJagan Teki #endif
84a7b6ef05SJagan Teki 
85a7b6ef05SJagan Teki /* xilinx spi register set */
869505c36eSJagan Teki struct xilinx_spi_regs {
87a7b6ef05SJagan Teki 	u32 __space0__[7];
88a7b6ef05SJagan Teki 	u32 dgier;	/* Device Global Interrupt Enable Register (DGIER) */
89a7b6ef05SJagan Teki 	u32 ipisr;	/* IP Interrupt Status Register (IPISR) */
90a7b6ef05SJagan Teki 	u32 __space1__;
91a7b6ef05SJagan Teki 	u32 ipier;	/* IP Interrupt Enable Register (IPIER) */
92a7b6ef05SJagan Teki 	u32 __space2__[5];
93a7b6ef05SJagan Teki 	u32 srr;	/* Softare Reset Register (SRR) */
94a7b6ef05SJagan Teki 	u32 __space3__[7];
95a7b6ef05SJagan Teki 	u32 spicr;	/* SPI Control Register (SPICR) */
96a7b6ef05SJagan Teki 	u32 spisr;	/* SPI Status Register (SPISR) */
97a7b6ef05SJagan Teki 	u32 spidtr;	/* SPI Data Transmit Register (SPIDTR) */
98a7b6ef05SJagan Teki 	u32 spidrr;	/* SPI Data Receive Register (SPIDRR) */
99a7b6ef05SJagan Teki 	u32 spissr;	/* SPI Slave Select Register (SPISSR) */
100a7b6ef05SJagan Teki 	u32 spitfor;	/* SPI Transmit FIFO Occupancy Register (SPITFOR) */
101a7b6ef05SJagan Teki 	u32 spirfor;	/* SPI Receive FIFO Occupancy Register (SPIRFOR) */
102a7b6ef05SJagan Teki };
103a7b6ef05SJagan Teki 
1049505c36eSJagan Teki /* xilinx spi priv */
1059505c36eSJagan Teki struct xilinx_spi_priv {
1069505c36eSJagan Teki 	struct xilinx_spi_regs *regs;
107f93542a8SJagan Teki 	unsigned int freq;
108f93542a8SJagan Teki 	unsigned int mode;
109f93542a8SJagan Teki };
110f93542a8SJagan Teki 
11109aac75eSStephan Linz static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST;
1129505c36eSJagan Teki static int xilinx_spi_probe(struct udevice *bus)
11309aac75eSStephan Linz {
1149505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1159505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
11609aac75eSStephan Linz 
1179505c36eSJagan Teki 	priv->regs = (struct xilinx_spi_regs *)xilinx_spi_base_list[bus->seq];
11809aac75eSStephan Linz 
1199505c36eSJagan Teki 	writel(SPISSR_RESET_VALUE, &regs->srr);
12009aac75eSStephan Linz 
12109aac75eSStephan Linz 	return 0;
12209aac75eSStephan Linz }
12309aac75eSStephan Linz 
1249505c36eSJagan Teki static void spi_cs_activate(struct udevice *dev, uint cs)
12509aac75eSStephan Linz {
1269505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1279505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1289505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
12909aac75eSStephan Linz 
1309505c36eSJagan Teki 	writel(SPISSR_ACT(cs), &regs->spissr);
13109aac75eSStephan Linz }
13209aac75eSStephan Linz 
1339505c36eSJagan Teki static void spi_cs_deactivate(struct udevice *dev)
13409aac75eSStephan Linz {
1359505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1369505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1379505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1389505c36eSJagan Teki 
1399505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1409505c36eSJagan Teki }
1419505c36eSJagan Teki 
1429505c36eSJagan Teki static int xilinx_spi_claim_bus(struct udevice *dev)
1439505c36eSJagan Teki {
1449505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1459505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1469505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1479505c36eSJagan Teki 
1489505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1499505c36eSJagan Teki 	writel(XILSPI_SPICR_DFLT_ON, &regs->spicr);
1509505c36eSJagan Teki 
1519505c36eSJagan Teki 	return 0;
1529505c36eSJagan Teki }
1539505c36eSJagan Teki 
1549505c36eSJagan Teki static int xilinx_spi_release_bus(struct udevice *dev)
1559505c36eSJagan Teki {
1569505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1579505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1589505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1599505c36eSJagan Teki 
1609505c36eSJagan Teki 	writel(SPISSR_OFF, &regs->spissr);
1619505c36eSJagan Teki 	writel(XILSPI_SPICR_DFLT_OFF, &regs->spicr);
1629505c36eSJagan Teki 
1639505c36eSJagan Teki 	return 0;
1649505c36eSJagan Teki }
1659505c36eSJagan Teki 
1669505c36eSJagan Teki static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen,
1679505c36eSJagan Teki 			    const void *dout, void *din, unsigned long flags)
1689505c36eSJagan Teki {
1699505c36eSJagan Teki 	struct udevice *bus = dev_get_parent(dev);
1709505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
1719505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
1729505c36eSJagan Teki 	struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
17309aac75eSStephan Linz 	/* assume spi core configured to do 8 bit transfers */
17409aac75eSStephan Linz 	unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS;
17509aac75eSStephan Linz 	const unsigned char *txp = dout;
17609aac75eSStephan Linz 	unsigned char *rxp = din;
17709aac75eSStephan Linz 	unsigned rxecount = 17;	/* max. 16 elements in FIFO, leftover 1 */
178999c39a4SMichal Simek 	unsigned global_timeout;
17909aac75eSStephan Linz 
180a7b6ef05SJagan Teki 	debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n",
1819505c36eSJagan Teki 	      bus->seq, slave_plat->cs, bitlen, bytes, flags);
182a7b6ef05SJagan Teki 
18309aac75eSStephan Linz 	if (bitlen == 0)
18409aac75eSStephan Linz 		goto done;
18509aac75eSStephan Linz 
18609aac75eSStephan Linz 	if (bitlen % XILSPI_MAX_XFER_BITS) {
187a7b6ef05SJagan Teki 		printf("XILSPI warning: Not a multiple of %d bits\n",
188a7b6ef05SJagan Teki 		       XILSPI_MAX_XFER_BITS);
18909aac75eSStephan Linz 		flags |= SPI_XFER_END;
19009aac75eSStephan Linz 		goto done;
19109aac75eSStephan Linz 	}
19209aac75eSStephan Linz 
19309aac75eSStephan Linz 	/* empty read buffer */
1949505c36eSJagan Teki 	while (rxecount && !(readl(&regs->spisr) & SPISR_RX_EMPTY)) {
1959505c36eSJagan Teki 		readl(&regs->spidrr);
19609aac75eSStephan Linz 		rxecount--;
19709aac75eSStephan Linz 	}
19809aac75eSStephan Linz 
19909aac75eSStephan Linz 	if (!rxecount) {
200a7b6ef05SJagan Teki 		printf("XILSPI error: Rx buffer not empty\n");
20109aac75eSStephan Linz 		return -1;
20209aac75eSStephan Linz 	}
20309aac75eSStephan Linz 
20409aac75eSStephan Linz 	if (flags & SPI_XFER_BEGIN)
2059505c36eSJagan Teki 		spi_cs_activate(dev, slave_plat->cs);
20609aac75eSStephan Linz 
207999c39a4SMichal Simek 	/* at least 1usec or greater, leftover 1 */
2089505c36eSJagan Teki 	global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 :
2099505c36eSJagan Teki 			(XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1;
21009aac75eSStephan Linz 
211999c39a4SMichal Simek 	while (bytes--) {
212999c39a4SMichal Simek 		unsigned timeout = global_timeout;
21309aac75eSStephan Linz 		/* get Tx element from data out buffer and count up */
21409aac75eSStephan Linz 		unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
215a7b6ef05SJagan Teki 		debug("spi_xfer: tx:%x ", d);
21609aac75eSStephan Linz 
21709aac75eSStephan Linz 		/* write out and wait for processing (receive data) */
2189505c36eSJagan Teki 		writel(d & SPIDTR_8BIT_MASK, &regs->spidtr);
2199505c36eSJagan Teki 		while (timeout && readl(&regs->spisr)
22009aac75eSStephan Linz 						& SPISR_RX_EMPTY) {
22109aac75eSStephan Linz 			timeout--;
22209aac75eSStephan Linz 			udelay(1);
22309aac75eSStephan Linz 		}
22409aac75eSStephan Linz 
22509aac75eSStephan Linz 		if (!timeout) {
226a7b6ef05SJagan Teki 			printf("XILSPI error: Xfer timeout\n");
22709aac75eSStephan Linz 			return -1;
22809aac75eSStephan Linz 		}
22909aac75eSStephan Linz 
23009aac75eSStephan Linz 		/* read Rx element and push into data in buffer */
2319505c36eSJagan Teki 		d = readl(&regs->spidrr) & SPIDRR_8BIT_MASK;
23209aac75eSStephan Linz 		if (rxp)
23309aac75eSStephan Linz 			*rxp++ = d;
234a7b6ef05SJagan Teki 		debug("spi_xfer: rx:%x\n", d);
23509aac75eSStephan Linz 	}
23609aac75eSStephan Linz 
23709aac75eSStephan Linz  done:
23809aac75eSStephan Linz 	if (flags & SPI_XFER_END)
2399505c36eSJagan Teki 		spi_cs_deactivate(dev);
24009aac75eSStephan Linz 
24109aac75eSStephan Linz 	return 0;
24209aac75eSStephan Linz }
2439505c36eSJagan Teki 
2449505c36eSJagan Teki static int xilinx_spi_set_speed(struct udevice *bus, uint speed)
2459505c36eSJagan Teki {
2469505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
2479505c36eSJagan Teki 
2489505c36eSJagan Teki 	priv->freq = speed;
2499505c36eSJagan Teki 
250d5f60737SJagan Teki 	debug("xilinx_spi_set_speed: regs=%p, speed=%d\n", priv->regs,
2519505c36eSJagan Teki 	      priv->freq);
2529505c36eSJagan Teki 
2539505c36eSJagan Teki 	return 0;
2549505c36eSJagan Teki }
2559505c36eSJagan Teki 
2569505c36eSJagan Teki static int xilinx_spi_set_mode(struct udevice *bus, uint mode)
2579505c36eSJagan Teki {
2589505c36eSJagan Teki 	struct xilinx_spi_priv *priv = dev_get_priv(bus);
2599505c36eSJagan Teki 	struct xilinx_spi_regs *regs = priv->regs;
2609505c36eSJagan Teki 	uint32_t spicr;
2619505c36eSJagan Teki 
2629505c36eSJagan Teki 	spicr = readl(&regs->spicr);
263d5f60737SJagan Teki 	if (mode & SPI_LSB_FIRST)
2649505c36eSJagan Teki 		spicr |= SPICR_LSB_FIRST;
265d5f60737SJagan Teki 	if (mode & SPI_CPHA)
2669505c36eSJagan Teki 		spicr |= SPICR_CPHA;
267d5f60737SJagan Teki 	if (mode & SPI_CPOL)
2689505c36eSJagan Teki 		spicr |= SPICR_CPOL;
269d5f60737SJagan Teki 	if (mode & SPI_LOOP)
2709505c36eSJagan Teki 		spicr |= SPICR_LOOP;
2719505c36eSJagan Teki 
2729505c36eSJagan Teki 	writel(spicr, &regs->spicr);
2739505c36eSJagan Teki 	priv->mode = mode;
2749505c36eSJagan Teki 
2759505c36eSJagan Teki 	debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs,
2769505c36eSJagan Teki 	      priv->mode);
2779505c36eSJagan Teki 
2789505c36eSJagan Teki 	return 0;
2799505c36eSJagan Teki }
2809505c36eSJagan Teki 
2819505c36eSJagan Teki static const struct dm_spi_ops xilinx_spi_ops = {
2829505c36eSJagan Teki 	.claim_bus	= xilinx_spi_claim_bus,
2839505c36eSJagan Teki 	.release_bus	= xilinx_spi_release_bus,
2849505c36eSJagan Teki 	.xfer		= xilinx_spi_xfer,
2859505c36eSJagan Teki 	.set_speed	= xilinx_spi_set_speed,
2869505c36eSJagan Teki 	.set_mode	= xilinx_spi_set_mode,
2879505c36eSJagan Teki };
2889505c36eSJagan Teki 
2899505c36eSJagan Teki static const struct udevice_id xilinx_spi_ids[] = {
2909505c36eSJagan Teki 	{ .compatible = "xlnx,xilinx-spi" },
2919505c36eSJagan Teki 	{ }
2929505c36eSJagan Teki };
2939505c36eSJagan Teki 
2949505c36eSJagan Teki U_BOOT_DRIVER(xilinx_spi) = {
2959505c36eSJagan Teki 	.name	= "xilinx_spi",
2969505c36eSJagan Teki 	.id	= UCLASS_SPI,
2979505c36eSJagan Teki 	.of_match = xilinx_spi_ids,
2989505c36eSJagan Teki 	.ops	= &xilinx_spi_ops,
2999505c36eSJagan Teki 	.priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
3009505c36eSJagan Teki 	.probe	= xilinx_spi_probe,
3019505c36eSJagan Teki };
302