diff options
author | Ye.Li <B37916@freescale.com> | 2014-03-10 16:13:19 +0800 |
---|---|---|
committer | Ye.Li <B37916@freescale.com> | 2014-03-10 17:50:37 +0800 |
commit | 93f4a65f3c0fcd06dc39329d203ee822a24c7b11 (patch) | |
tree | 197c3e1ece4e778804e66108f5e38cdacbb166bf | |
parent | 7ef25cd637b1ec9713427a871cb1c57e3cd2f8ce (diff) | |
download | u-boot-imx-93f4a65f3c0fcd06dc39329d203ee822a24c7b11.zip u-boot-imx-93f4a65f3c0fcd06dc39329d203ee822a24c7b11.tar.gz u-boot-imx-93f4a65f3c0fcd06dc39329d203ee822a24c7b11.tar.bz2 |
ENGR00302525 QuadSPI: Update driver to support 4 flash chips on each QSPI.
Add two configurations "CONFIG_QSPI_BASE" and "CONFIG_QSPI_MEMMAP_BASE"
for QSPI registers base and AHB memory base. So the driver is independent
from QSPI2. Use "bus" and "cs" parameters to denote 4 flash chip connected
on one QuadSPI:
SFA1: bus 0, cs 0
SFA2: bus 0, cs 1
SFB1: bus 1, cs 0
SFB2: bus 1, cs 1
Currently in uboot, the SPI flash framework does not have way to notify the
flash size to the driver. It brings a problem for QSPI driver to set the memory
map space of each chip. In this patch, we fix the mem map space of each chip
to 64MB(total is 256MB). So for flash larger than 64MB, driver only support
low 64MB.
Because u-boot SPI flash framework only supports 24bits address (16MB), the 64MB
limitation in driver is ok to work in u-boot.
Clean up the spi_xfer and spi read. Divide read to "IP read" and "AHB read".
In current implementation, the IPCR is still filled even reading from AHB
memory. This causes QSPI to read from flash twice, one to IP buffer, the
other to the AHB buffer.
Signed-off-by: Ye.Li <B37916@freescale.com>
-rw-r--r-- | drivers/spi/fsl_qspi.c | 222 | ||||
-rwxr-xr-x | include/configs/mx6sx_arm2.h | 2 | ||||
-rw-r--r-- | include/configs/mx6sxsabresd.h | 2 |
3 files changed, 95 insertions, 131 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index a8901f3..a14e935 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -14,6 +14,8 @@ #include <asm/io.h> +#define QUADSPI_AHBMAP_BANK_MAXSIZE SZ_64M + /* The registers */ #define QUADSPI_MCR 0x00 #define QUADSPI_MCR_RESERVED_SHIFT 16 @@ -253,21 +255,10 @@ struct fsl_qspi { uint32_t mode; u32 iobase; u32 ahb_base; /* Used when read from AHB bus */ - u32 memmap_phy; - u32 nor_size; - u32 nor_num; - unsigned int chip_base_addr; /* We may support two chips. */ + u32 bank_memmap_phy[4]; struct fsl_qspi_devtype_data *devtype_data; }; -/*stucture to store the previous cmd*/ -struct previous_cmd { -u8 cmd; -unsigned int addr; -}; -struct previous_cmd pre_cmd = {0, 0}; - - static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) { writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); @@ -297,15 +288,10 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Quad Read */ lut_base = SEQID_QUAD_READ * 4; - if (q->nor_size <= SZ_16M) { - cmd = OPCODE_QUAD_READ; - addrlen = ADDR24BIT; - dummy = 8; - } else { - cmd = OPCODE_QUAD_READ_4B; - addrlen = ADDR32BIT; - dummy = 8; - } + /* U-boot SPI flash only support 24bits address*/ + cmd = OPCODE_QUAD_READ; + addrlen = ADDR24BIT; + dummy = 8; writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); @@ -318,16 +304,10 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Fast Read */ lut_base = SEQID_FAST_READ * 4; + cmd = OPCODE_FAST_READ; + addrlen = ADDR24BIT; + dummy = 8; - if (q->nor_size <= SZ_16M) { - cmd = OPCODE_FAST_READ; - addrlen = ADDR24BIT; - dummy = 8; - } else { - cmd = OPCODE_FAST_READ_4B; - addrlen = ADDR32BIT; - dummy = 8; - } writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD1, rxfifo), @@ -335,14 +315,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Page Program */ lut_base = SEQID_PP * 4; - - if (q->nor_size <= SZ_16M) { - cmd = OPCODE_PP; - addrlen = ADDR24BIT; - } else { - cmd = OPCODE_PP_4B; - addrlen = ADDR32BIT; - } + cmd = OPCODE_PP; + addrlen = ADDR24BIT; writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); @@ -355,14 +329,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Erase a sector */ lut_base = SEQID_SE * 4; - - if (q->nor_size <= SZ_16M) { - cmd = OPCODE_SE; - addrlen = ADDR24BIT; - } else { - cmd = OPCODE_SE_4B; - addrlen = ADDR32BIT; - } + cmd = OPCODE_SE; + addrlen = ADDR24BIT; writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); @@ -389,16 +357,9 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* DDR QUAD Read */ lut_base = SEQID_DDR_QUAD_READ * 4; - - if (q->nor_size <= SZ_16M) { - cmd = OPCODE_DDR_QUAD_READ; - addrlen = ADDR24BIT; - dummy = 6; - } else { - cmd = OPCODE_DDR_QUAD_READ; - addrlen = ADDR32BIT; - dummy = 6; - } + cmd = OPCODE_DDR_QUAD_READ; + addrlen = ADDR24BIT; + dummy = 6; writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR_DDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); @@ -450,14 +411,16 @@ static void fsl_enable_ddr_mode(struct fsl_qspi *q) static void fsl_qspi_init_abh_read(struct fsl_qspi *q) { u32 base = q->iobase; - int nor_size = q->nor_size; - int nor_num = q->nor_num; - /* Map the SPI NOR to accessiable address */ - writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); - writel(nor_size + q->memmap_phy, base + QUADSPI_SFA2AD); - writel((nor_size * nor_num) + q->memmap_phy, base + QUADSPI_SFB1AD); - writel((nor_size * nor_num) + q->memmap_phy, base + QUADSPI_SFB2AD); + /* Map the SPI NOR to accessiable address, arrage max space for each bank*/ + writel(q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFA1AD); + writel(q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFA2AD); + writel(q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFB1AD); + writel(q->bank_memmap_phy[3] + QUADSPI_AHBMAP_BANK_MAXSIZE, + base + QUADSPI_SFB2AD); /* AHB configuration for access buffer 0/1/2 .*/ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); @@ -528,22 +491,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, struct fsl_qspi *q; int ret; + if (bus > 1) { + puts("FSL_QSPI: Not a valid bus !\n"); + return NULL; + } + + if (cs > 1) { + puts("FSL_QSPI: Not a valid cs !\n"); + return NULL; + } + q = spi_alloc_slave(struct fsl_qspi, bus, cs); if (!q) { puts("FSL_QSPI: SPI Slave not allocated !\n"); return NULL; } - q->iobase = QSPI2_BASE_ADDR; - q->memmap_phy = QSPI2_ARB_BASE_ADDR; - q->nor_num = 1; /* change it in future */ - q->nor_size = 0x1000000; /* 16MB */ + q->iobase = CONFIG_QSPI_BASE; + q->bank_memmap_phy[0] = CONFIG_QSPI_MEMMAP_BASE; + q->bank_memmap_phy[1] = q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE; + q->bank_memmap_phy[2] = q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE; + q->bank_memmap_phy[3] = q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE; /* Init the QuadSPI controller */ ret = fsl_qspi_init(q); if (ret) { puts("FSL_QSPI: init failed!\n"); - printf("FSL_QSPI: init failed!\n"); return NULL; } @@ -652,35 +625,32 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) int seqid; u32 reg, reg2; int err; - struct previous_cmd *pcmd = &pre_cmd; - - /*use ddr quad read instead of fast read*/ - if (OPCODE_FAST_READ == cmd) - cmd = OPCODE_DDR_QUAD_READ; - /*save the previous cmd*/ - pcmd->cmd = cmd; - pcmd->addr = addr; - /* save the reg */ - reg = readl(base + QUADSPI_MCR); + int bank_id; - writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR); - writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, - base + QUADSPI_RBCT); - writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); - - do { + /* check the SR first, wait previous cmd completed*/ + do { reg2 = readl(base + QUADSPI_SR); if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) { udelay(1); - printf("The controller is busy, 0x%x\n", reg2); - continue; + printf("The controller is busy, 0x%x\n", reg2); + continue; } break; } while (1); + /* save the reg */ + reg = readl(base + QUADSPI_MCR); + + /* get the bank index */ + bank_id = ((q->slave.bus) << 1) + (q->slave.cs); + + writel(q->bank_memmap_phy[bank_id] + addr, base + QUADSPI_SFAR); + writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, + base + QUADSPI_RBCT); + writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); + /* trigger the LUT now */ seqid = fsl_qspi_get_seqid(q, cmd); - /*printf("cmd %x, len %d, seqid %d\n", cmd, len, seqid);*/ writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); /* Wait until completed */ @@ -710,23 +680,23 @@ static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) } /* Read out the data from the AHB buffer. */ -static void fsl_qspi_read(struct fsl_qspi *q, unsigned int addr, int len, u8 *rxbuf) +static void fsl_qspi_ahb_read(struct fsl_qspi *q, + unsigned int addr, int len, u8 *rxbuf) { + int bank_id; + + /* get the bank index */ + bank_id = ((q->slave.bus) << 1) + (q->slave.cs); + /* Read out the data directly from the AHB buffer.*/ - memcpy(rxbuf, (u8 *)(q->memmap_phy + q->chip_base_addr + addr), len); + memcpy(rxbuf, (u8 *)(q->bank_memmap_phy[bank_id] + addr), len); } /* Read out the data from the QUADSPI_RBDR buffer registers. */ -static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf) +static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf) { u32 tmp; int i = 0; - struct previous_cmd *pcmd = &pre_cmd; - - if (OPCODE_DDR_QUAD_READ == pcmd->cmd) { - fsl_qspi_read(q, pcmd->addr, len, rxbuf); - return; - } while (len > 0) { tmp = readl(q->iobase + QUADSPI_RBDR + i * 4); @@ -768,57 +738,47 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, { struct fsl_qspi *q = container_of(slave, struct fsl_qspi, slave); int len = bitlen / 8; - int ret; + int ret = 0; u8 *buf; static u8 opcode; static unsigned int addr; - if (!opcode) { + if (!opcode && (flags & SPI_XFER_BEGIN)) { /* spi_xfer for cmd phase */ buf = (u8 *)dout; opcode = buf[0]; - addr = buf[1] << 16 | buf[2] << 8 | buf[3]; - if (flags & SPI_XFER_END) { - /* if transfer cmd only */ - ret = fsl_qspi_runcmd(q, opcode, addr, len); - opcode = 0; - addr = 0; - if (ret) - return ret; - } - } else if (SPI_XFER_END == flags && !din && !dout) { - /* for read status only, restore opcode and addr to 0 */ - opcode = 0; - addr = 0; - return 0; - } else { + if (len > 1) + addr = buf[1] << 16 | buf[2] << 8 | buf[3]; + + /* if transfer cmd only */ + if (flags & SPI_XFER_END) + ret = fsl_qspi_runcmd(q, opcode, addr, 0); + + } else if (opcode) { /* spi_xfer for data phase */ - if (OPCODE_PP != opcode) { - /* run all cmds except page program*/ - ret = fsl_qspi_runcmd(q, opcode, addr, len); - if (flags == SPI_XFER_END) { - /* data transfer end, restore opcode and addr to 0*/ - opcode = 0; - addr = 0; - } - if (ret) - return ret; - } if (din) { - /* read data */ + /* read*/ buf = (u8 *)din; - fsl_qspi_read_data(q, len, buf); + if (OPCODE_FAST_READ == opcode) { + fsl_qspi_ahb_read(q, addr, len, buf); + } else { + ret = fsl_qspi_runcmd(q, opcode, addr, len); + if (!ret) + fsl_qspi_ip_read(q, len, buf); + } } else if (dout) { /* write data, prepare data first */ buf = (u8 *)dout; fsl_qspi_write_data(q, len, buf); /* then run page program cmd */ ret = fsl_qspi_runcmd(q, opcode, addr, len); - opcode = 0; - addr = 0; - if (ret) - return ret; } } - return 0; + + if (ret || (flags & SPI_XFER_END)) { + opcode = 0; + addr = 0; + } + + return ret; } diff --git a/include/configs/mx6sx_arm2.h b/include/configs/mx6sx_arm2.h index 6caa2b0..82a2352 100755 --- a/include/configs/mx6sx_arm2.h +++ b/include/configs/mx6sx_arm2.h @@ -98,6 +98,8 @@ #ifdef CONFIG_CMD_SPI #define CONFIG_QSPI /* enable the QUADSPI driver */ +#define CONFIG_QSPI_BASE QSPI2_BASE_ADDR +#define CONFIG_QSPI_MEMMAP_BASE QSPI2_ARB_BASE_ADDR #define CONFIG_HARD_SPI #define CONFIG_DEFAULT_SPI_BUS 0 diff --git a/include/configs/mx6sxsabresd.h b/include/configs/mx6sxsabresd.h index c4e2c9c..9db91cc 100644 --- a/include/configs/mx6sxsabresd.h +++ b/include/configs/mx6sxsabresd.h @@ -106,6 +106,8 @@ #ifdef CONFIG_CMD_SPI #define CONFIG_QSPI /* enable the QUADSPI driver */ +#define CONFIG_QSPI_BASE QSPI2_BASE_ADDR +#define CONFIG_QSPI_MEMMAP_BASE QSPI2_ARB_BASE_ADDR #define CONFIG_HARD_SPI #define CONFIG_DEFAULT_SPI_BUS 0 |