diff mbox

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

Message ID 20161130115012.15889-1-vigneshr@ti.com
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Commit Message

Raghavendra, Vignesh Nov. 30, 2016, 11:50 a.m. UTC
According to Section 11.15.4.9.1 Indirect Read Controller of K2G SoC
TRM SPRUHY8D[1], the external master is only permitted to issue 32-bit
data interface reads until the last word of an indirect transfer
So, make sure that QSPI indirect reads are 32 bit sized except for the
final read. If the rxbuf is unaligned then use bounce buffer, so that
readsl() can be used instead of readsb() to avoid non 32-bit accesses.

[1]www.ti.com/lit/ug/spruhy8d/spruhy8d.pdf

Signed-off-by: Vignesh R <vigneshr@ti.com>
---
 drivers/spi/cadence_qspi_apb.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

Comments

Marek Vasut Nov. 30, 2016, 12:57 p.m. UTC | #1
On 11/30/2016 12:50 PM, Vignesh R wrote:
> According to Section 11.15.4.9.1 Indirect Read Controller of K2G SoC
> TRM SPRUHY8D[1], the external master is only permitted to issue 32-bit
> data interface reads until the last word of an indirect transfer
> So, make sure that QSPI indirect reads are 32 bit sized except for the
> final read. If the rxbuf is unaligned then use bounce buffer, so that
> readsl() can be used instead of readsb() to avoid non 32-bit accesses.
> 
> [1]www.ti.com/lit/ug/spruhy8d/spruhy8d.pdf
> 
> Signed-off-by: Vignesh R <vigneshr@ti.com>

Reviewed-by: Marek Vasut <marex@denx.de>

Thanks!

> ---
>  drivers/spi/cadence_qspi_apb.c | 22 ++++++++++++++++------
>  1 file changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
> index 6ce98acf747d..160ceb23aefe 100644
> --- a/drivers/spi/cadence_qspi_apb.c
> +++ b/drivers/spi/cadence_qspi_apb.c
> @@ -651,6 +651,8 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>  {
>  	unsigned int remaining = n_rx;
>  	unsigned int bytes_to_read = 0;
> +	struct bounce_buffer bb;
> +	u8 *bb_rxbuf;
>  	int ret;
>  
>  	writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
> @@ -659,6 +661,11 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>  	writel(CQSPI_REG_INDIRECTRD_START_MASK,
>  	       plat->regbase + CQSPI_REG_INDIRECTRD);
>  
> +	ret = bounce_buffer_start(&bb, (void *)rxbuf, n_rx, GEN_BB_WRITE);
> +	if (ret)
> +		return ret;
> +	bb_rxbuf = bb.bounce_buffer;
> +
>  	while (remaining > 0) {
>  		ret = cadence_qspi_wait_for_data(plat);
>  		if (ret < 0) {
> @@ -672,12 +679,13 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>  			bytes_to_read *= CQSPI_FIFO_WIDTH;
>  			bytes_to_read = bytes_to_read > remaining ?
>  					remaining : bytes_to_read;
> -			/* Handle non-4-byte aligned access to avoid data abort. */
> -			if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4))
> -				readsb(plat->ahbbase, rxbuf, bytes_to_read);
> -			else
> -				readsl(plat->ahbbase, rxbuf, bytes_to_read >> 2);
> -			rxbuf += bytes_to_read;
> +			readsl(plat->ahbbase, bb_rxbuf, bytes_to_read >> 2);
> +			if (bytes_to_read % 4)
> +				readsb(plat->ahbbase,
> +				       bb_rxbuf + rounddown(bytes_to_read, 4),
> +				       bytes_to_read % 4);
> +
> +			bb_rxbuf += bytes_to_read;
>  			remaining -= bytes_to_read;
>  			bytes_to_read = cadence_qspi_get_rd_sram_level(plat);
>  		}
> @@ -694,6 +702,7 @@ int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
>  	/* Clear indirect completion status */
>  	writel(CQSPI_REG_INDIRECTRD_DONE_MASK,
>  	       plat->regbase + CQSPI_REG_INDIRECTRD);
> +	bounce_buffer_stop(&bb);
>  
>  	return 0;
>  
> @@ -701,6 +710,7 @@ failrd:
>  	/* Cancel the indirect read */
>  	writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK,
>  	       plat->regbase + CQSPI_REG_INDIRECTRD);
> +	bounce_buffer_stop(&bb);
>  	return ret;
>  }
>  
>
diff mbox

Patch

diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 6ce98acf747d..160ceb23aefe 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -651,6 +651,8 @@  int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 {
 	unsigned int remaining = n_rx;
 	unsigned int bytes_to_read = 0;
+	struct bounce_buffer bb;
+	u8 *bb_rxbuf;
 	int ret;
 
 	writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES);
@@ -659,6 +661,11 @@  int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 	writel(CQSPI_REG_INDIRECTRD_START_MASK,
 	       plat->regbase + CQSPI_REG_INDIRECTRD);
 
+	ret = bounce_buffer_start(&bb, (void *)rxbuf, n_rx, GEN_BB_WRITE);
+	if (ret)
+		return ret;
+	bb_rxbuf = bb.bounce_buffer;
+
 	while (remaining > 0) {
 		ret = cadence_qspi_wait_for_data(plat);
 		if (ret < 0) {
@@ -672,12 +679,13 @@  int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 			bytes_to_read *= CQSPI_FIFO_WIDTH;
 			bytes_to_read = bytes_to_read > remaining ?
 					remaining : bytes_to_read;
-			/* Handle non-4-byte aligned access to avoid data abort. */
-			if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4))
-				readsb(plat->ahbbase, rxbuf, bytes_to_read);
-			else
-				readsl(plat->ahbbase, rxbuf, bytes_to_read >> 2);
-			rxbuf += bytes_to_read;
+			readsl(plat->ahbbase, bb_rxbuf, bytes_to_read >> 2);
+			if (bytes_to_read % 4)
+				readsb(plat->ahbbase,
+				       bb_rxbuf + rounddown(bytes_to_read, 4),
+				       bytes_to_read % 4);
+
+			bb_rxbuf += bytes_to_read;
 			remaining -= bytes_to_read;
 			bytes_to_read = cadence_qspi_get_rd_sram_level(plat);
 		}
@@ -694,6 +702,7 @@  int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
 	/* Clear indirect completion status */
 	writel(CQSPI_REG_INDIRECTRD_DONE_MASK,
 	       plat->regbase + CQSPI_REG_INDIRECTRD);
+	bounce_buffer_stop(&bb);
 
 	return 0;
 
@@ -701,6 +710,7 @@  failrd:
 	/* Cancel the indirect read */
 	writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK,
 	       plat->regbase + CQSPI_REG_INDIRECTRD);
+	bounce_buffer_stop(&bb);
 	return ret;
 }