diff options
author | Peng Fan <Peng.Fan@freescale.com> | 2014-09-04 11:21:29 +0800 |
---|---|---|
committer | Peng Fan <Peng.Fan@freescale.com> | 2014-09-05 09:20:16 +0800 |
commit | 0338ad3a375c4809abde523d9adfd689cc1f83cf (patch) | |
tree | c37f46c40c125ec45dfaabd4644c04e2fcf840b5 | |
parent | 69f56f7509a4116fa0f2b9be50db256f1e628d31 (diff) | |
download | u-boot-imx-0338ad3a375c4809abde523d9adfd689cc1f83cf.zip u-boot-imx-0338ad3a375c4809abde523d9adfd689cc1f83cf.tar.gz u-boot-imx-0338ad3a375c4809abde523d9adfd689cc1f83cf.tar.bz2 |
ENGR00329484-1 QuadSPI:Unaligned access crash uboot
To fsl_qspi_write_data and fsl_qspi_ip_read, pointer txbuf and
rxbuf are not guaranteed that they are 4 Bytes aligned. Also,
it it not a good idea to cast type 'u8 *' to 'u32 *', except
we are sure that pointer type 'u8 *' is 4 Bytes aligned and
cast it to 'u32 *' will not pass memory boundary.
The problem is found when using fsl_qspi_write_data to write
registers in flash devices. The err msg:
data abort
pc : [<87822f44>] lr : [<87822f38>]
sp : bf5512c8 ip : 0000001c fp : bf856608
r10: 87868904 r9 : bf551efc r8 : 200f048c
r7 : 00000002 r6 : bf551336 r5 : bf552a70 r4 : 00000001
r3 : 00000000 r2 : 00000060 r1 : 8783b520 r0 : 8783b520
Flags: nZCv IRQs on FIQs off Mode SVC_32
Resetting CPU ...
The asm code which cause data abort is:
87822f30: e5964000 ldr r4, [r6]
From the dump msg, r6 is not 4 Bytes aligned, and data abort exception.
So, Use mempcy but not unsafe type casting.
In this patch, max_write_size is assigned using txfifo to avoid possible
errors in future.
Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
-rw-r--r-- | drivers/spi/fsl_qspi.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index ae1559c..a01867e 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -478,6 +478,13 @@ static int fsl_qspi_init(struct fsl_qspi *q) /* init for AHB read */ fsl_qspi_init_abh_read(q); + + /* + * High level code use page_size and max_write_size to calculate + * the number of bytes that should be programmed once. + */ + q->slave.max_write_size = q->devtype_data->txfifo; + return 0; } @@ -701,7 +708,7 @@ static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf) tmp = fsl_qspi_endian_xchg(q, tmp); if (len >= 4) { - *((u32 *)rxbuf) = tmp; + memcpy(rxbuf, &tmp, 4); rxbuf += 4; } else { memcpy(rxbuf, &tmp, len); @@ -717,19 +724,32 @@ static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf) static void fsl_qspi_write_data(struct fsl_qspi *q, int len, u8* txbuf) { u32 tmp; - int i, j; + u32 t1, t2; + int j; - /* clear the TX FIFO. */ + /* clear the TX FIFO. */ tmp = readl(q->iobase + QUADSPI_MCR); writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR); /* fill the TX data to the FIFO */ - for (j = 0, i = ((len + 3) / 4); j < i; j++) { - tmp = fsl_qspi_endian_xchg(q, *(u32 *)txbuf); + t2 = len % 4; + t1 = len >> 2; /* 4 Bytes aligned */ + + for (j = 0; j < t1; j++) { + memcpy(&tmp, txbuf, 4); + tmp = fsl_qspi_endian_xchg(q, tmp); writel(tmp, q->iobase + QUADSPI_TBDR); txbuf += 4; } + + if (t2) { + tmp = 0; + memcpy(&tmp, txbuf, t2); + tmp = fsl_qspi_endian_xchg(q, tmp); + writel(tmp, q->iobase + QUADSPI_TBDR); + } } + /* see the spi_flash_read_write() */ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) |