DaVinci: Improve DaVinci SPI speed.

I have updated this patch based on the comments [1] by Wolfgang Denk and
removed unused variables.
[1][http://lists.denx.de/pipermail/u-boot/2010-May/071728.html]

Reduce the number of reads per byte transferred on the BUF register from 2 to 1 and
take advantage of the TX buffer in the SPI module. On LogicPD OMAP-L138 EVM,
SPI read throughput goes up from ~0.8Mbyte/s to ~1.3Mbyte/s. Tested with a 2Mbyte image file.
Remove unused variables in the spi_xfer() function.

Signed-off-by: Delio Brignoli <dbrignoli@audioscience.com>
Tested-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
This commit is contained in:
Delio Brignoli 2010-06-07 17:16:13 -04:00 committed by Tom
parent 1a5038ca68
commit 9268236529

View File

@ -113,7 +113,8 @@ int spi_claim_bus(struct spi_slave *slave)
writel(0, &ds->regs->lvl); writel(0, &ds->regs->lvl);
/* enable SPI */ /* enable SPI */
writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); writel((readl(&ds->regs->gcr1) |
SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
return 0; return 0;
} }
@ -131,12 +132,10 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
{ {
struct davinci_spi_slave *ds = to_davinci_spi(slave); struct davinci_spi_slave *ds = to_davinci_spi(slave);
unsigned int len, data1_reg_val = readl(&ds->regs->dat1); unsigned int len, data1_reg_val = readl(&ds->regs->dat1);
int ret, i; unsigned int i_cnt = 0, o_cnt = 0, buf_reg_val;
const u8 *txp = dout; /* dout can be NULL for read operation */ const u8 *txp = dout; /* dout can be NULL for read operation */
u8 *rxp = din; /* din can be NULL for write operation */ u8 *rxp = din; /* din can be NULL for write operation */
ret = 0;
if (bitlen == 0) if (bitlen == 0)
/* Finish any previously submitted transfers */ /* Finish any previously submitted transfers */
goto out; goto out;
@ -159,41 +158,51 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
readl(&ds->regs->buf); readl(&ds->regs->buf);
/* keep writing and reading 1 byte until done */ /* keep writing and reading 1 byte until done */
for (i = 0; i < len; i++) { while ((i_cnt < len) || (o_cnt < len)) {
/* wait till TXFULL is asserted */ /* read RX buffer and flags */
while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK); buf_reg_val = readl(&ds->regs->buf);
/* write the data */ /* if data is available */
data1_reg_val &= ~0xFFFF; if ((i_cnt < len) &&
if (txp) { (buf_reg_val & SPIBUF_RXEMPTY_MASK) == 0) {
data1_reg_val |= *txp; /*
txp++; * If there is no read buffer simply
* ignore the read character
*/
if (rxp)
*rxp++ = buf_reg_val & 0xFF;
/* increment read words count */
i_cnt++;
} }
/* /*
* Write to DAT1 is required to keep the serial transfer going. * if the tx buffer is empty and there
* We just terminate when we reach the end. * is still data to transmit
*/ */
if ((i == (len - 1)) && (flags & SPI_XFER_END)) { if ((o_cnt < len) &&
/* clear CS hold */ ((buf_reg_val & SPIBUF_TXFULL_MASK) == 0)) {
writel(data1_reg_val & /* write the data */
~(1 << SPIDAT1_CSHOLD_SHIFT), &ds->regs->dat1); data1_reg_val &= ~0xFFFF;
} else { if (txp)
/* enable CS hold */ data1_reg_val |= *txp++;
data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) | /*
* Write to DAT1 is required to keep
* the serial transfer going.
* We just terminate when we reach the end.
*/
if ((o_cnt == (len - 1)) && (flags & SPI_XFER_END)) {
/* clear CS hold */
writel(data1_reg_val &
~(1 << SPIDAT1_CSHOLD_SHIFT),
&ds->regs->dat1);
} else {
/* enable CS hold and write TX register */
data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) |
(slave->cs << SPIDAT1_CSNR_SHIFT)); (slave->cs << SPIDAT1_CSNR_SHIFT));
writel(data1_reg_val, &ds->regs->dat1); writel(data1_reg_val, &ds->regs->dat1);
} }
/* increment written words count */
/* read the data - wait for data availability */ o_cnt++;
while (readl(&ds->regs->buf) & SPIBUF_RXEMPTY_MASK);
if (rxp) {
*rxp = readl(&ds->regs->buf) & 0xFF;
rxp++;
} else {
/* simply drop the read character */
readl(&ds->regs->buf);
} }
} }
return 0; return 0;