Hi Wolfgang,
Thanks for your reply. I have a driver loosely based on the u-boot code, that works with my SPI flash in 4-bit mode with single byte transfers. However, I cannot get multi-byte transfers to work reliably. That is why I am wondering about the semantics of the FIFO_FULL and FIFO_EMPTY bits. Do they mean at least 1 byte or 1 word of space in the FIFO?
Hi,
clear read fifo, send as much bytes as you want to receive..
Single Byte - as documented - wait fifo empty, send byte, wait fifo empty(tx), read out received byte from data register.
As far as I reversed engineered it - you can write 4Bytes into the 32Bit output register to send... same is with receive.
If you look for the spansion multi i-o driver on this forum - there are the needed u-boot src files which support spi with more than one data line. Anyway, you can see a way how to use the fifo in polled mode there.
I wanted to boot my machine from spi reading 8MByte from SPI flash.
This took initial up to 30 seconds.
By tweaking the u-boot spi_xfer routine - I speeded up the process down to 8 seconds, loop unrolling, explicit encoding from r/w/rw situation, removed timeouts.... tweaked - but still single byte transfer.
==========================
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct mxs_spi_slave *mxs_slave = to_mxs_slave(slave);
struct mx28_ssp_regs *ssp_regs = mxs_slave->regs;
int len = bitlen / 8;
const char *tx = dout;
char *rx = din;
char dummy;
if (bitlen == 0) {
if (flags & SPI_XFER_END) {
rx = &dummy;
len = 1;
} else
return 0;
}
if (!rx && !tx)
return 0;
if (flags & SPI_XFER_BEGIN)
mxs_spi_start_xfer(ssp_regs);
writel(1, &ssp_regs->hw_ssp_xfer_size);
if(tx&&(!rx))
{
while(--len)
{
writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_clr);
writel(SSP_CTRL0_RUN, &ssp_regs->hw_ssp_ctrl0_set);
if (mx28_wait_mask_set(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for start\n");
return -ETIMEDOUT;
}
writel(*tx++, &ssp_regs->hw_ssp_data);
writel(SSP_CTRL0_DATA_XFER, &ssp_regs->hw_ssp_ctrl0_set);
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for finish\n");
return -ETIMEDOUT;
}
}
if(flags & SPI_XFER_END) mxs_spi_end_xfer(ssp_regs);
writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_clr);
writel(SSP_CTRL0_RUN, &ssp_regs->hw_ssp_ctrl0_set);
if (mx28_wait_mask_set(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for start\n");
return -ETIMEDOUT;
}
writel(*tx++, &ssp_regs->hw_ssp_data);
writel(SSP_CTRL0_DATA_XFER, &ssp_regs->hw_ssp_ctrl0_set);
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for finish\n");
return -ETIMEDOUT;
}
}
else if((!tx)&&rx)
{
while (--len)
{
while(readl(0x80014000)&SSP_CTRL0_RUN){}
writel(SSP_CTRL0_READ|SSP_CTRL0_RUN|SSP_CTRL0_DATA_XFER, 0x80014004/*&ssp_regs->hw_ssp_ctrl0_set*/);
while(readl(0x80014100)&SSP_STATUS_FIFO_EMPTY){}
*rx = readl(0x80014090);
rx++;
}
while(readl(0x80014000)&SSP_CTRL0_RUN){}
if (flags & SPI_XFER_END) mxs_spi_end_xfer(ssp_regs);
writel(SSP_CTRL0_READ|SSP_CTRL0_RUN|SSP_CTRL0_DATA_XFER, 0x80014004/*&ssp_regs->hw_ssp_ctrl0_set*/);
while(readl(0x80014100)&SSP_STATUS_FIFO_EMPTY){}
*rx = readl(0x80014090);
rx++;
}
else
{
while (len--) {
/* We transfer 1 byte */
if ((flags & SPI_XFER_END) && !len)
mxs_spi_end_xfer(ssp_regs);
if (tx)
writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_clr);
else
writel(SSP_CTRL0_READ, &ssp_regs->hw_ssp_ctrl0_set);
writel(SSP_CTRL0_RUN, &ssp_regs->hw_ssp_ctrl0_set);
if (mx28_wait_mask_set(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for start\n");
return -ETIMEDOUT;
}
if (tx)
writel(*tx++, &ssp_regs->hw_ssp_data);
writel(SSP_CTRL0_DATA_XFER, &ssp_regs->hw_ssp_ctrl0_set);
if (rx) {
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_status_reg,
SSP_STATUS_FIFO_EMPTY, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for data\n");
return -ETIMEDOUT;
}
*rx = readl(&ssp_regs->hw_ssp_data);
rx++;
}
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for finish\n");
return -ETIMEDOUT;
}
}
}
return 0;
}