Commit aaa21d3ffc023623a3a8247e5fa25d0db2bfb630

Authored by Vignesh R
Committed by Jagan Teki
1 parent a743e2ba38

spi: cadence_qspi_apb: Make flash writes 32 bit aligned

Make flash writes 32 bit aligned by using bounce buffers to deal with
non 32 bit aligned buffers.
This is required because as per TI K2G TRM[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 fail
sometimes.

[1] http://www.ti.com/lit/ug/spruhy8g/spruhy8g.pdf

Signed-off-by: Vignesh R <vigneshr@ti.com>
Acked-by: Marek Vasut <marex@denx.de>
Acked-by: Simon Goldschmidt <sgoldschmidt@de.pepperl-fuchs.com>
Reviewed-by: Jason Rush <jarush@gmail.com>
Acked-by: Jason Rush <jarush@gmail.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>

Showing 1 changed file with 25 additions and 6 deletions Side-by-side Diff

drivers/spi/cadence_qspi_apb.c
... ... @@ -30,6 +30,7 @@
30 30 #include <linux/errno.h>
31 31 #include <wait_bit.h>
32 32 #include <spi.h>
  33 +#include <malloc.h>
33 34 #include "cadence_qspi.h"
34 35  
35 36 #define CQSPI_REG_POLL_US 1 /* 1us */
36 37  
... ... @@ -719,9 +720,23 @@
719 720 {
720 721 unsigned int page_size = plat->page_size;
721 722 unsigned int remaining = n_tx;
  723 + const u8 *bb_txbuf = txbuf;
  724 + void *bounce_buf = NULL;
722 725 unsigned int write_bytes;
723 726 int ret;
724 727  
  728 + /*
  729 + * Use bounce buffer for non 32 bit aligned txbuf to avoid data
  730 + * aborts
  731 + */
  732 + if ((uintptr_t)txbuf % 4) {
  733 + bounce_buf = malloc(n_tx);
  734 + if (!bounce_buf)
  735 + return -ENOMEM;
  736 + memcpy(bounce_buf, txbuf, n_tx);
  737 + bb_txbuf = bounce_buf;
  738 + }
  739 +
725 740 /* Configure the indirect read transfer bytes */
726 741 writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES);
727 742  
... ... @@ -731,11 +746,11 @@
731 746  
732 747 while (remaining > 0) {
733 748 write_bytes = remaining > page_size ? page_size : remaining;
734   - /* Handle non-4-byte aligned access to avoid data abort. */
735   - if (((uintptr_t)txbuf % 4) || (write_bytes % 4))
736   - writesb(plat->ahbbase, txbuf, write_bytes);
737   - else
738   - writesl(plat->ahbbase, txbuf, write_bytes >> 2);
  749 + writesl(plat->ahbbase, bb_txbuf, write_bytes >> 2);
  750 + if (write_bytes % 4)
  751 + writesb(plat->ahbbase,
  752 + bb_txbuf + rounddown(write_bytes, 4),
  753 + write_bytes % 4);
739 754  
740 755 ret = wait_for_bit_le32(plat->regbase + CQSPI_REG_SDRAMLEVEL,
741 756 CQSPI_REG_SDRAMLEVEL_WR_MASK <<
... ... @@ -745,7 +760,7 @@
745 760 goto failwr;
746 761 }
747 762  
748   - txbuf += write_bytes;
  763 + bb_txbuf += write_bytes;
749 764 remaining -= write_bytes;
750 765 }
751 766  
752 767  
... ... @@ -760,12 +775,16 @@
760 775 /* Clear indirect completion status */
761 776 writel(CQSPI_REG_INDIRECTWR_DONE,
762 777 plat->regbase + CQSPI_REG_INDIRECTWR);
  778 + if (bounce_buf)
  779 + free(bounce_buf);
763 780 return 0;
764 781  
765 782 failwr:
766 783 /* Cancel the indirect write */
767 784 writel(CQSPI_REG_INDIRECTWR_CANCEL,
768 785 plat->regbase + CQSPI_REG_INDIRECTWR);
  786 + if (bounce_buf)
  787 + free(bounce_buf);
769 788 return ret;
770 789 }
771 790