xref: /rk3399_rockchip-uboot/drivers/spi/tegra20_sflash.c (revision 6b3a03e112cecda55b58f3de40f4fc760159979b)
1ff1da6fbSAllen Martin /*
2*6b3a03e1SAllen Martin  * Copyright (c) 2010-2013 NVIDIA Corporation
3ff1da6fbSAllen Martin  * With help from the mpc8xxx SPI driver
4ff1da6fbSAllen Martin  * With more help from omap3_spi SPI driver
5ff1da6fbSAllen Martin  *
6ff1da6fbSAllen Martin  * See file CREDITS for list of people who contributed to this
7ff1da6fbSAllen Martin  * project.
8ff1da6fbSAllen Martin  *
9ff1da6fbSAllen Martin  * This program is free software; you can redistribute it and/or
10ff1da6fbSAllen Martin  * modify it under the terms of the GNU General Public License as
11ff1da6fbSAllen Martin  * published by the Free Software Foundation; either version 2 of
12ff1da6fbSAllen Martin  * the License, or (at your option) any later version.
13ff1da6fbSAllen Martin  *
14ff1da6fbSAllen Martin  * This program is distributed in the hope that it will be useful,
15ff1da6fbSAllen Martin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16ff1da6fbSAllen Martin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17ff1da6fbSAllen Martin  * GNU General Public License for more details.
18ff1da6fbSAllen Martin  *
19ff1da6fbSAllen Martin  * You should have received a copy of the GNU General Public License
20ff1da6fbSAllen Martin  * along with this program; if not, write to the Free Software
21ff1da6fbSAllen Martin  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22ff1da6fbSAllen Martin  * MA 02111-1307 USA
23ff1da6fbSAllen Martin  */
24ff1da6fbSAllen Martin 
25ff1da6fbSAllen Martin #include <common.h>
26ff1da6fbSAllen Martin #include <malloc.h>
27ff1da6fbSAllen Martin #include <asm/io.h>
28ff1da6fbSAllen Martin #include <asm/gpio.h>
29ff1da6fbSAllen Martin #include <asm/arch/clock.h>
30ff1da6fbSAllen Martin #include <asm/arch/pinmux.h>
31ff1da6fbSAllen Martin #include <asm/arch-tegra/clk_rst.h>
32ff1da6fbSAllen Martin #include <asm/arch-tegra20/tegra20_sflash.h>
33ff1da6fbSAllen Martin #include <spi.h>
34ff1da6fbSAllen Martin #include <fdtdec.h>
35ff1da6fbSAllen Martin 
36ff1da6fbSAllen Martin DECLARE_GLOBAL_DATA_PTR;
37ff1da6fbSAllen Martin 
387a49ba6eSAllen Martin #define SPI_CMD_GO			(1 << 30)
397a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_SHIFT	26
407a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SCLK_MASK	(3 << SPI_CMD_ACTIVE_SCLK_SHIFT)
417a49ba6eSAllen Martin #define SPI_CMD_CK_SDA			(1 << 21)
427a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_SHIFT	18
437a49ba6eSAllen Martin #define SPI_CMD_ACTIVE_SDA_MASK		(3 << SPI_CMD_ACTIVE_SDA_SHIFT)
447a49ba6eSAllen Martin #define SPI_CMD_CS_POL			(1 << 16)
457a49ba6eSAllen Martin #define SPI_CMD_TXEN			(1 << 15)
467a49ba6eSAllen Martin #define SPI_CMD_RXEN			(1 << 14)
477a49ba6eSAllen Martin #define SPI_CMD_CS_VAL			(1 << 13)
487a49ba6eSAllen Martin #define SPI_CMD_CS_SOFT			(1 << 12)
497a49ba6eSAllen Martin #define SPI_CMD_CS_DELAY		(1 << 9)
507a49ba6eSAllen Martin #define SPI_CMD_CS3_EN			(1 << 8)
517a49ba6eSAllen Martin #define SPI_CMD_CS2_EN			(1 << 7)
527a49ba6eSAllen Martin #define SPI_CMD_CS1_EN			(1 << 6)
537a49ba6eSAllen Martin #define SPI_CMD_CS0_EN			(1 << 5)
547a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH		(1 << 4)
557a49ba6eSAllen Martin #define SPI_CMD_BIT_LENGTH_MASK		0x0000001F
567a49ba6eSAllen Martin 
577a49ba6eSAllen Martin #define SPI_STAT_BSY			(1 << 31)
587a49ba6eSAllen Martin #define SPI_STAT_RDY			(1 << 30)
597a49ba6eSAllen Martin #define SPI_STAT_RXF_FLUSH		(1 << 29)
607a49ba6eSAllen Martin #define SPI_STAT_TXF_FLUSH		(1 << 28)
617a49ba6eSAllen Martin #define SPI_STAT_RXF_UNR		(1 << 27)
627a49ba6eSAllen Martin #define SPI_STAT_TXF_OVF		(1 << 26)
637a49ba6eSAllen Martin #define SPI_STAT_RXF_EMPTY		(1 << 25)
647a49ba6eSAllen Martin #define SPI_STAT_RXF_FULL		(1 << 24)
657a49ba6eSAllen Martin #define SPI_STAT_TXF_EMPTY		(1 << 23)
667a49ba6eSAllen Martin #define SPI_STAT_TXF_FULL		(1 << 22)
677a49ba6eSAllen Martin #define SPI_STAT_SEL_TXRX_N		(1 << 16)
687a49ba6eSAllen Martin #define SPI_STAT_CUR_BLKCNT		(1 << 15)
697a49ba6eSAllen Martin 
707a49ba6eSAllen Martin #define SPI_TIMEOUT		1000
717a49ba6eSAllen Martin #define TEGRA_SPI_MAX_FREQ	52000000
727a49ba6eSAllen Martin 
737a49ba6eSAllen Martin struct spi_regs {
747a49ba6eSAllen Martin 	u32 command;	/* SPI_COMMAND_0 register  */
757a49ba6eSAllen Martin 	u32 status;	/* SPI_STATUS_0 register */
767a49ba6eSAllen Martin 	u32 rx_cmp;	/* SPI_RX_CMP_0 register  */
777a49ba6eSAllen Martin 	u32 dma_ctl;	/* SPI_DMA_CTL_0 register */
787a49ba6eSAllen Martin 	u32 tx_fifo;	/* SPI_TX_FIFO_0 register */
797a49ba6eSAllen Martin 	u32 rsvd[3];	/* offsets 0x14 to 0x1F reserved */
807a49ba6eSAllen Martin 	u32 rx_fifo;	/* SPI_RX_FIFO_0 register */
817a49ba6eSAllen Martin };
827a49ba6eSAllen Martin 
83*6b3a03e1SAllen Martin struct tegra_spi_ctrl {
847a49ba6eSAllen Martin 	struct spi_regs *regs;
85ff1da6fbSAllen Martin 	unsigned int freq;
86ff1da6fbSAllen Martin 	unsigned int mode;
87ff1da6fbSAllen Martin 	int periph_id;
88*6b3a03e1SAllen Martin 	int valid;
89ff1da6fbSAllen Martin };
90ff1da6fbSAllen Martin 
91*6b3a03e1SAllen Martin struct tegra_spi_slave {
92*6b3a03e1SAllen Martin 	struct spi_slave slave;
93*6b3a03e1SAllen Martin 	struct tegra_spi_ctrl *ctrl;
94*6b3a03e1SAllen Martin };
95*6b3a03e1SAllen Martin 
96*6b3a03e1SAllen Martin /* tegra20 only supports one SFLASH controller */
97*6b3a03e1SAllen Martin static struct tegra_spi_ctrl spi_ctrls[1];
98*6b3a03e1SAllen Martin 
99ff1da6fbSAllen Martin static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
100ff1da6fbSAllen Martin {
101ff1da6fbSAllen Martin 	return container_of(slave, struct tegra_spi_slave, slave);
102ff1da6fbSAllen Martin }
103ff1da6fbSAllen Martin 
104ff1da6fbSAllen Martin int spi_cs_is_valid(unsigned int bus, unsigned int cs)
105ff1da6fbSAllen Martin {
106ff1da6fbSAllen Martin 	/* Tegra20 SPI-Flash - only 1 device ('bus/cs') */
107ff1da6fbSAllen Martin 	if (bus != 0 || cs != 0)
108ff1da6fbSAllen Martin 		return 0;
109ff1da6fbSAllen Martin 	else
110ff1da6fbSAllen Martin 		return 1;
111ff1da6fbSAllen Martin }
112ff1da6fbSAllen Martin 
113ff1da6fbSAllen Martin struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
114ff1da6fbSAllen Martin 		unsigned int max_hz, unsigned int mode)
115ff1da6fbSAllen Martin {
116ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi;
117ff1da6fbSAllen Martin 
118ff1da6fbSAllen Martin 	if (!spi_cs_is_valid(bus, cs)) {
119ff1da6fbSAllen Martin 		printf("SPI error: unsupported bus %d / chip select %d\n",
120ff1da6fbSAllen Martin 		       bus, cs);
121ff1da6fbSAllen Martin 		return NULL;
122ff1da6fbSAllen Martin 	}
123ff1da6fbSAllen Martin 
124ff1da6fbSAllen Martin 	if (max_hz > TEGRA_SPI_MAX_FREQ) {
125ff1da6fbSAllen Martin 		printf("SPI error: unsupported frequency %d Hz. Max frequency"
126ff1da6fbSAllen Martin 			" is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
127ff1da6fbSAllen Martin 		return NULL;
128ff1da6fbSAllen Martin 	}
129ff1da6fbSAllen Martin 
130ff1da6fbSAllen Martin 	spi = malloc(sizeof(struct tegra_spi_slave));
131ff1da6fbSAllen Martin 	if (!spi) {
132ff1da6fbSAllen Martin 		printf("SPI error: malloc of SPI structure failed\n");
133ff1da6fbSAllen Martin 		return NULL;
134ff1da6fbSAllen Martin 	}
135ff1da6fbSAllen Martin 	spi->slave.bus = bus;
136ff1da6fbSAllen Martin 	spi->slave.cs = cs;
137*6b3a03e1SAllen Martin 	spi->ctrl = &spi_ctrls[bus];
138*6b3a03e1SAllen Martin 	if (!spi->ctrl) {
139*6b3a03e1SAllen Martin 		printf("SPI error: could not find controller for bus %d\n",
140*6b3a03e1SAllen Martin 		       bus);
141*6b3a03e1SAllen Martin 		return NULL;
142*6b3a03e1SAllen Martin 	}
1432a3c5bc2SAllen Martin 
144*6b3a03e1SAllen Martin 	if (max_hz < spi->ctrl->freq) {
145ff1da6fbSAllen Martin 		debug("%s: limiting frequency from %u to %u\n", __func__,
146*6b3a03e1SAllen Martin 		      spi->ctrl->freq, max_hz);
147*6b3a03e1SAllen Martin 		spi->ctrl->freq = max_hz;
148ff1da6fbSAllen Martin 	}
149*6b3a03e1SAllen Martin 	spi->ctrl->mode = mode;
150ff1da6fbSAllen Martin 
151ff1da6fbSAllen Martin 	return &spi->slave;
152ff1da6fbSAllen Martin }
153ff1da6fbSAllen Martin 
154ff1da6fbSAllen Martin void spi_free_slave(struct spi_slave *slave)
155ff1da6fbSAllen Martin {
156ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi = to_tegra_spi(slave);
157ff1da6fbSAllen Martin 
158ff1da6fbSAllen Martin 	free(spi);
159ff1da6fbSAllen Martin }
160ff1da6fbSAllen Martin 
161ff1da6fbSAllen Martin void spi_init(void)
162ff1da6fbSAllen Martin {
163*6b3a03e1SAllen Martin 	struct tegra_spi_ctrl *ctrl;
164*6b3a03e1SAllen Martin 	int i;
165*6b3a03e1SAllen Martin 	int node = 0;
166*6b3a03e1SAllen Martin 	int count;
167*6b3a03e1SAllen Martin 	int node_list[1];
168*6b3a03e1SAllen Martin 
169*6b3a03e1SAllen Martin 	count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi",
170*6b3a03e1SAllen Martin 					   COMPAT_NVIDIA_TEGRA20_SFLASH,
171*6b3a03e1SAllen Martin 					   node_list,
172*6b3a03e1SAllen Martin 					   1);
173*6b3a03e1SAllen Martin 	for (i = 0; i < count; i++) {
174*6b3a03e1SAllen Martin 		ctrl = &spi_ctrls[i];
175*6b3a03e1SAllen Martin 		node = node_list[i];
176*6b3a03e1SAllen Martin 
177*6b3a03e1SAllen Martin 		ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
178*6b3a03e1SAllen Martin 								node, "reg");
179*6b3a03e1SAllen Martin 		if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
180*6b3a03e1SAllen Martin 			debug("%s: no slink register found\n", __func__);
181*6b3a03e1SAllen Martin 			continue;
182*6b3a03e1SAllen Martin 		}
183*6b3a03e1SAllen Martin 		ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
184*6b3a03e1SAllen Martin 					    "spi-max-frequency", 0);
185*6b3a03e1SAllen Martin 		if (!ctrl->freq) {
186*6b3a03e1SAllen Martin 			debug("%s: no slink max frequency found\n", __func__);
187*6b3a03e1SAllen Martin 			continue;
188*6b3a03e1SAllen Martin 		}
189*6b3a03e1SAllen Martin 
190*6b3a03e1SAllen Martin 		ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
191*6b3a03e1SAllen Martin 		if (ctrl->periph_id == PERIPH_ID_NONE) {
192*6b3a03e1SAllen Martin 			debug("%s: could not decode periph id\n", __func__);
193*6b3a03e1SAllen Martin 			continue;
194*6b3a03e1SAllen Martin 		}
195*6b3a03e1SAllen Martin 		ctrl->valid = 1;
196*6b3a03e1SAllen Martin 
197*6b3a03e1SAllen Martin 		debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
198*6b3a03e1SAllen Martin 		      __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
199*6b3a03e1SAllen Martin 	}
200ff1da6fbSAllen Martin }
201ff1da6fbSAllen Martin 
202ff1da6fbSAllen Martin int spi_claim_bus(struct spi_slave *slave)
203ff1da6fbSAllen Martin {
204ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi = to_tegra_spi(slave);
205*6b3a03e1SAllen Martin 	struct spi_regs *regs = spi->ctrl->regs;
206ff1da6fbSAllen Martin 	u32 reg;
207ff1da6fbSAllen Martin 
208ff1da6fbSAllen Martin 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
209*6b3a03e1SAllen Martin 	clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
210*6b3a03e1SAllen Martin 			       spi->ctrl->freq);
211ff1da6fbSAllen Martin 
212ff1da6fbSAllen Martin 	/* Clear stale status here */
213ff1da6fbSAllen Martin 	reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
214ff1da6fbSAllen Martin 		SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF;
215ff1da6fbSAllen Martin 	writel(reg, &regs->status);
216ff1da6fbSAllen Martin 	debug("spi_init: STATUS = %08x\n", readl(&regs->status));
217ff1da6fbSAllen Martin 
218ff1da6fbSAllen Martin 	/*
219ff1da6fbSAllen Martin 	 * Use sw-controlled CS, so we can clock in data after ReadID, etc.
220ff1da6fbSAllen Martin 	 */
221*6b3a03e1SAllen Martin 	reg = (spi->ctrl->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
222*6b3a03e1SAllen Martin 	if (spi->ctrl->mode & 2)
223ff1da6fbSAllen Martin 		reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT;
224ff1da6fbSAllen Martin 	clrsetbits_le32(&regs->command, SPI_CMD_ACTIVE_SCLK_MASK |
225ff1da6fbSAllen Martin 		SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg);
226ff1da6fbSAllen Martin 	debug("spi_init: COMMAND = %08x\n", readl(&regs->command));
227ff1da6fbSAllen Martin 
228ff1da6fbSAllen Martin 	/*
229ff1da6fbSAllen Martin 	 * SPI pins on Tegra20 are muxed - change pinmux later due to UART
230ff1da6fbSAllen Martin 	 * issue.
231ff1da6fbSAllen Martin 	 */
232ff1da6fbSAllen Martin 	pinmux_set_func(PINGRP_GMD, PMUX_FUNC_SFLASH);
233ff1da6fbSAllen Martin 	pinmux_tristate_disable(PINGRP_LSPI);
234ff1da6fbSAllen Martin 	pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH);
235ff1da6fbSAllen Martin 
236ff1da6fbSAllen Martin 	return 0;
237ff1da6fbSAllen Martin }
238ff1da6fbSAllen Martin 
239ff1da6fbSAllen Martin void spi_release_bus(struct spi_slave *slave)
240ff1da6fbSAllen Martin {
241ff1da6fbSAllen Martin 	/*
242ff1da6fbSAllen Martin 	 * We can't release UART_DISABLE and set pinmux to UART4 here since
243ff1da6fbSAllen Martin 	 * some code (e,g, spi_flash_probe) uses printf() while the SPI
244ff1da6fbSAllen Martin 	 * bus is held. That is arguably bad, but it has the advantage of
245ff1da6fbSAllen Martin 	 * already being in the source tree.
246ff1da6fbSAllen Martin 	 */
247ff1da6fbSAllen Martin }
248ff1da6fbSAllen Martin 
249ff1da6fbSAllen Martin void spi_cs_activate(struct spi_slave *slave)
250ff1da6fbSAllen Martin {
251ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi = to_tegra_spi(slave);
252*6b3a03e1SAllen Martin 	struct spi_regs *regs = spi->ctrl->regs;
253ff1da6fbSAllen Martin 
254ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 1 to get a 0 */
255*6b3a03e1SAllen Martin 	setbits_le32(&regs->command, SPI_CMD_CS_VAL);
256ff1da6fbSAllen Martin }
257ff1da6fbSAllen Martin 
258ff1da6fbSAllen Martin void spi_cs_deactivate(struct spi_slave *slave)
259ff1da6fbSAllen Martin {
260ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi = to_tegra_spi(slave);
261*6b3a03e1SAllen Martin 	struct spi_regs *regs = spi->ctrl->regs;
262ff1da6fbSAllen Martin 
263ff1da6fbSAllen Martin 	/* CS is negated on Tegra, so drive a 0 to get a 1 */
264*6b3a03e1SAllen Martin 	clrbits_le32(&regs->command, SPI_CMD_CS_VAL);
265ff1da6fbSAllen Martin }
266ff1da6fbSAllen Martin 
267ff1da6fbSAllen Martin int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
268ff1da6fbSAllen Martin 		const void *data_out, void *data_in, unsigned long flags)
269ff1da6fbSAllen Martin {
270ff1da6fbSAllen Martin 	struct tegra_spi_slave *spi = to_tegra_spi(slave);
271*6b3a03e1SAllen Martin 	struct spi_regs *regs = spi->ctrl->regs;
272ff1da6fbSAllen Martin 	u32 reg, tmpdout, tmpdin = 0;
273ff1da6fbSAllen Martin 	const u8 *dout = data_out;
274ff1da6fbSAllen Martin 	u8 *din = data_in;
275ff1da6fbSAllen Martin 	int num_bytes;
276ff1da6fbSAllen Martin 	int ret;
277ff1da6fbSAllen Martin 
278ff1da6fbSAllen Martin 	debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
279ff1da6fbSAllen Martin 	      slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen);
280ff1da6fbSAllen Martin 	if (bitlen % 8)
281ff1da6fbSAllen Martin 		return -1;
282ff1da6fbSAllen Martin 	num_bytes = bitlen / 8;
283ff1da6fbSAllen Martin 
284ff1da6fbSAllen Martin 	ret = 0;
285ff1da6fbSAllen Martin 
286ff1da6fbSAllen Martin 	reg = readl(&regs->status);
287ff1da6fbSAllen Martin 	writel(reg, &regs->status);	/* Clear all SPI events via R/W */
288ff1da6fbSAllen Martin 	debug("spi_xfer entry: STATUS = %08x\n", reg);
289ff1da6fbSAllen Martin 
290ff1da6fbSAllen Martin 	reg = readl(&regs->command);
291ff1da6fbSAllen Martin 	reg |= SPI_CMD_TXEN | SPI_CMD_RXEN;
292ff1da6fbSAllen Martin 	writel(reg, &regs->command);
293ff1da6fbSAllen Martin 	debug("spi_xfer: COMMAND = %08x\n", readl(&regs->command));
294ff1da6fbSAllen Martin 
295ff1da6fbSAllen Martin 	if (flags & SPI_XFER_BEGIN)
296ff1da6fbSAllen Martin 		spi_cs_activate(slave);
297ff1da6fbSAllen Martin 
298ff1da6fbSAllen Martin 	/* handle data in 32-bit chunks */
299ff1da6fbSAllen Martin 	while (num_bytes > 0) {
300ff1da6fbSAllen Martin 		int bytes;
301ff1da6fbSAllen Martin 		int is_read = 0;
302ff1da6fbSAllen Martin 		int tm, i;
303ff1da6fbSAllen Martin 
304ff1da6fbSAllen Martin 		tmpdout = 0;
305ff1da6fbSAllen Martin 		bytes = (num_bytes > 4) ?  4 : num_bytes;
306ff1da6fbSAllen Martin 
307ff1da6fbSAllen Martin 		if (dout != NULL) {
308ff1da6fbSAllen Martin 			for (i = 0; i < bytes; ++i)
309ff1da6fbSAllen Martin 				tmpdout = (tmpdout << 8) | dout[i];
310ff1da6fbSAllen Martin 		}
311ff1da6fbSAllen Martin 
312ff1da6fbSAllen Martin 		num_bytes -= bytes;
313ff1da6fbSAllen Martin 		if (dout)
314ff1da6fbSAllen Martin 			dout += bytes;
315ff1da6fbSAllen Martin 
316ff1da6fbSAllen Martin 		clrsetbits_le32(&regs->command, SPI_CMD_BIT_LENGTH_MASK,
317ff1da6fbSAllen Martin 				bytes * 8 - 1);
318ff1da6fbSAllen Martin 		writel(tmpdout, &regs->tx_fifo);
319ff1da6fbSAllen Martin 		setbits_le32(&regs->command, SPI_CMD_GO);
320ff1da6fbSAllen Martin 
321ff1da6fbSAllen Martin 		/*
322ff1da6fbSAllen Martin 		 * Wait for SPI transmit FIFO to empty, or to time out.
323ff1da6fbSAllen Martin 		 * The RX FIFO status will be read and cleared last
324ff1da6fbSAllen Martin 		 */
325ff1da6fbSAllen Martin 		for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) {
326ff1da6fbSAllen Martin 			u32 status;
327ff1da6fbSAllen Martin 
328ff1da6fbSAllen Martin 			status = readl(&regs->status);
329ff1da6fbSAllen Martin 
330ff1da6fbSAllen Martin 			/* We can exit when we've had both RX and TX activity */
331ff1da6fbSAllen Martin 			if (is_read && (status & SPI_STAT_TXF_EMPTY))
332ff1da6fbSAllen Martin 				break;
333ff1da6fbSAllen Martin 
334ff1da6fbSAllen Martin 			if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) !=
335ff1da6fbSAllen Martin 					SPI_STAT_RDY)
336ff1da6fbSAllen Martin 				tm++;
337ff1da6fbSAllen Martin 
338ff1da6fbSAllen Martin 			else if (!(status & SPI_STAT_RXF_EMPTY)) {
339ff1da6fbSAllen Martin 				tmpdin = readl(&regs->rx_fifo);
340ff1da6fbSAllen Martin 				is_read = 1;
341ff1da6fbSAllen Martin 
342ff1da6fbSAllen Martin 				/* swap bytes read in */
343ff1da6fbSAllen Martin 				if (din != NULL) {
344ff1da6fbSAllen Martin 					for (i = bytes - 1; i >= 0; --i) {
345ff1da6fbSAllen Martin 						din[i] = tmpdin & 0xff;
346ff1da6fbSAllen Martin 						tmpdin >>= 8;
347ff1da6fbSAllen Martin 					}
348ff1da6fbSAllen Martin 					din += bytes;
349ff1da6fbSAllen Martin 				}
350ff1da6fbSAllen Martin 			}
351ff1da6fbSAllen Martin 		}
352ff1da6fbSAllen Martin 
353ff1da6fbSAllen Martin 		if (tm >= SPI_TIMEOUT)
354ff1da6fbSAllen Martin 			ret = tm;
355ff1da6fbSAllen Martin 
356ff1da6fbSAllen Martin 		/* clear ACK RDY, etc. bits */
357ff1da6fbSAllen Martin 		writel(readl(&regs->status), &regs->status);
358ff1da6fbSAllen Martin 	}
359ff1da6fbSAllen Martin 
360ff1da6fbSAllen Martin 	if (flags & SPI_XFER_END)
361ff1da6fbSAllen Martin 		spi_cs_deactivate(slave);
362ff1da6fbSAllen Martin 
363ff1da6fbSAllen Martin 	debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n",
364ff1da6fbSAllen Martin 		tmpdin, readl(&regs->status));
365ff1da6fbSAllen Martin 
366ff1da6fbSAllen Martin 	if (ret) {
367ff1da6fbSAllen Martin 		printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret);
368ff1da6fbSAllen Martin 		return -1;
369ff1da6fbSAllen Martin 	}
370ff1da6fbSAllen Martin 
371ff1da6fbSAllen Martin 	return 0;
372ff1da6fbSAllen Martin }
373