
Make flash writes 32 bit aligned by using bounce buffers to deal with non 32 bit aligned buffers. Allocate a 512 byte bounce buffer (max known page size currently) for this case. 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 --- drivers/spi/cadence_qspi.c | 13 ++++++++++++- drivers/spi/cadence_qspi.h | 1 + drivers/spi/cadence_qspi_apb.c | 10 +++++----- 3 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 991a7160bdb8..49c9b477e678 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -158,6 +158,10 @@ static int cadence_spi_probe(struct udevice *bus)
priv->regbase = plat->regbase; priv->ahbbase = plat->ahbbase; + /* Bounce buf to handle unaligned writes. 512B is max pagesize */ + priv->bounce_buf = malloc(512); + if (!priv->bounce_buf) + return -ENOMEM;
if (!priv->qspi_is_init) { cadence_qspi_apb_controller_init(plat); @@ -259,8 +263,15 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen, err = cadence_qspi_apb_indirect_write_setup (plat, priv->cmd_len, cmd_buf); if (!err) { + const u8 *txbuf = dout; + + if ((uintptr_t)txbuf % 4) { + memcpy(priv->bounce_buf, dout, + data_bytes); + txbuf = priv->bounce_buf; + } err = cadence_qspi_apb_indirect_write_execute - (plat, data_bytes, dout); + (plat, data_bytes, txbuf); } break; default: diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index 83154210bd95..c97419af3de3 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -43,6 +43,7 @@ struct cadence_spi_priv { unsigned int qspi_calibrated_hz; unsigned int qspi_calibrated_cs; unsigned int previous_hz; + void *bounce_buf; };
/* Functions call declaration */ diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index fa8af33ae19b..fd3ece4cb129 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -727,11 +727,11 @@ int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat,
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 <<