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 */
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
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;
xilinx_spi_probe(struct udevice * bus)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, ®s->srr);
12009aac75eSStephan Linz
12109aac75eSStephan Linz return 0;
12209aac75eSStephan Linz }
12309aac75eSStephan Linz
spi_cs_activate(struct udevice * dev,uint cs)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), ®s->spissr);
13109aac75eSStephan Linz }
13209aac75eSStephan Linz
spi_cs_deactivate(struct udevice * dev)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, ®s->spissr);
1409505c36eSJagan Teki }
1419505c36eSJagan Teki
xilinx_spi_claim_bus(struct udevice * dev)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, ®s->spissr);
1499505c36eSJagan Teki writel(XILSPI_SPICR_DFLT_ON, ®s->spicr);
1509505c36eSJagan Teki
1519505c36eSJagan Teki return 0;
1529505c36eSJagan Teki }
1539505c36eSJagan Teki
xilinx_spi_release_bus(struct udevice * dev)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, ®s->spissr);
1619505c36eSJagan Teki writel(XILSPI_SPICR_DFLT_OFF, ®s->spicr);
1629505c36eSJagan Teki
1639505c36eSJagan Teki return 0;
1649505c36eSJagan Teki }
1659505c36eSJagan Teki
xilinx_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)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(®s->spisr) & SPISR_RX_EMPTY)) {
1959505c36eSJagan Teki readl(®s->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, ®s->spidtr);
2199505c36eSJagan Teki while (timeout && readl(®s->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(®s->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
xilinx_spi_set_speed(struct udevice * bus,uint speed)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
xilinx_spi_set_mode(struct udevice * bus,uint mode)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(®s->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, ®s->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[] = {
290*76de51a6SMichal Simek { .compatible = "xlnx,xps-spi-2.00.a" },
291*76de51a6SMichal Simek { .compatible = "xlnx,xps-spi-2.00.b" },
2929505c36eSJagan Teki { }
2939505c36eSJagan Teki };
2949505c36eSJagan Teki
2959505c36eSJagan Teki U_BOOT_DRIVER(xilinx_spi) = {
2969505c36eSJagan Teki .name = "xilinx_spi",
2979505c36eSJagan Teki .id = UCLASS_SPI,
2989505c36eSJagan Teki .of_match = xilinx_spi_ids,
2999505c36eSJagan Teki .ops = &xilinx_spi_ops,
3009505c36eSJagan Teki .priv_auto_alloc_size = sizeof(struct xilinx_spi_priv),
3019505c36eSJagan Teki .probe = xilinx_spi_probe,
3029505c36eSJagan Teki };
303