X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fspi%2Ffsl_qspi.c;h=5e0b0692747cb7791c38e33783c515629f8ba6ff;hb=073adf987e8251ad934fcac4fd1bf20d4f34f96e;hp=ba20beff4f988adfeadbb8c799372da546440878;hpb=84f24ac8278d287581e5a559a7299e1dc2b53481;p=oweals%2Fu-boot.git diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index ba20beff4f..5e0b069274 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -14,7 +14,11 @@ #include "fsl_qspi.h" #define RX_BUFFER_SIZE 0x80 +#ifdef CONFIG_MX6SX +#define TX_BUFFER_SIZE 0x200 +#else #define TX_BUFFER_SIZE 0x40 +#endif #define OFFSET_BITS_MASK 0x00ffffff @@ -28,20 +32,36 @@ #define SEQID_CHIP_ERASE 5 #define SEQID_PP 6 #define SEQID_RDID 7 +#define SEQID_BE_4K 8 +#ifdef CONFIG_SPI_FLASH_BAR +#define SEQID_BRRD 9 +#define SEQID_BRWR 10 +#define SEQID_RDEAR 11 +#define SEQID_WREAR 12 +#endif -/* Flash opcodes */ -#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ -#define OPCODE_RDSR 0x05 /* Read status register */ -#define OPCODE_WREN 0x06 /* Write enable */ -#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ -#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ -#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ -#define OPCODE_RDID 0x9f /* Read JEDEC ID */ - -/* 4-byte address opcodes - used on Spansion and some Macronix flashes */ -#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ -#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ -#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ +/* QSPI CMD */ +#define QSPI_CMD_PP 0x02 /* Page program (up to 256 bytes) */ +#define QSPI_CMD_RDSR 0x05 /* Read status register */ +#define QSPI_CMD_WREN 0x06 /* Write enable */ +#define QSPI_CMD_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define QSPI_CMD_BE_4K 0x20 /* 4K erase */ +#define QSPI_CMD_CHIP_ERASE 0xc7 /* Erase whole flash chip */ +#define QSPI_CMD_SE 0xd8 /* Sector erase (usually 64KiB) */ +#define QSPI_CMD_RDID 0x9f /* Read JEDEC ID */ + +/* Used for Micron, winbond and Macronix flashes */ +#define QSPI_CMD_WREAR 0xc5 /* EAR register write */ +#define QSPI_CMD_RDEAR 0xc8 /* EAR reigster read */ + +/* Used for Spansion flashes only. */ +#define QSPI_CMD_BRRD 0x16 /* Bank register read */ +#define QSPI_CMD_BRWR 0x17 /* Bank register write */ + +/* 4-byte address QSPI CMD - used on Spansion and some Macronix flashes */ +#define QSPI_CMD_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define QSPI_CMD_PP_4B 0x12 /* Page program (up to 256 bytes) */ +#define QSPI_CMD_SE_4B 0xdc /* Sector erase (usually 64KiB) */ #ifdef CONFIG_SYS_FSL_QSPI_LE #define qspi_read32 in_le32 @@ -53,10 +73,16 @@ static unsigned long spi_bases[] = { QSPI0_BASE_ADDR, +#ifdef CONFIG_MX6SX + QSPI1_BASE_ADDR, +#endif }; static unsigned long amba_bases[] = { QSPI0_AMBA_BASE, +#ifdef CONFIG_MX6SX + QSPI1_AMBA_BASE, +#endif }; struct fsl_qspi { @@ -94,7 +120,7 @@ static void qspi_set_lut(struct fsl_qspi *qspi) /* Write Enable */ lut_base = SEQID_WREN * 4; - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_WREN) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_WREN) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); qspi_write32(®s->lut[lut_base + 1], 0); qspi_write32(®s->lut[lut_base + 2], 0); @@ -102,14 +128,22 @@ static void qspi_set_lut(struct fsl_qspi *qspi) /* Fast Read */ lut_base = SEQID_FAST_READ * 4; +#ifdef CONFIG_SPI_FLASH_BAR + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); +#else if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_FAST_READ) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); else - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_FAST_READ_4B) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(®s->lut[lut_base], + OPRND0(QSPI_CMD_FAST_READ_4B) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | + OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | + INSTR1(LUT_ADDR)); +#endif qspi_write32(®s->lut[lut_base + 1], OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) | INSTR1(LUT_READ)); @@ -118,7 +152,7 @@ static void qspi_set_lut(struct fsl_qspi *qspi) /* Read Status */ lut_base = SEQID_RDSR * 4; - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDSR) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_RDSR) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | PAD1(LUT_PAD1) | INSTR1(LUT_READ)); qspi_write32(®s->lut[lut_base + 1], 0); @@ -127,21 +161,27 @@ static void qspi_set_lut(struct fsl_qspi *qspi) /* Erase a sector */ lut_base = SEQID_SE * 4; +#ifdef CONFIG_SPI_FLASH_BAR + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_SE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); +#else if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); else - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_SE_4B) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_SE_4B) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); +#endif qspi_write32(®s->lut[lut_base + 1], 0); qspi_write32(®s->lut[lut_base + 2], 0); qspi_write32(®s->lut[lut_base + 3], 0); /* Erase the whole chip */ lut_base = SEQID_CHIP_ERASE * 4; - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_CHIP_ERASE) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_CHIP_ERASE) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); qspi_write32(®s->lut[lut_base + 1], 0); qspi_write32(®s->lut[lut_base + 2], 0); @@ -149,33 +189,184 @@ static void qspi_set_lut(struct fsl_qspi *qspi) /* Page Program */ lut_base = SEQID_PP * 4; +#ifdef CONFIG_SPI_FLASH_BAR + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_PP) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); +#else if (FSL_QSPI_FLASH_SIZE <= SZ_16M) - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); else - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP_4B) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_PP_4B) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); +#endif +#ifdef CONFIG_MX6SX + /* + * To MX6SX, OPRND0(TX_BUFFER_SIZE) can not work correctly. + * So, Use IDATSZ in IPCR to determine the size and here set 0. + */ + qspi_write32(®s->lut[lut_base + 1], OPRND0(0) | + PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); +#else qspi_write32(®s->lut[lut_base + 1], OPRND0(TX_BUFFER_SIZE) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE)); +#endif qspi_write32(®s->lut[lut_base + 2], 0); qspi_write32(®s->lut[lut_base + 3], 0); /* READ ID */ lut_base = SEQID_RDID * 4; - qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDID) | + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_RDID) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) | PAD1(LUT_PAD1) | INSTR1(LUT_READ)); qspi_write32(®s->lut[lut_base + 1], 0); qspi_write32(®s->lut[lut_base + 2], 0); qspi_write32(®s->lut[lut_base + 3], 0); + /* SUB SECTOR 4K ERASE */ + lut_base = SEQID_BE_4K * 4; + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | + PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + +#ifdef CONFIG_SPI_FLASH_BAR + /* + * BRRD BRWR RDEAR WREAR are all supported, because it is hard to + * dynamically check whether to set BRRD BRWR or RDEAR WREAR during + * initialization. + */ + lut_base = SEQID_BRRD * 4; + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_BRRD) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + + lut_base = SEQID_BRWR * 4; + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_BRWR) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); + + lut_base = SEQID_RDEAR * 4; + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_READ)); + + lut_base = SEQID_WREAR * 4; + qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_WREAR) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) | + PAD1(LUT_PAD1) | INSTR1(LUT_WRITE)); +#endif /* Lock the LUT */ qspi_write32(®s->lutkey, LUT_KEY_VALUE); qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK); } +#if defined(CONFIG_SYS_FSL_QSPI_AHB) +/* + * If we have changed the content of the flash by writing or erasing, + * we need to invalidate the AHB buffer. If we do not do so, we may read out + * the wrong data. The spec tells us reset the AHB domain and Serial Flash + * domain at the same time. + */ +static inline void qspi_ahb_invalid(struct fsl_qspi *q) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + u32 reg; + + reg = qspi_read32(®s->mcr); + reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; + qspi_write32(®s->mcr, reg); + + /* + * The minimum delay : 1 AHB + 2 SFCK clocks. + * Delay 1 us is enough. + */ + udelay(1); + + reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); + qspi_write32(®s->mcr, reg); +} + +/* Read out the data from the AHB buffer. */ +static inline void qspi_ahb_read(struct fsl_qspi *q, u8 *rxbuf, int len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + u32 mcr_reg; + + mcr_reg = qspi_read32(®s->mcr); + + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + + /* Read out the data directly from the AHB buffer. */ + memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len); + + qspi_write32(®s->mcr, mcr_reg); +} + +static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs) +{ + u32 reg, reg2; + + reg = qspi_read32(®s->mcr); + /* Disable the module */ + qspi_write32(®s->mcr, reg | QSPI_MCR_MDIS_MASK); + + /* Set the Sampling Register for DDR */ + reg2 = qspi_read32(®s->smpr); + reg2 &= ~QSPI_SMPR_DDRSMP_MASK; + reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT); + qspi_write32(®s->smpr, reg2); + + /* Enable the module again (enable the DDR too) */ + reg |= QSPI_MCR_DDR_EN_MASK; + /* Enable bit 29 for imx6sx */ + reg |= (1 << 29); + + qspi_write32(®s->mcr, reg); +} + +/* + * There are two different ways to read out the data from the flash: + * the "IP Command Read" and the "AHB Command Read". + * + * The IC guy suggests we use the "AHB Command Read" which is faster + * then the "IP Command Read". (What's more is that there is a bug in + * the "IP Command Read" in the Vybrid.) + * + * After we set up the registers for the "AHB Command Read", we can use + * the memcpy to read the data directly. A "missed" access to the buffer + * causes the controller to clear the buffer, and use the sequence pointed + * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash. + */ +static void qspi_init_ahb_read(struct fsl_qspi_regs *regs) +{ + /* AHB configuration for access buffer 0/1/2 .*/ + qspi_write32(®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(®s->buf3cr, QSPI_BUF3CR_ALLMST_MASK | + (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT)); + + /* We only use the buffer3 */ + qspi_write32(®s->buf0ind, 0); + qspi_write32(®s->buf1ind, 0); + qspi_write32(®s->buf2ind, 0); + + /* + * Set the default lut sequence for AHB Read. + * Parallel mode is disabled. + */ + qspi_write32(®s->bfgencr, + SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT); + + /*Enable DDR Mode*/ + qspi_enable_ddr_mode(regs); +} +#endif + void spi_init() { /* do nothing */ @@ -186,18 +377,28 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, { struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; - u32 reg_val, smpr_val; - u32 total_size, seq_id; + u32 smpr_val; + u32 total_size; if (bus >= ARRAY_SIZE(spi_bases)) return NULL; + if (cs >= FSL_QSPI_FLASH_NUM) + return NULL; + qspi = spi_alloc_slave(struct fsl_qspi, bus, cs); if (!qspi) return NULL; qspi->reg_base = spi_bases[bus]; - qspi->amba_base = amba_bases[bus]; + /* + * According cs, use different amba_base to choose the + * corresponding flash devices. + * + * If not, only one flash device is used even if passing + * different cs using `sf probe` + */ + qspi->amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE; qspi->slave.max_write_size = TX_BUFFER_SIZE; @@ -210,10 +411,20 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; - qspi_write32(®s->sfa1ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); - qspi_write32(®s->sfa2ad, FSL_QSPI_FLASH_SIZE | qspi->amba_base); - qspi_write32(®s->sfb1ad, total_size | qspi->amba_base); - qspi_write32(®s->sfb2ad, total_size | qspi->amba_base); + /* + * Any read access to non-implemented addresses will provide + * undefined results. + * + * In case single die flash devices, TOP_ADDR_MEMA2 and + * TOP_ADDR_MEMB2 should be initialized/programmed to + * TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect, + * setting the size of these devices to 0. This would ensure + * that the complete memory map is assigned to only one flash device. + */ + qspi_write32(®s->sfa1ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]); + qspi_write32(®s->sfa2ad, FSL_QSPI_FLASH_SIZE | amba_bases[bus]); + qspi_write32(®s->sfb1ad, total_size | amba_bases[bus]); + qspi_write32(®s->sfb2ad, total_size | amba_bases[bus]); qspi_set_lut(qspi); @@ -222,13 +433,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, qspi_write32(®s->smpr, smpr_val); qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); - seq_id = 0; - reg_val = qspi_read32(®s->bfgencr); - reg_val &= ~QSPI_BFGENCR_SEQID_MASK; - reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT); - reg_val &= ~QSPI_BFGENCR_PAR_EN_MASK; - qspi_write32(®s->bfgencr, reg_val); - +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_init_ahb_read(regs); +#endif return &qspi->slave; } @@ -244,6 +451,47 @@ int spi_claim_bus(struct spi_slave *slave) return 0; } +#ifdef CONFIG_SPI_FLASH_BAR +/* Bank register read/write, EAR register read/write */ +static void qspi_op_rdbank(struct fsl_qspi *qspi, u8 *rxbuf, u32 len) +{ + struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + u32 reg, mcr_reg, data, seqid; + + mcr_reg = qspi_read32(®s->mcr); + qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); + qspi_write32(®s->rbct, QSPI_RBCT_RXBRD_USEIPS); + + qspi_write32(®s->sfar, qspi->amba_base); + + if (qspi->cur_seqid == QSPI_CMD_BRRD) + seqid = SEQID_BRRD; + else + seqid = SEQID_RDEAR; + + qspi_write32(®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len); + + /* Wait previous command complete */ + while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) + ; + + while (1) { + reg = qspi_read32(®s->rbsr); + if (reg & QSPI_RBSR_RDBFL_MASK) { + data = qspi_read32(®s->rbdr[0]); + data = qspi_endian_xchg(data); + memcpy(rxbuf, &data, len); + qspi_write32(®s->mcr, qspi_read32(®s->mcr) | + QSPI_MCR_CLR_RXF_MASK); + break; + } + } + + qspi_write32(®s->mcr, mcr_reg); +} +#endif + static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; @@ -278,6 +526,8 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) qspi_write32(®s->mcr, mcr_reg); } +#ifndef CONFIG_SYS_FSL_QSPI_AHB +/* If not use AHB read, read data from ip interface */ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; @@ -321,11 +571,12 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len) qspi_write32(®s->mcr, mcr_reg); } +#endif -static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len) +static void qspi_op_write(struct fsl_qspi *qspi, u8 *txbuf, u32 len) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; - u32 mcr_reg, data, reg, status_reg; + u32 mcr_reg, data, reg, status_reg, seqid; int i, size, tx_size; u32 to_or_from = 0; @@ -355,22 +606,39 @@ static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len) qspi_read32(®s->mcr) | QSPI_MCR_CLR_RXF_MASK); } + /* Default is page programming */ + seqid = SEQID_PP; +#ifdef CONFIG_SPI_FLASH_BAR + if (qspi->cur_seqid == QSPI_CMD_BRWR) + seqid = SEQID_BRWR; + else if (qspi->cur_seqid == QSPI_CMD_WREAR) + seqid = SEQID_WREAR; +#endif + to_or_from = qspi->sf_addr + qspi->amba_base; + qspi_write32(®s->sfar, to_or_from); tx_size = (len > TX_BUFFER_SIZE) ? TX_BUFFER_SIZE : len; - size = (tx_size + 3) / 4; - + size = tx_size / 4; for (i = 0; i < size; i++) { - data = qspi_endian_xchg(*txbuf); + memcpy(&data, txbuf, 4); + data = qspi_endian_xchg(data); qspi_write32(®s->tbdr, data); - txbuf++; + txbuf += 4; } - qspi_write32(®s->ipcr, - (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size); + size = tx_size % 4; + if (size) { + data = 0; + memcpy(&data, txbuf, size); + data = qspi_endian_xchg(data); + qspi_write32(®s->tbdr, data); + } + + qspi_write32(®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; @@ -409,7 +677,7 @@ static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf) qspi_write32(®s->mcr, mcr_reg); } -static void qspi_op_se(struct fsl_qspi *qspi) +static void qspi_op_erase(struct fsl_qspi *qspi) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; u32 mcr_reg; @@ -428,8 +696,13 @@ static void qspi_op_se(struct fsl_qspi *qspi) while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; - qspi_write32(®s->ipcr, - (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); + if (qspi->cur_seqid == QSPI_CMD_SE) { + qspi_write32(®s->ipcr, + (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); + } else if (qspi->cur_seqid == QSPI_CMD_BE_4K) { + qspi_write32(®s->ipcr, + (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0); + } while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; @@ -441,38 +714,67 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct fsl_qspi *qspi = to_qspi_spi(slave); u32 bytes = DIV_ROUND_UP(bitlen, 8); - static u32 pp_sfaddr; + static u32 wr_sfaddr; u32 txbuf; if (dout) { - memcpy(&txbuf, dout, 4); - qspi->cur_seqid = *(u8 *)dout; + if (flags & SPI_XFER_BEGIN) { + qspi->cur_seqid = *(u8 *)dout; + memcpy(&txbuf, dout, 4); + } if (flags == SPI_XFER_END) { - qspi->sf_addr = pp_sfaddr; - qspi_op_pp(qspi, (u32 *)dout, bytes); + qspi->sf_addr = wr_sfaddr; + qspi_op_write(qspi, (u8 *)dout, bytes); return 0; } - if (qspi->cur_seqid == OPCODE_FAST_READ) { + if (qspi->cur_seqid == QSPI_CMD_FAST_READ) { qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; - } else if (qspi->cur_seqid == OPCODE_SE) { + } else if ((qspi->cur_seqid == QSPI_CMD_SE) || + (qspi->cur_seqid == QSPI_CMD_BE_4K)) { qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; - qspi_op_se(qspi); - } else if (qspi->cur_seqid == OPCODE_PP) { - pp_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; + qspi_op_erase(qspi); + } else if (qspi->cur_seqid == QSPI_CMD_PP) + wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; +#ifdef CONFIG_SPI_FLASH_BAR + else if ((qspi->cur_seqid == QSPI_CMD_BRWR) || + (qspi->cur_seqid == QSPI_CMD_WREAR)) { + wr_sfaddr = 0; } +#endif } if (din) { - if (qspi->cur_seqid == OPCODE_FAST_READ) + if (qspi->cur_seqid == QSPI_CMD_FAST_READ) { +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_ahb_read(qspi, din, bytes); +#else qspi_op_read(qspi, din, bytes); - else if (qspi->cur_seqid == OPCODE_RDID) +#endif + } + else if (qspi->cur_seqid == QSPI_CMD_RDID) qspi_op_rdid(qspi, din, bytes); - else if (qspi->cur_seqid == OPCODE_RDSR) + else if (qspi->cur_seqid == QSPI_CMD_RDSR) qspi_op_rdsr(qspi, din); +#ifdef CONFIG_SPI_FLASH_BAR + else if ((qspi->cur_seqid == QSPI_CMD_BRRD) || + (qspi->cur_seqid == QSPI_CMD_RDEAR)) { + qspi->sf_addr = 0; + qspi_op_rdbank(qspi, din, bytes); + } +#endif } +#ifdef CONFIG_SYS_FSL_QSPI_AHB + if ((qspi->cur_seqid == QSPI_CMD_SE) || + (qspi->cur_seqid == QSPI_CMD_PP) || + (qspi->cur_seqid == QSPI_CMD_BE_4K) || + (qspi->cur_seqid == QSPI_CMD_WREAR) || + (qspi->cur_seqid == QSPI_CMD_BRWR)) + qspi_ahb_invalid(qspi); +#endif + return 0; }