[U-Boot] [PATCH] DaVinci: Improve DaVinci SPI speed.
Delio Brignoli
dbrignoli at audioscience.com
Tue Jun 1 13:36:28 CEST 2010
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 at audioscience.com>
Tested-by: Ben Gardiner <bengardiner at nanometrics.ca>
---
drivers/spi/davinci_spi.c | 69 ++++++++++++++++++++++-----------------------
1 files changed, 34 insertions(+), 35 deletions(-)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 60ba007..d7f130d 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -131,12 +131,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 +157,42 @@ 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);
-
- /* write the data */
- data1_reg_val &= ~0xFFFF;
- if (txp) {
- data1_reg_val |= *txp;
- txp++;
+ while ((i_cnt < len) || (o_cnt < len)) {
+ /* read RX buffer and flags */
+ buf_reg_val = readl(&ds->regs->buf);
+
+ /* 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 ((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 the tx buffer is empty and there is still data to transmit */
+ 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;
--
1.6.3.3
More information about the U-Boot
mailing list