Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
09aac75e SL |
2 | /* |
3 | * Xilinx SPI driver | |
4 | * | |
a7b6ef05 | 5 | * Supports 8 bit SPI transfers only, with or w/o FIFO |
09aac75e | 6 | * |
a7b6ef05 | 7 | * Based on bfin_spi.c, by way of altera_spi.c |
9505c36e | 8 | * Copyright (c) 2015 Jagan Teki <jteki@openedev.com> |
09aac75e | 9 | * Copyright (c) 2012 Stephan Linz <linz@li-pro.net> |
a7b6ef05 JT |
10 | * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca> |
11 | * Copyright (c) 2010 Thomas Chou <thomas@wytron.com.tw> | |
12 | * Copyright (c) 2005-2008 Analog Devices Inc. | |
09aac75e | 13 | */ |
a7b6ef05 | 14 | |
09aac75e SL |
15 | #include <config.h> |
16 | #include <common.h> | |
9505c36e JT |
17 | #include <dm.h> |
18 | #include <errno.h> | |
f7ae49fc | 19 | #include <log.h> |
09aac75e SL |
20 | #include <malloc.h> |
21 | #include <spi.h> | |
5f24d123 | 22 | #include <asm/io.h> |
0c0de58f | 23 | #include <wait_bit.h> |
cd93d625 | 24 | #include <linux/bitops.h> |
09aac75e | 25 | |
f93542a8 | 26 | /* |
a7b6ef05 | 27 | * [0]: http://www.xilinx.com/support/documentation |
f93542a8 | 28 | * |
a7b6ef05 | 29 | * Xilinx SPI Register Definitions |
f93542a8 JT |
30 | * [1]: [0]/ip_documentation/xps_spi.pdf |
31 | * page 8, Register Descriptions | |
32 | * [2]: [0]/ip_documentation/axi_spi_ds742.pdf | |
33 | * page 7, Register Overview Table | |
34 | */ | |
f93542a8 JT |
35 | |
36 | /* SPI Control Register (spicr), [1] p9, [2] p8 */ | |
5ea392d4 JT |
37 | #define SPICR_LSB_FIRST BIT(9) |
38 | #define SPICR_MASTER_INHIBIT BIT(8) | |
39 | #define SPICR_MANUAL_SS BIT(7) | |
40 | #define SPICR_RXFIFO_RESEST BIT(6) | |
41 | #define SPICR_TXFIFO_RESEST BIT(5) | |
42 | #define SPICR_CPHA BIT(4) | |
43 | #define SPICR_CPOL BIT(3) | |
44 | #define SPICR_MASTER_MODE BIT(2) | |
45 | #define SPICR_SPE BIT(1) | |
46 | #define SPICR_LOOP BIT(0) | |
f93542a8 JT |
47 | |
48 | /* SPI Status Register (spisr), [1] p11, [2] p10 */ | |
5ea392d4 JT |
49 | #define SPISR_SLAVE_MODE_SELECT BIT(5) |
50 | #define SPISR_MODF BIT(4) | |
51 | #define SPISR_TX_FULL BIT(3) | |
52 | #define SPISR_TX_EMPTY BIT(2) | |
53 | #define SPISR_RX_FULL BIT(1) | |
54 | #define SPISR_RX_EMPTY BIT(0) | |
f93542a8 JT |
55 | |
56 | /* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */ | |
d2436301 JT |
57 | #define SPIDTR_8BIT_MASK GENMASK(7, 0) |
58 | #define SPIDTR_16BIT_MASK GENMASK(15, 0) | |
59 | #define SPIDTR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
60 | |
61 | /* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */ | |
d2436301 JT |
62 | #define SPIDRR_8BIT_MASK GENMASK(7, 0) |
63 | #define SPIDRR_16BIT_MASK GENMASK(15, 0) | |
64 | #define SPIDRR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
65 | |
66 | /* SPI Slave Select Register (spissr), [1] p13, [2] p13 */ | |
67 | #define SPISSR_MASK(cs) (1 << (cs)) | |
68 | #define SPISSR_ACT(cs) ~SPISSR_MASK(cs) | |
69 | #define SPISSR_OFF ~0UL | |
70 | ||
f93542a8 JT |
71 | /* SPI Software Reset Register (ssr) */ |
72 | #define SPISSR_RESET_VALUE 0x0a | |
73 | ||
a7b6ef05 JT |
74 | #define XILSPI_MAX_XFER_BITS 8 |
75 | #define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \ | |
76 | SPICR_SPE) | |
77 | #define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS) | |
78 | ||
f44bd3bc | 79 | #define XILINX_SPI_IDLE_VAL GENMASK(7, 0) |
a7b6ef05 | 80 | |
0c0de58f VK |
81 | #define XILINX_SPISR_TIMEOUT 10000 /* in milliseconds */ |
82 | ||
a7b6ef05 | 83 | /* xilinx spi register set */ |
9505c36e | 84 | struct xilinx_spi_regs { |
a7b6ef05 JT |
85 | u32 __space0__[7]; |
86 | u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */ | |
87 | u32 ipisr; /* IP Interrupt Status Register (IPISR) */ | |
88 | u32 __space1__; | |
89 | u32 ipier; /* IP Interrupt Enable Register (IPIER) */ | |
90 | u32 __space2__[5]; | |
91 | u32 srr; /* Softare Reset Register (SRR) */ | |
92 | u32 __space3__[7]; | |
93 | u32 spicr; /* SPI Control Register (SPICR) */ | |
94 | u32 spisr; /* SPI Status Register (SPISR) */ | |
95 | u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */ | |
96 | u32 spidrr; /* SPI Data Receive Register (SPIDRR) */ | |
97 | u32 spissr; /* SPI Slave Select Register (SPISSR) */ | |
98 | u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */ | |
99 | u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */ | |
100 | }; | |
101 | ||
9505c36e JT |
102 | /* xilinx spi priv */ |
103 | struct xilinx_spi_priv { | |
104 | struct xilinx_spi_regs *regs; | |
f93542a8 JT |
105 | unsigned int freq; |
106 | unsigned int mode; | |
0c0de58f | 107 | unsigned int fifo_depth; |
83ce6469 | 108 | u8 startup; |
f93542a8 JT |
109 | }; |
110 | ||
9505c36e | 111 | static int xilinx_spi_probe(struct udevice *bus) |
09aac75e | 112 | { |
9505c36e JT |
113 | struct xilinx_spi_priv *priv = dev_get_priv(bus); |
114 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 115 | |
6e9d9fcb | 116 | priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus); |
09aac75e | 117 | |
6e9d9fcb | 118 | priv->fifo_depth = dev_read_u32_default(bus, "fifo-size", 0); |
0c0de58f | 119 | |
9505c36e | 120 | writel(SPISSR_RESET_VALUE, ®s->srr); |
09aac75e | 121 | |
9505c36e | 122 | return 0; |
09aac75e SL |
123 | } |
124 | ||
9505c36e | 125 | static void spi_cs_activate(struct udevice *dev, uint cs) |
09aac75e | 126 | { |
9505c36e JT |
127 | struct udevice *bus = dev_get_parent(dev); |
128 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
129 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 130 | |
9505c36e | 131 | writel(SPISSR_ACT(cs), ®s->spissr); |
09aac75e SL |
132 | } |
133 | ||
9505c36e | 134 | static void spi_cs_deactivate(struct udevice *dev) |
09aac75e | 135 | { |
9505c36e JT |
136 | struct udevice *bus = dev_get_parent(dev); |
137 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
138 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 139 | |
9505c36e | 140 | writel(SPISSR_OFF, ®s->spissr); |
09aac75e SL |
141 | } |
142 | ||
9505c36e | 143 | static int xilinx_spi_claim_bus(struct udevice *dev) |
09aac75e | 144 | { |
9505c36e JT |
145 | struct udevice *bus = dev_get_parent(dev); |
146 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
147 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 148 | |
9505c36e JT |
149 | writel(SPISSR_OFF, ®s->spissr); |
150 | writel(XILSPI_SPICR_DFLT_ON, ®s->spicr); | |
09aac75e | 151 | |
09aac75e SL |
152 | return 0; |
153 | } | |
154 | ||
9505c36e | 155 | static int xilinx_spi_release_bus(struct udevice *dev) |
09aac75e | 156 | { |
9505c36e JT |
157 | struct udevice *bus = dev_get_parent(dev); |
158 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
159 | struct xilinx_spi_regs *regs = priv->regs; | |
09aac75e | 160 | |
9505c36e JT |
161 | writel(SPISSR_OFF, ®s->spissr); |
162 | writel(XILSPI_SPICR_DFLT_OFF, ®s->spicr); | |
163 | ||
164 | return 0; | |
09aac75e SL |
165 | } |
166 | ||
0c0de58f VK |
167 | static u32 xilinx_spi_fill_txfifo(struct udevice *bus, const u8 *txp, |
168 | u32 txbytes) | |
169 | { | |
170 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
171 | struct xilinx_spi_regs *regs = priv->regs; | |
172 | unsigned char d; | |
173 | u32 i = 0; | |
174 | ||
175 | while (txbytes && !(readl(®s->spisr) & SPISR_TX_FULL) && | |
176 | i < priv->fifo_depth) { | |
f44bd3bc | 177 | d = txp ? *txp++ : XILINX_SPI_IDLE_VAL; |
0c0de58f VK |
178 | debug("spi_xfer: tx:%x ", d); |
179 | /* write out and wait for processing (receive data) */ | |
180 | writel(d & SPIDTR_8BIT_MASK, ®s->spidtr); | |
181 | txbytes--; | |
182 | i++; | |
183 | } | |
184 | ||
185 | return i; | |
186 | } | |
187 | ||
188 | static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes) | |
189 | { | |
190 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
191 | struct xilinx_spi_regs *regs = priv->regs; | |
192 | unsigned char d; | |
193 | unsigned int i = 0; | |
194 | ||
195 | while (rxbytes && !(readl(®s->spisr) & SPISR_RX_EMPTY)) { | |
196 | d = readl(®s->spidrr) & SPIDRR_8BIT_MASK; | |
197 | if (rxp) | |
198 | *rxp++ = d; | |
199 | debug("spi_xfer: rx:%x\n", d); | |
200 | rxbytes--; | |
201 | i++; | |
202 | } | |
203 | debug("Rx_done\n"); | |
204 | ||
205 | return i; | |
206 | } | |
207 | ||
83ce6469 VK |
208 | static void xilinx_spi_startup_block(struct udevice *dev, unsigned int bytes, |
209 | const void *dout, void *din) | |
210 | { | |
211 | struct udevice *bus = dev_get_parent(dev); | |
212 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
213 | struct xilinx_spi_regs *regs = priv->regs; | |
8a8d24bd | 214 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
83ce6469 VK |
215 | const unsigned char *txp = dout; |
216 | unsigned char *rxp = din; | |
c94b44c6 | 217 | u32 reg; |
83ce6469 VK |
218 | u32 txbytes = bytes; |
219 | u32 rxbytes = bytes; | |
220 | ||
221 | /* | |
222 | * This loop runs two times. First time to send the command. | |
223 | * Second time to transfer data. After transferring data, | |
224 | * it sets txp to the initial value for the normal operation. | |
225 | */ | |
226 | for ( ; priv->startup < 2; priv->startup++) { | |
c94b44c6 | 227 | xilinx_spi_fill_txfifo(bus, txp, txbytes); |
83ce6469 VK |
228 | reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; |
229 | writel(reg, ®s->spicr); | |
c94b44c6 | 230 | xilinx_spi_read_rxfifo(bus, rxp, rxbytes); |
83ce6469 VK |
231 | txp = din; |
232 | ||
233 | if (priv->startup) { | |
234 | spi_cs_deactivate(dev); | |
235 | spi_cs_activate(dev, slave_plat->cs); | |
236 | txp = dout; | |
237 | } | |
238 | } | |
239 | } | |
240 | ||
9505c36e JT |
241 | static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, |
242 | const void *dout, void *din, unsigned long flags) | |
09aac75e | 243 | { |
9505c36e JT |
244 | struct udevice *bus = dev_get_parent(dev); |
245 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
246 | struct xilinx_spi_regs *regs = priv->regs; | |
8a8d24bd | 247 | struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); |
09aac75e SL |
248 | /* assume spi core configured to do 8 bit transfers */ |
249 | unsigned int bytes = bitlen / XILSPI_MAX_XFER_BITS; | |
250 | const unsigned char *txp = dout; | |
251 | unsigned char *rxp = din; | |
0c0de58f VK |
252 | u32 txbytes = bytes; |
253 | u32 rxbytes = bytes; | |
e1303b2b | 254 | u32 reg, count; |
0c0de58f | 255 | int ret; |
09aac75e | 256 | |
a7b6ef05 | 257 | debug("spi_xfer: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", |
8b85dfc6 | 258 | dev_seq(bus), slave_plat->cs, bitlen, bytes, flags); |
a7b6ef05 | 259 | |
09aac75e SL |
260 | if (bitlen == 0) |
261 | goto done; | |
262 | ||
263 | if (bitlen % XILSPI_MAX_XFER_BITS) { | |
a7b6ef05 JT |
264 | printf("XILSPI warning: Not a multiple of %d bits\n", |
265 | XILSPI_MAX_XFER_BITS); | |
09aac75e SL |
266 | flags |= SPI_XFER_END; |
267 | goto done; | |
268 | } | |
269 | ||
09aac75e | 270 | if (flags & SPI_XFER_BEGIN) |
9505c36e | 271 | spi_cs_activate(dev, slave_plat->cs); |
09aac75e | 272 | |
83ce6469 VK |
273 | /* |
274 | * This is the work around for the startup block issue in | |
275 | * the spi controller. SPI clock is passing through STARTUP | |
276 | * block to FLASH. STARTUP block don't provide clock as soon | |
277 | * as QSPI provides command. So first command fails. | |
278 | */ | |
279 | xilinx_spi_startup_block(dev, bytes, dout, din); | |
09aac75e | 280 | |
0c0de58f VK |
281 | while (txbytes && rxbytes) { |
282 | count = xilinx_spi_fill_txfifo(bus, txp, txbytes); | |
283 | reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; | |
284 | writel(reg, ®s->spicr); | |
285 | txbytes -= count; | |
286 | if (txp) | |
287 | txp += count; | |
09aac75e | 288 | |
0c0de58f VK |
289 | ret = wait_for_bit_le32(®s->spisr, SPISR_TX_EMPTY, true, |
290 | XILINX_SPISR_TIMEOUT, false); | |
291 | if (ret < 0) { | |
a7b6ef05 | 292 | printf("XILSPI error: Xfer timeout\n"); |
0c0de58f | 293 | return ret; |
09aac75e SL |
294 | } |
295 | ||
0c0de58f VK |
296 | debug("txbytes:0x%x,txp:0x%p\n", txbytes, txp); |
297 | count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes); | |
298 | rxbytes -= count; | |
09aac75e | 299 | if (rxp) |
0c0de58f VK |
300 | rxp += count; |
301 | debug("rxbytes:0x%x rxp:0x%p\n", rxbytes, rxp); | |
09aac75e SL |
302 | } |
303 | ||
304 | done: | |
305 | if (flags & SPI_XFER_END) | |
9505c36e | 306 | spi_cs_deactivate(dev); |
09aac75e SL |
307 | |
308 | return 0; | |
309 | } | |
9505c36e JT |
310 | |
311 | static int xilinx_spi_set_speed(struct udevice *bus, uint speed) | |
312 | { | |
313 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
314 | ||
315 | priv->freq = speed; | |
316 | ||
d999a7b7 | 317 | debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq); |
9505c36e JT |
318 | |
319 | return 0; | |
320 | } | |
321 | ||
322 | static int xilinx_spi_set_mode(struct udevice *bus, uint mode) | |
323 | { | |
324 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
325 | struct xilinx_spi_regs *regs = priv->regs; | |
d999a7b7 | 326 | u32 spicr; |
9505c36e JT |
327 | |
328 | spicr = readl(®s->spicr); | |
d5f60737 | 329 | if (mode & SPI_LSB_FIRST) |
9505c36e | 330 | spicr |= SPICR_LSB_FIRST; |
d5f60737 | 331 | if (mode & SPI_CPHA) |
9505c36e | 332 | spicr |= SPICR_CPHA; |
d5f60737 | 333 | if (mode & SPI_CPOL) |
9505c36e | 334 | spicr |= SPICR_CPOL; |
d5f60737 | 335 | if (mode & SPI_LOOP) |
9505c36e JT |
336 | spicr |= SPICR_LOOP; |
337 | ||
338 | writel(spicr, ®s->spicr); | |
339 | priv->mode = mode; | |
340 | ||
d999a7b7 | 341 | debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode); |
9505c36e JT |
342 | |
343 | return 0; | |
344 | } | |
345 | ||
346 | static const struct dm_spi_ops xilinx_spi_ops = { | |
347 | .claim_bus = xilinx_spi_claim_bus, | |
348 | .release_bus = xilinx_spi_release_bus, | |
349 | .xfer = xilinx_spi_xfer, | |
350 | .set_speed = xilinx_spi_set_speed, | |
351 | .set_mode = xilinx_spi_set_mode, | |
352 | }; | |
353 | ||
354 | static const struct udevice_id xilinx_spi_ids[] = { | |
76de51a6 MS |
355 | { .compatible = "xlnx,xps-spi-2.00.a" }, |
356 | { .compatible = "xlnx,xps-spi-2.00.b" }, | |
9505c36e JT |
357 | { } |
358 | }; | |
359 | ||
360 | U_BOOT_DRIVER(xilinx_spi) = { | |
361 | .name = "xilinx_spi", | |
362 | .id = UCLASS_SPI, | |
363 | .of_match = xilinx_spi_ids, | |
364 | .ops = &xilinx_spi_ops, | |
41575d8e | 365 | .priv_auto = sizeof(struct xilinx_spi_priv), |
9505c36e JT |
366 | .probe = xilinx_spi_probe, |
367 | }; |