]>
Commit | Line | Data |
---|---|---|
09aac75e SL |
1 | /* |
2 | * Xilinx SPI driver | |
3 | * | |
a7b6ef05 | 4 | * Supports 8 bit SPI transfers only, with or w/o FIFO |
09aac75e | 5 | * |
a7b6ef05 | 6 | * Based on bfin_spi.c, by way of altera_spi.c |
9505c36e | 7 | * Copyright (c) 2015 Jagan Teki <jteki@openedev.com> |
09aac75e | 8 | * Copyright (c) 2012 Stephan Linz <linz@li-pro.net> |
a7b6ef05 JT |
9 | * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca> |
10 | * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw> | |
11 | * Copyright (c) 2005-2008 Analog Devices Inc. | |
09aac75e | 12 | * |
e7b1e452 | 13 | * SPDX-License-Identifier: GPL-2.0+ |
09aac75e | 14 | */ |
a7b6ef05 | 15 | |
09aac75e SL |
16 | #include <config.h> |
17 | #include <common.h> | |
9505c36e JT |
18 | #include <dm.h> |
19 | #include <errno.h> | |
09aac75e SL |
20 | #include <malloc.h> |
21 | #include <spi.h> | |
5f24d123 | 22 | #include <asm/io.h> |
09aac75e | 23 | |
f93542a8 | 24 | /* |
a7b6ef05 | 25 | * [0]: http://www.xilinx.com/support/documentation |
f93542a8 | 26 | * |
a7b6ef05 | 27 | * Xilinx SPI Register Definitions |
f93542a8 JT |
28 | * [1]: [0]/ip_documentation/xps_spi.pdf |
29 | * page 8, Register Descriptions | |
30 | * [2]: [0]/ip_documentation/axi_spi_ds742.pdf | |
31 | * page 7, Register Overview Table | |
32 | */ | |
f93542a8 JT |
33 | |
34 | /* SPI Control Register (spicr), [1] p9, [2] p8 */ | |
5ea392d4 JT |
35 | #define SPICR_LSB_FIRST BIT(9) |
36 | #define SPICR_MASTER_INHIBIT BIT(8) | |
37 | #define SPICR_MANUAL_SS BIT(7) | |
38 | #define SPICR_RXFIFO_RESEST BIT(6) | |
39 | #define SPICR_TXFIFO_RESEST BIT(5) | |
40 | #define SPICR_CPHA BIT(4) | |
41 | #define SPICR_CPOL BIT(3) | |
42 | #define SPICR_MASTER_MODE BIT(2) | |
43 | #define SPICR_SPE BIT(1) | |
44 | #define SPICR_LOOP BIT(0) | |
f93542a8 JT |
45 | |
46 | /* SPI Status Register (spisr), [1] p11, [2] p10 */ | |
5ea392d4 JT |
47 | #define SPISR_SLAVE_MODE_SELECT BIT(5) |
48 | #define SPISR_MODF BIT(4) | |
49 | #define SPISR_TX_FULL BIT(3) | |
50 | #define SPISR_TX_EMPTY BIT(2) | |
51 | #define SPISR_RX_FULL BIT(1) | |
52 | #define SPISR_RX_EMPTY BIT(0) | |
f93542a8 JT |
53 | |
54 | /* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */ | |
d2436301 JT |
55 | #define SPIDTR_8BIT_MASK GENMASK(7, 0) |
56 | #define SPIDTR_16BIT_MASK GENMASK(15, 0) | |
57 | #define SPIDTR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
58 | |
59 | /* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */ | |
d2436301 JT |
60 | #define SPIDRR_8BIT_MASK GENMASK(7, 0) |
61 | #define SPIDRR_16BIT_MASK GENMASK(15, 0) | |
62 | #define SPIDRR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
63 | |
64 | /* SPI Slave Select Register (spissr), [1] p13, [2] p13 */ | |
65 | #define SPISSR_MASK(cs) (1 << (cs)) | |
66 | #define SPISSR_ACT(cs) ~SPISSR_MASK(cs) | |
67 | #define SPISSR_OFF ~0UL | |
68 | ||
f93542a8 JT |
69 | /* SPI Software Reset Register (ssr) */ |
70 | #define SPISSR_RESET_VALUE 0x0a | |
71 | ||
a7b6ef05 JT |
72 | #define XILSPI_MAX_XFER_BITS 8 |
73 | #define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \ | |
74 | SPICR_SPE) | |
75 | #define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS) | |
76 | ||
77 | #ifndef CONFIG_XILINX_SPI_IDLE_VAL | |
d2436301 | 78 | #define CONFIG_XILINX_SPI_IDLE_VAL GENMASK(7, 0) |
a7b6ef05 JT |
79 | #endif |
80 | ||
81 | #ifndef CONFIG_SYS_XILINX_SPI_LIST | |
82 | #define CONFIG_SYS_XILINX_SPI_LIST { CONFIG_SYS_SPI_BASE } | |
83 | #endif | |
84 | ||
85 | /* xilinx spi register set */ | |
9505c36e | 86 | struct xilinx_spi_regs { |
a7b6ef05 JT |
87 | u32 __space0__[7]; |
88 | u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */ | |
89 | u32 ipisr; /* IP Interrupt Status Register (IPISR) */ | |
90 | u32 __space1__; | |
91 | u32 ipier; /* IP Interrupt Enable Register (IPIER) */ | |
92 | u32 __space2__[5]; | |
93 | u32 srr; /* Softare Reset Register (SRR) */ | |
94 | u32 __space3__[7]; | |
95 | u32 spicr; /* SPI Control Register (SPICR) */ | |
96 | u32 spisr; /* SPI Status Register (SPISR) */ | |
97 | u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */ | |
98 | u32 spidrr; /* SPI Data Receive Register (SPIDRR) */ | |
99 | u32 spissr; /* SPI Slave Select Register (SPISSR) */ | |
100 | u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */ | |
101 | u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */ | |
102 | }; | |
103 | ||
9505c36e JT |
104 | /* xilinx spi priv */ |
105 | struct xilinx_spi_priv { | |
106 | struct xilinx_spi_regs *regs; | |
f93542a8 JT |
107 | unsigned int freq; |
108 | unsigned int mode; | |
109 | }; | |
110 | ||
09aac75e | 111 | static unsigned long xilinx_spi_base_list[] = CONFIG_SYS_XILINX_SPI_LIST; |
9505c36e | 112 | static int xilinx_spi_probe(struct udevice *bus) |
09aac75e | 113 | { |
9505c36e JT |
114 | struct xilinx_spi_priv *priv = dev_get_priv(bus); |
115 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 116 | |
9505c36e | 117 | priv->regs = (struct xilinx_spi_regs *)xilinx_spi_base_list[bus->seq]; |
09aac75e | 118 | |
9505c36e | 119 | writel(SPISSR_RESET_VALUE, ®s->srr); |
09aac75e | 120 | |
9505c36e | 121 | return 0; |
09aac75e SL |
122 | } |
123 | ||
9505c36e | 124 | static void spi_cs_activate(struct udevice *dev, uint cs) |
09aac75e | 125 | { |
9505c36e JT |
126 | struct udevice *bus = dev_get_parent(dev); |
127 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
128 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 129 | |
9505c36e | 130 | writel(SPISSR_ACT(cs), ®s->spissr); |
09aac75e SL |
131 | } |
132 | ||
9505c36e | 133 | static void spi_cs_deactivate(struct udevice *dev) |
09aac75e | 134 | { |
9505c36e JT |
135 | struct udevice *bus = dev_get_parent(dev); |
136 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
137 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 138 | |
9505c36e | 139 | writel(SPISSR_OFF, ®s->spissr); |
09aac75e SL |
140 | } |
141 | ||
9505c36e | 142 | static int xilinx_spi_claim_bus(struct udevice *dev) |
09aac75e | 143 | { |
9505c36e JT |
144 | struct udevice *bus = dev_get_parent(dev); |
145 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
146 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 147 | |
9505c36e JT |
148 | writel(SPISSR_OFF, ®s->spissr); |
149 | writel(XILSPI_SPICR_DFLT_ON, ®s->spicr); | |
09aac75e | 150 | |
09aac75e SL |
151 | return 0; |
152 | } | |
153 | ||
9505c36e | 154 | static int xilinx_spi_release_bus(struct udevice *dev) |
09aac75e | 155 | { |
9505c36e JT |
156 | struct udevice *bus = dev_get_parent(dev); |
157 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
158 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 159 | |
9505c36e JT |
160 | writel(SPISSR_OFF, ®s->spissr); |
161 | writel(XILSPI_SPICR_DFLT_OFF, ®s->spicr); | |
162 | ||
163 | return 0; | |
09aac75e SL |
164 | } |
165 | ||
9505c36e JT |
166 | static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, |
167 | const void *dout, void *din, unsigned long flags) | |
09aac75e | 168 | { |
9505c36e JT |
169 | struct udevice *bus = dev_get_parent(dev); |
170 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
171 | struct xilinx_spi_regs *regs = priv->regs; | |
172 | struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); | |
09aac75e SL |
173 | /* assume spi core configured to do 8 bit transfers */ |
174 | unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS; | |
175 | const unsigned char *txp = dout; | |
176 | unsigned char *rxp = din; | |
177 | unsigned rxecount = 17; /* max. 16 elements in FIFO, leftover 1 */ | |
999c39a4 | 178 | unsigned global_timeout; |
09aac75e | 179 | |
a7b6ef05 | 180 | debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", |
9505c36e | 181 | bus->seq, slave_plat->cs, bitlen, bytes, flags); |
a7b6ef05 | 182 | |
09aac75e SL |
183 | if (bitlen == 0) |
184 | goto done; | |
185 | ||
186 | if (bitlen % XILSPI_MAX_XFER_BITS) { | |
a7b6ef05 JT |
187 | printf("XILSPI warning: Not a multiple of %d bits\n", |
188 | XILSPI_MAX_XFER_BITS); | |
09aac75e SL |
189 | flags |= SPI_XFER_END; |
190 | goto done; | |
191 | } | |
192 | ||
193 | /* empty read buffer */ | |
9505c36e JT |
194 | while (rxecount && !(readl(®s->spisr) & SPISR_RX_EMPTY)) { |
195 | readl(®s->spidrr); | |
09aac75e SL |
196 | rxecount--; |
197 | } | |
198 | ||
199 | if (!rxecount) { | |
a7b6ef05 | 200 | printf("XILSPI error: Rx buffer not empty\n"); |
09aac75e SL |
201 | return -1; |
202 | } | |
203 | ||
204 | if (flags & SPI_XFER_BEGIN) | |
9505c36e | 205 | spi_cs_activate(dev, slave_plat->cs); |
09aac75e | 206 | |
999c39a4 | 207 | /* at least 1usec or greater, leftover 1 */ |
9505c36e JT |
208 | global_timeout = priv->freq > XILSPI_MAX_XFER_BITS * 1000000 ? 2 : |
209 | (XILSPI_MAX_XFER_BITS * 1000000 / priv->freq) + 1; | |
09aac75e | 210 | |
999c39a4 MS |
211 | while (bytes--) { |
212 | unsigned timeout = global_timeout; | |
09aac75e SL |
213 | /* get Tx element from data out buffer and count up */ |
214 | unsigned char d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL; | |
a7b6ef05 | 215 | debug("spi_xfer: tx:%x ", d); |
09aac75e SL |
216 | |
217 | /* write out and wait for processing (receive data) */ | |
9505c36e JT |
218 | writel(d & SPIDTR_8BIT_MASK, ®s->spidtr); |
219 | while (timeout && readl(®s->spisr) | |
09aac75e SL |
220 | & SPISR_RX_EMPTY) { |
221 | timeout--; | |
222 | udelay(1); | |
223 | } | |
224 | ||
225 | if (!timeout) { | |
a7b6ef05 | 226 | printf("XILSPI error: Xfer timeout\n"); |
09aac75e SL |
227 | return -1; |
228 | } | |
229 | ||
230 | /* read Rx element and push into data in buffer */ | |
9505c36e | 231 | d = readl(®s->spidrr) & SPIDRR_8BIT_MASK; |
09aac75e SL |
232 | if (rxp) |
233 | *rxp++ = d; | |
a7b6ef05 | 234 | debug("spi_xfer: rx:%x\n", d); |
09aac75e SL |
235 | } |
236 | ||
237 | done: | |
238 | if (flags & SPI_XFER_END) | |
9505c36e | 239 | spi_cs_deactivate(dev); |
09aac75e SL |
240 | |
241 | return 0; | |
242 | } | |
9505c36e JT |
243 | |
244 | static int xilinx_spi_set_speed(struct udevice *bus, uint speed) | |
245 | { | |
246 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
247 | ||
248 | priv->freq = speed; | |
249 | ||
d5f60737 | 250 | debug("xilinx_spi_set_speed: regs=%p, speed=%d\n", priv->regs, |
9505c36e JT |
251 | priv->freq); |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | static int xilinx_spi_set_mode(struct udevice *bus, uint mode) | |
257 | { | |
258 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
259 | struct xilinx_spi_regs *regs = priv->regs; | |
260 | uint32_t spicr; | |
261 | ||
262 | spicr = readl(®s->spicr); | |
d5f60737 | 263 | if (mode & SPI_LSB_FIRST) |
9505c36e | 264 | spicr |= SPICR_LSB_FIRST; |
d5f60737 | 265 | if (mode & SPI_CPHA) |
9505c36e | 266 | spicr |= SPICR_CPHA; |
d5f60737 | 267 | if (mode & SPI_CPOL) |
9505c36e | 268 | spicr |= SPICR_CPOL; |
d5f60737 | 269 | if (mode & SPI_LOOP) |
9505c36e JT |
270 | spicr |= SPICR_LOOP; |
271 | ||
272 | writel(spicr, ®s->spicr); | |
273 | priv->mode = mode; | |
274 | ||
275 | debug("xilinx_spi_set_mode: regs=%p, mode=%d\n", priv->regs, | |
276 | priv->mode); | |
277 | ||
278 | return 0; | |
279 | } | |
280 | ||
281 | static const struct dm_spi_ops xilinx_spi_ops = { | |
282 | .claim_bus = xilinx_spi_claim_bus, | |
283 | .release_bus = xilinx_spi_release_bus, | |
284 | .xfer = xilinx_spi_xfer, | |
285 | .set_speed = xilinx_spi_set_speed, | |
286 | .set_mode = xilinx_spi_set_mode, | |
287 | }; | |
288 | ||
289 | static const struct udevice_id xilinx_spi_ids[] = { | |
76de51a6 MS |
290 | { .compatible = "xlnx,xps-spi-2.00.a" }, |
291 | { .compatible = "xlnx,xps-spi-2.00.b" }, | |
9505c36e JT |
292 | { } |
293 | }; | |
294 | ||
295 | U_BOOT_DRIVER(xilinx_spi) = { | |
296 | .name = "xilinx_spi", | |
297 | .id = UCLASS_SPI, | |
298 | .of_match = xilinx_spi_ids, | |
299 | .ops = &xilinx_spi_ops, | |
300 | .priv_auto_alloc_size = sizeof(struct xilinx_spi_priv), | |
301 | .probe = xilinx_spi_probe, | |
302 | }; |