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