[U-Boot] [PATCH] DaVinci: Improve DaVinci SPI speed.

Paulraj, Sandeep s-paulraj at ti.com
Thu Jun 17 17:10:11 CEST 2010



> 
> 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 <dbrignoli at audioscience.com>
> > Tested-by: Ben Gardiner <bengardiner at 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 at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot


More information about the U-Boot mailing list