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, ®s->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), ®s->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, ®s->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, ®s->spissr); 1499505c36eSJagan Teki writel(XILSPI_SPICR_DFLT_ON, ®s->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, ®s->spissr); 1619505c36eSJagan Teki writel(XILSPI_SPICR_DFLT_OFF, ®s->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(®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 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(®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[] = { 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