[U-Boot] [PATCH] spi: cadence_qspi_apb: Use 32 bit indirect write transaction when possible

Marek Vasut marex at denx.de
Sat Nov 12 22:43:36 CET 2016


On 11/10/2016 06:18 AM, Vignesh R wrote:
> According to Section 11.15.4.9.2 Indirect Write Controller of K2G SoC
> TRM SPRUHY8D[1], the external master is only permitted to issue 32-bit
> data interface writes until the last word of an indirect transfer
> otherwise indirect writes is known to fails sometimes. So, make sure
> that QSPI indirect writes are 32 bit sized except for the last write.
> 
> [1]www.ti.com/lit/ug/spruhy8d/spruhy8d.pdf
> 
> Signed-off-by: Vignesh R <vigneshr at ti.com>

I would if it wouldn't be better to use bounce buffer for the txbuf .
See common/bouncebuf.c

> ---
>  drivers/spi/cadence_qspi_apb.c | 41 +++++++++++++++++++++++++++++++----------
>  1 file changed, 31 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> index e285d3c1e761..0115700ef6a7 100644
> --- a/drivers/spi/cadence_qspi_apb.c
> +++ b/drivers/spi/cadence_qspi_apb.c
> @@ -739,23 +739,44 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
>  {
>  	unsigned int page_size = plat->page_size;
>  	unsigned int remaining = n_tx;
> -	unsigned int write_bytes;
> +	unsigned int write_bytes = 0;
>  	int ret;
>  
> +	/* Handle non-4-byte aligned access to avoid data abort. */
> +	if ((uintptr_t) txbuf % 4) {
> +		write_bytes = n_tx > 3 ? 4 - ((uintptr_t)txbuf % 4) : n_tx;
> +		/* Configure the indirect read transfer bytes */
> +		writel(write_bytes, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
> +		/* Start the indirect write transfer */
> +		writel(CQSPI_REG_INDIRECTWR_START_MASK,
> +		       plat->regbase + CQSPI_REG_INDIRECTWR);
> +		writesb(plat->ahbbase, txbuf, write_bytes);
> +		txbuf += write_bytes;
> +		remaining -= write_bytes;
> +		if (remaining > 0) {
> +			u32 start_addr = readl(plat->regbase +
> +					       CQSPI_REG_INDIRECTWRSTARTADDR);
> +			start_addr += write_bytes;
> +			writel(start_addr, plat->regbase +
> +			       CQSPI_REG_INDIRECTWRSTARTADDR);
> +		}
> +	}
> +
>  	/* Configure the indirect read transfer bytes */
> -	writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
> +	writel(n_tx - write_bytes, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
>  
> -	/* Start the indirect write transfer */
> -	writel(CQSPI_REG_INDIRECTWR_START_MASK,
> -	       plat->regbase + CQSPI_REG_INDIRECTWR);
> +	if (remaining > 0)
> +		writel(CQSPI_REG_INDIRECTWR_START_MASK,
> +		       plat->regbase + CQSPI_REG_INDIRECTWR);
>  
>  	while (remaining > 0) {
>  		write_bytes = remaining > page_size ? page_size : remaining;
> -		/* Handle non-4-byte aligned access to avoid data abort. */
> -		if (((uintptr_t)txbuf % 4) || (write_bytes % 4))
> -			writesb(plat->ahbbase, txbuf, write_bytes);
> -		else
> -			writesl(plat->ahbbase, txbuf, write_bytes >> 2);
> +
> +		writesl(plat->ahbbase, txbuf, write_bytes >> 2);
> +		if (write_bytes % 4)
> +			writesb(plat->ahbbase,
> +				txbuf + rounddown(write_bytes, 4),
> +				write_bytes % 4);
>  
>  		ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_SDRAMLEVEL,
>  				   CQSPI_REG_SDRAMLEVEL_WR_MASK <<
> 


-- 
Best regards,
Marek Vasut


More information about the U-Boot mailing list