]>
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> | |
f2dd6599 | 22 | #include <spi-mem.h> |
5f24d123 | 23 | #include <asm/io.h> |
0c0de58f | 24 | #include <wait_bit.h> |
cd93d625 | 25 | #include <linux/bitops.h> |
09aac75e | 26 | |
f93542a8 | 27 | /* |
a7b6ef05 | 28 | * [0]: http://www.xilinx.com/support/documentation |
f93542a8 | 29 | * |
a7b6ef05 | 30 | * Xilinx SPI Register Definitions |
f93542a8 JT |
31 | * [1]: [0]/ip_documentation/xps_spi.pdf |
32 | * page 8, Register Descriptions | |
33 | * [2]: [0]/ip_documentation/axi_spi_ds742.pdf | |
34 | * page 7, Register Overview Table | |
35 | */ | |
f93542a8 JT |
36 | |
37 | /* SPI Control Register (spicr), [1] p9, [2] p8 */ | |
5ea392d4 JT |
38 | #define SPICR_LSB_FIRST BIT(9) |
39 | #define SPICR_MASTER_INHIBIT BIT(8) | |
40 | #define SPICR_MANUAL_SS BIT(7) | |
41 | #define SPICR_RXFIFO_RESEST BIT(6) | |
42 | #define SPICR_TXFIFO_RESEST BIT(5) | |
43 | #define SPICR_CPHA BIT(4) | |
44 | #define SPICR_CPOL BIT(3) | |
45 | #define SPICR_MASTER_MODE BIT(2) | |
46 | #define SPICR_SPE BIT(1) | |
47 | #define SPICR_LOOP BIT(0) | |
f93542a8 JT |
48 | |
49 | /* SPI Status Register (spisr), [1] p11, [2] p10 */ | |
5ea392d4 JT |
50 | #define SPISR_SLAVE_MODE_SELECT BIT(5) |
51 | #define SPISR_MODF BIT(4) | |
52 | #define SPISR_TX_FULL BIT(3) | |
53 | #define SPISR_TX_EMPTY BIT(2) | |
54 | #define SPISR_RX_FULL BIT(1) | |
55 | #define SPISR_RX_EMPTY BIT(0) | |
f93542a8 JT |
56 | |
57 | /* SPI Data Transmit Register (spidtr), [1] p12, [2] p12 */ | |
d2436301 JT |
58 | #define SPIDTR_8BIT_MASK GENMASK(7, 0) |
59 | #define SPIDTR_16BIT_MASK GENMASK(15, 0) | |
60 | #define SPIDTR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
61 | |
62 | /* SPI Data Receive Register (spidrr), [1] p12, [2] p12 */ | |
d2436301 JT |
63 | #define SPIDRR_8BIT_MASK GENMASK(7, 0) |
64 | #define SPIDRR_16BIT_MASK GENMASK(15, 0) | |
65 | #define SPIDRR_32BIT_MASK GENMASK(31, 0) | |
f93542a8 JT |
66 | |
67 | /* SPI Slave Select Register (spissr), [1] p13, [2] p13 */ | |
68 | #define SPISSR_MASK(cs) (1 << (cs)) | |
69 | #define SPISSR_ACT(cs) ~SPISSR_MASK(cs) | |
70 | #define SPISSR_OFF ~0UL | |
71 | ||
f93542a8 JT |
72 | /* SPI Software Reset Register (ssr) */ |
73 | #define SPISSR_RESET_VALUE 0x0a | |
74 | ||
a7b6ef05 JT |
75 | #define XILSPI_MAX_XFER_BITS 8 |
76 | #define XILSPI_SPICR_DFLT_ON (SPICR_MANUAL_SS | SPICR_MASTER_MODE | \ | |
f2dd6599 | 77 | SPICR_SPE | SPICR_MASTER_INHIBIT) |
a7b6ef05 JT |
78 | #define XILSPI_SPICR_DFLT_OFF (SPICR_MASTER_INHIBIT | SPICR_MANUAL_SS) |
79 | ||
f44bd3bc | 80 | #define XILINX_SPI_IDLE_VAL GENMASK(7, 0) |
a7b6ef05 | 81 | |
0c0de58f VK |
82 | #define XILINX_SPISR_TIMEOUT 10000 /* in milliseconds */ |
83 | ||
a7b6ef05 | 84 | /* xilinx spi register set */ |
9505c36e | 85 | struct xilinx_spi_regs { |
a7b6ef05 JT |
86 | u32 __space0__[7]; |
87 | u32 dgier; /* Device Global Interrupt Enable Register (DGIER) */ | |
88 | u32 ipisr; /* IP Interrupt Status Register (IPISR) */ | |
89 | u32 __space1__; | |
90 | u32 ipier; /* IP Interrupt Enable Register (IPIER) */ | |
91 | u32 __space2__[5]; | |
92 | u32 srr; /* Softare Reset Register (SRR) */ | |
93 | u32 __space3__[7]; | |
94 | u32 spicr; /* SPI Control Register (SPICR) */ | |
95 | u32 spisr; /* SPI Status Register (SPISR) */ | |
96 | u32 spidtr; /* SPI Data Transmit Register (SPIDTR) */ | |
97 | u32 spidrr; /* SPI Data Receive Register (SPIDRR) */ | |
98 | u32 spissr; /* SPI Slave Select Register (SPISSR) */ | |
99 | u32 spitfor; /* SPI Transmit FIFO Occupancy Register (SPITFOR) */ | |
100 | u32 spirfor; /* SPI Receive FIFO Occupancy Register (SPIRFOR) */ | |
101 | }; | |
102 | ||
9505c36e JT |
103 | /* xilinx spi priv */ |
104 | struct xilinx_spi_priv { | |
105 | struct xilinx_spi_regs *regs; | |
f93542a8 JT |
106 | unsigned int freq; |
107 | unsigned int mode; | |
0c0de58f | 108 | unsigned int fifo_depth; |
83ce6469 | 109 | u8 startup; |
f93542a8 JT |
110 | }; |
111 | ||
9505c36e | 112 | static int xilinx_spi_probe(struct udevice *bus) |
09aac75e | 113 | { |
9505c36e | 114 | struct xilinx_spi_priv *priv = dev_get_priv(bus); |
4fffbc11 | 115 | struct xilinx_spi_regs *regs; |
09aac75e | 116 | |
4fffbc11 | 117 | regs = priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus); |
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 | |
f2dd6599 KR |
122 | /* |
123 | * Reset RX & TX FIFO | |
124 | * Enable Manual Slave Select Assertion, | |
125 | * Set SPI controller into master mode, and enable it | |
126 | */ | |
127 | writel(SPICR_RXFIFO_RESEST | SPICR_TXFIFO_RESEST | | |
128 | SPICR_MANUAL_SS | SPICR_MASTER_MODE | SPICR_SPE, | |
129 | ®s->spicr); | |
130 | ||
9505c36e | 131 | return 0; |
09aac75e SL |
132 | } |
133 | ||
9505c36e | 134 | static void spi_cs_activate(struct udevice *dev, uint cs) |
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_ACT(cs), ®s->spissr); |
09aac75e SL |
141 | } |
142 | ||
9505c36e | 143 | static void spi_cs_deactivate(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; | |
f2dd6599 | 148 | u32 reg; |
09aac75e | 149 | |
f2dd6599 KR |
150 | reg = readl(®s->spicr) | SPICR_RXFIFO_RESEST | SPICR_TXFIFO_RESEST; |
151 | writel(reg, ®s->spicr); | |
9505c36e | 152 | writel(SPISSR_OFF, ®s->spissr); |
09aac75e SL |
153 | } |
154 | ||
9505c36e | 155 | static int xilinx_spi_claim_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_ON, ®s->spicr); | |
09aac75e | 163 | |
09aac75e SL |
164 | return 0; |
165 | } | |
166 | ||
9505c36e | 167 | static int xilinx_spi_release_bus(struct udevice *dev) |
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; | |
09aac75e | 172 | |
9505c36e JT |
173 | writel(SPISSR_OFF, ®s->spissr); |
174 | writel(XILSPI_SPICR_DFLT_OFF, ®s->spicr); | |
175 | ||
176 | return 0; | |
09aac75e SL |
177 | } |
178 | ||
0c0de58f VK |
179 | static u32 xilinx_spi_fill_txfifo(struct udevice *bus, const u8 *txp, |
180 | u32 txbytes) | |
181 | { | |
182 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
183 | struct xilinx_spi_regs *regs = priv->regs; | |
184 | unsigned char d; | |
185 | u32 i = 0; | |
186 | ||
187 | while (txbytes && !(readl(®s->spisr) & SPISR_TX_FULL) && | |
188 | i < priv->fifo_depth) { | |
f44bd3bc | 189 | d = txp ? *txp++ : XILINX_SPI_IDLE_VAL; |
0c0de58f VK |
190 | debug("spi_xfer: tx:%x ", d); |
191 | /* write out and wait for processing (receive data) */ | |
192 | writel(d & SPIDTR_8BIT_MASK, ®s->spidtr); | |
193 | txbytes--; | |
194 | i++; | |
195 | } | |
196 | ||
197 | return i; | |
198 | } | |
199 | ||
200 | static u32 xilinx_spi_read_rxfifo(struct udevice *bus, u8 *rxp, u32 rxbytes) | |
201 | { | |
202 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
203 | struct xilinx_spi_regs *regs = priv->regs; | |
204 | unsigned char d; | |
205 | unsigned int i = 0; | |
206 | ||
207 | while (rxbytes && !(readl(®s->spisr) & SPISR_RX_EMPTY)) { | |
208 | d = readl(®s->spidrr) & SPIDRR_8BIT_MASK; | |
209 | if (rxp) | |
210 | *rxp++ = d; | |
211 | debug("spi_xfer: rx:%x\n", d); | |
212 | rxbytes--; | |
213 | i++; | |
214 | } | |
215 | debug("Rx_done\n"); | |
216 | ||
217 | return i; | |
218 | } | |
219 | ||
f2dd6599 | 220 | static int start_transfer(struct spi_slave *spi, const void *dout, void *din, u32 len) |
83ce6469 | 221 | { |
f2dd6599 | 222 | struct udevice *bus = spi->dev->parent; |
83ce6469 VK |
223 | struct xilinx_spi_priv *priv = dev_get_priv(bus); |
224 | struct xilinx_spi_regs *regs = priv->regs; | |
f2dd6599 KR |
225 | u32 count, txbytes, rxbytes; |
226 | int reg, ret; | |
227 | const unsigned char *txp = (const unsigned char *)dout; | |
228 | unsigned char *rxp = (unsigned char *)din; | |
229 | ||
230 | txbytes = len; | |
231 | rxbytes = len; | |
232 | while (txbytes || rxbytes) { | |
233 | /* Disable master transaction */ | |
234 | reg = readl(®s->spicr) | SPICR_MASTER_INHIBIT; | |
83ce6469 | 235 | writel(reg, ®s->spicr); |
0c0de58f | 236 | count = xilinx_spi_fill_txfifo(bus, txp, txbytes); |
f2dd6599 | 237 | /* Enable master transaction */ |
0c0de58f VK |
238 | reg = readl(®s->spicr) & ~SPICR_MASTER_INHIBIT; |
239 | writel(reg, ®s->spicr); | |
240 | txbytes -= count; | |
241 | if (txp) | |
242 | txp += count; | |
09aac75e | 243 | |
0c0de58f VK |
244 | ret = wait_for_bit_le32(®s->spisr, SPISR_TX_EMPTY, true, |
245 | XILINX_SPISR_TIMEOUT, false); | |
246 | if (ret < 0) { | |
a7b6ef05 | 247 | printf("XILSPI error: Xfer timeout\n"); |
0c0de58f | 248 | return ret; |
09aac75e SL |
249 | } |
250 | ||
f2dd6599 KR |
251 | reg = readl(®s->spicr) | SPICR_MASTER_INHIBIT; |
252 | writel(reg, ®s->spicr); | |
0c0de58f VK |
253 | count = xilinx_spi_read_rxfifo(bus, rxp, rxbytes); |
254 | rxbytes -= count; | |
09aac75e | 255 | if (rxp) |
0c0de58f | 256 | rxp += count; |
09aac75e SL |
257 | } |
258 | ||
09aac75e SL |
259 | return 0; |
260 | } | |
9505c36e | 261 | |
f2dd6599 KR |
262 | static void xilinx_spi_startup_block(struct spi_slave *spi) |
263 | { | |
264 | struct dm_spi_slave_plat *slave_plat = | |
265 | dev_get_parent_plat(spi->dev); | |
266 | unsigned char txp; | |
267 | unsigned char rxp[8]; | |
268 | ||
269 | /* | |
270 | * Perform a dummy read as a work around for | |
271 | * the startup block issue. | |
272 | */ | |
273 | spi_cs_activate(spi->dev, slave_plat->cs); | |
274 | txp = 0x9f; | |
275 | start_transfer(spi, (void *)&txp, NULL, 1); | |
276 | ||
277 | start_transfer(spi, NULL, (void *)rxp, 6); | |
278 | ||
279 | spi_cs_deactivate(spi->dev); | |
280 | } | |
281 | ||
282 | static int xilinx_spi_mem_exec_op(struct spi_slave *spi, | |
283 | const struct spi_mem_op *op) | |
284 | { | |
285 | struct dm_spi_slave_plat *slave_plat = | |
286 | dev_get_parent_plat(spi->dev); | |
287 | static u32 startup; | |
288 | u32 dummy_len, ret; | |
289 | ||
290 | /* | |
291 | * This is the work around for the startup block issue in | |
292 | * the spi controller. SPI clock is passing through STARTUP | |
293 | * block to FLASH. STARTUP block don't provide clock as soon | |
294 | * as QSPI provides command. So first command fails. | |
295 | */ | |
296 | if (!startup) { | |
297 | xilinx_spi_startup_block(spi); | |
298 | startup++; | |
299 | } | |
300 | ||
301 | spi_cs_activate(spi->dev, slave_plat->cs); | |
302 | ||
303 | if (op->cmd.opcode) { | |
304 | ret = start_transfer(spi, (void *)&op->cmd.opcode, NULL, 1); | |
305 | if (ret) | |
306 | goto done; | |
307 | } | |
308 | if (op->addr.nbytes) { | |
309 | int i; | |
310 | u8 addr_buf[4]; | |
311 | ||
312 | for (i = 0; i < op->addr.nbytes; i++) | |
313 | addr_buf[i] = op->addr.val >> | |
314 | (8 * (op->addr.nbytes - i - 1)); | |
315 | ||
316 | ret = start_transfer(spi, (void *)addr_buf, NULL, | |
317 | op->addr.nbytes); | |
318 | if (ret) | |
319 | goto done; | |
320 | } | |
321 | if (op->dummy.nbytes) { | |
557832bd KR |
322 | dummy_len = (op->dummy.nbytes * op->data.buswidth) / |
323 | op->dummy.buswidth; | |
324 | ||
f2dd6599 KR |
325 | ret = start_transfer(spi, NULL, NULL, dummy_len); |
326 | if (ret) | |
327 | goto done; | |
328 | } | |
329 | if (op->data.nbytes) { | |
330 | if (op->data.dir == SPI_MEM_DATA_IN) { | |
331 | ret = start_transfer(spi, NULL, | |
332 | op->data.buf.in, op->data.nbytes); | |
333 | } else { | |
334 | ret = start_transfer(spi, op->data.buf.out, | |
335 | NULL, op->data.nbytes); | |
336 | } | |
337 | if (ret) | |
338 | goto done; | |
339 | } | |
340 | done: | |
341 | spi_cs_deactivate(spi->dev); | |
342 | ||
343 | return ret; | |
344 | } | |
345 | ||
557832bd KR |
346 | static int xilinx_qspi_check_buswidth(struct spi_slave *slave, u8 width) |
347 | { | |
348 | u32 mode = slave->mode; | |
349 | ||
350 | switch (width) { | |
351 | case 1: | |
352 | return 0; | |
353 | case 2: | |
354 | if (mode & SPI_RX_DUAL) | |
355 | return 0; | |
356 | break; | |
357 | case 4: | |
358 | if (mode & SPI_RX_QUAD) | |
359 | return 0; | |
360 | break; | |
361 | } | |
362 | ||
363 | return -EOPNOTSUPP; | |
364 | } | |
365 | ||
366 | bool xilinx_qspi_mem_exec_op(struct spi_slave *slave, | |
367 | const struct spi_mem_op *op) | |
368 | { | |
369 | if (xilinx_qspi_check_buswidth(slave, op->cmd.buswidth)) | |
370 | return false; | |
371 | ||
372 | if (op->addr.nbytes && | |
373 | xilinx_qspi_check_buswidth(slave, op->addr.buswidth)) | |
374 | return false; | |
375 | ||
376 | if (op->dummy.nbytes && | |
377 | xilinx_qspi_check_buswidth(slave, op->dummy.buswidth)) | |
378 | return false; | |
379 | ||
380 | if (op->data.dir != SPI_MEM_NO_DATA && | |
381 | xilinx_qspi_check_buswidth(slave, op->data.buswidth)) | |
382 | return false; | |
383 | ||
384 | return true; | |
385 | } | |
386 | ||
9505c36e JT |
387 | static int xilinx_spi_set_speed(struct udevice *bus, uint speed) |
388 | { | |
389 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
390 | ||
391 | priv->freq = speed; | |
392 | ||
d999a7b7 | 393 | debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq); |
9505c36e JT |
394 | |
395 | return 0; | |
396 | } | |
397 | ||
398 | static int xilinx_spi_set_mode(struct udevice *bus, uint mode) | |
399 | { | |
400 | struct xilinx_spi_priv *priv = dev_get_priv(bus); | |
401 | struct xilinx_spi_regs *regs = priv->regs; | |
d999a7b7 | 402 | u32 spicr; |
9505c36e JT |
403 | |
404 | spicr = readl(®s->spicr); | |
d5f60737 | 405 | if (mode & SPI_LSB_FIRST) |
9505c36e | 406 | spicr |= SPICR_LSB_FIRST; |
d5f60737 | 407 | if (mode & SPI_CPHA) |
9505c36e | 408 | spicr |= SPICR_CPHA; |
d5f60737 | 409 | if (mode & SPI_CPOL) |
9505c36e | 410 | spicr |= SPICR_CPOL; |
d5f60737 | 411 | if (mode & SPI_LOOP) |
9505c36e JT |
412 | spicr |= SPICR_LOOP; |
413 | ||
414 | writel(spicr, ®s->spicr); | |
415 | priv->mode = mode; | |
416 | ||
d999a7b7 | 417 | debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode); |
9505c36e JT |
418 | |
419 | return 0; | |
420 | } | |
421 | ||
f2dd6599 KR |
422 | static const struct spi_controller_mem_ops xilinx_spi_mem_ops = { |
423 | .exec_op = xilinx_spi_mem_exec_op, | |
557832bd | 424 | .supports_op = xilinx_qspi_mem_exec_op, |
f2dd6599 KR |
425 | }; |
426 | ||
9505c36e JT |
427 | static const struct dm_spi_ops xilinx_spi_ops = { |
428 | .claim_bus = xilinx_spi_claim_bus, | |
429 | .release_bus = xilinx_spi_release_bus, | |
9505c36e JT |
430 | .set_speed = xilinx_spi_set_speed, |
431 | .set_mode = xilinx_spi_set_mode, | |
f2dd6599 | 432 | .mem_ops = &xilinx_spi_mem_ops, |
9505c36e JT |
433 | }; |
434 | ||
435 | static const struct udevice_id xilinx_spi_ids[] = { | |
76de51a6 MS |
436 | { .compatible = "xlnx,xps-spi-2.00.a" }, |
437 | { .compatible = "xlnx,xps-spi-2.00.b" }, | |
9505c36e JT |
438 | { } |
439 | }; | |
440 | ||
441 | U_BOOT_DRIVER(xilinx_spi) = { | |
442 | .name = "xilinx_spi", | |
443 | .id = UCLASS_SPI, | |
444 | .of_match = xilinx_spi_ids, | |
445 | .ops = &xilinx_spi_ops, | |
41575d8e | 446 | .priv_auto = sizeof(struct xilinx_spi_priv), |
9505c36e JT |
447 | .probe = xilinx_spi_probe, |
448 | }; |