> 
> On 01/06/10 12:36, Delio Brignoli wrote:
> > 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 <dbrign...@audioscience.com>
> > Tested-by: Ben Gardiner <bengardi...@nanometrics.ca>
> 
> Sorry, I'm a bit late to the party on this.

It is late. Pull request already sent to Wolfgang
> 
> I have an alternative patch that tries to be even quicker, but I
> don't have the same platform as Delio, so can't compare like with
> like.

Compare it on your platform. I believe you have the OMAP L137.
And post the results.

> 
> This diff applies before Delio's patch. If it is any faster I am
> prepared to create a proper patch. If nobody can test it for speed
> I'll probably just drop it, since it produces a slightly bigger
> executable and I don't know that it is actually any faster...
> 
> In essence, it splits up read and write operations to avoid testing
> pointers in every loop iteration. It also unrolls the last iteration
> so that it doesn't have to test for loop ending twice each time
> round. Finally it avoids bit setting/clearing on each iteration when
> the results would only turn out to be the same anyway.
> 
> Here's the diff:
> 
> diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
> index 60ba007..a90d2f4 100644
> --- a/drivers/spi/davinci_spi.c
> +++ b/drivers/spi/davinci_spi.c
> @@ -126,16 +126,98 @@ void spi_release_bus(struct spi_slave *slave)
>       writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
>  }
> 
> -int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
> -             const void *dout, void *din, unsigned long flags)
> +static inline u8 davinci_spi_read_data(struct davinci_spi_slave *ds, u32
> data)
> +{
> +     unsigned int    buf_reg_val;
> +     /* wait till TXFULL is deasserted */
> +     while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
> +             ;
> +     writel(data, &ds->regs->dat1);
> +
> +     /* read the data - wait for data availability */
> +     while ((buf_reg_val = readl(&ds->regs->buf)) & SPIBUF_RXEMPTY_MASK)
> +             ;
> +     return buf_reg_val & 0xFF;
> +}
> +
> +static int davinci_spi_read(struct spi_slave *slave, unsigned int len,
> +                         u8 *rxp, unsigned long flags)
>  {
>       struct davinci_spi_slave *ds = to_davinci_spi(slave);
> -     unsigned int    len, data1_reg_val = readl(&ds->regs->dat1);
> -     int             ret, i;
> -     const u8        *txp = dout; /* dout can be NULL for read operation */
> -     u8              *rxp = din;  /* din can be NULL for write operation */
> +     unsigned int data1_reg_val = readl(&ds->regs->dat1);
> +
> +     /* do an empty read to clear the current contents */
> +     (void)readl(&ds->regs->buf);
> +
> +     /* enable CS hold */
> +     data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) |
> +                     (slave->cs << SPIDAT1_CSNR_SHIFT));
> +     data1_reg_val &= ~0xFFFF;
> +
> +     /* keep writing and reading 1 byte until only 1 byte left to read */
> +     while ((len--) > 1) {
> +             *rxp++ = davinci_spi_read_data(ds, data1_reg_val);
> +     }
> 
> -     ret = 0;
> +     /*
> +      * clear CS hold when we reach the end.
> +      */
> +     if (flags & SPI_XFER_END)
> +             data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
> +
> +     *rxp = davinci_spi_read_data(ds, data1_reg_val);
> +
> +     return 0;
> +}
> +
> +static inline void davinci_spi_write_data(struct davinci_spi_slave *ds,
> u32 data)
> +{
> +     /* wait till TXFULL is deasserted */
> +     while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
> +             ;
> +     writel(data, &ds->regs->dat1);
> +
> +     /* wait for read data availability */
> +     while (readl(&ds->regs->buf) & SPIBUF_RXEMPTY_MASK)
> +             ;
> +}
> +
> +static int davinci_spi_write(struct spi_slave *slave, unsigned int len,
> +             const u8 *txp, unsigned long flags)
> +{
> +     struct davinci_spi_slave *ds = to_davinci_spi(slave);
> +     unsigned int data1_reg_val = readl(&ds->regs->dat1);
> +
> +     /* do an empty read to clear the current contents */
> +     (void)readl(&ds->regs->buf);
> +
> +     /* enable CS hold */
> +     data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) |
> +                     (slave->cs << SPIDAT1_CSNR_SHIFT));
> +     data1_reg_val &= ~0xFFFF;
> +
> +     /* keep writing and reading 1 byte until only 1 byte left to write
> */
> +     while ((len--) > 1) {
> +             /* write the data */
> +             davinci_spi_write_data(ds, data1_reg_val | *txp++);
> +     }
> +
> +     /*
> +      * clear CS hold when we reach the end.
> +      */
> +     if (flags & SPI_XFER_END)
> +             data1_reg_val &= ~(1 << SPIDAT1_CSHOLD_SHIFT);
> +
> +     /* write the data */
> +     davinci_spi_write_data(ds, data1_reg_val | *txp);
> +
> +     return 0;
> +}
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
> +             const void *dout, void *din, unsigned long flags)
> +{
> +     unsigned int len;
> 
>       if (bitlen == 0)
>               /* Finish any previously submitted transfers */
> @@ -155,53 +237,15 @@ int spi_xfer(struct spi_slave *slave, unsigned int
> bitlen,
> 
>       len = bitlen / 8;
> 
> -     /* do an empty read to clear the current contents */
> -     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++;
> -             }
> -
> -             /*
> -              * 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) |
> -                                     (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);
> -             }
> -     }
> -     return 0;
> +     if (din)
> +             return davinci_spi_read(slave, len, din, flags);
> +     else
> +             return davinci_spi_write(slave, len, dout, flags);
> 
>  out:
>       if (flags & SPI_XFER_END) {
> -             writel(data1_reg_val &
> -                     ~(1 << SPIDAT1_CSHOLD_SHIFT), &ds->regs->dat1);
> +             u8 dummy = 0;
> +             davinci_spi_write(slave, 1, &dummy, flags);
>       }
>       return 0;
>  }
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to