static void qspi_op_erase(struct fsl_qspi_priv *priv) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg; u32 to_or_from = 0; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); to_or_from = priv->sf_addr + priv->cur_amba_base; qspi_write32(priv->flags, ®s->sfar, to_or_from); qspi_write32(priv->flags, ®s->ipcr, (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; if (priv->cur_seqid == QSPI_CMD_SE) { qspi_write32(priv->flags, ®s->ipcr, (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); } else if (priv->cur_seqid == QSPI_CMD_BE_4K) { qspi_write32(priv->flags, ®s->ipcr, (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0); } while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
static void qspi_op_rdid(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg, rbsr_reg, data, size; int i; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); qspi_write32(priv->flags, ®s->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; i = 0; while ((RX_BUFFER_SIZE >= len) && (len > 0)) { rbsr_reg = qspi_read32(priv->flags, ®s->rbsr); if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(priv->flags, ®s->rbdr[i]); data = qspi_endian_xchg(data); size = (len < 4) ? len : 4; memcpy(rxbuf, &data, size); len -= size; rxbuf++; i++; } } qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
static void qspi_op_rdsr(struct fsl_qspi_priv *priv, void *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg, reg, data; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); qspi_write32(priv->flags, ®s->ipcr, (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; while (1) { reg = qspi_read32(priv->flags, ®s->rbsr); if (reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(priv->flags, ®s->rbdr[0]); data = qspi_endian_xchg(data); memcpy(rxbuf, &data, len); qspi_write32(priv->flags, ®s->mcr, qspi_read32(priv->flags, ®s->mcr) | QSPI_MCR_CLR_RXF_MASK); break; } } qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
static void qspi_op_se(struct fsl_qspi *qspi) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; u32 mcr_reg; u32 to_or_from = 0; 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); to_or_from = qspi->sf_addr + qspi->amba_base; qspi_write32(®s->sfar, to_or_from); qspi_write32(®s->ipcr, (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(®s->ipcr, (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(®s->mcr, mcr_reg); }
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; u32 mcr_reg, rbsr_reg, data; int i, size; 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); qspi_write32(®s->ipcr, (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; i = 0; size = len; while ((RX_BUFFER_SIZE >= size) && (size > 0)) { rbsr_reg = qspi_read32(®s->rbsr); if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(®s->rbdr[i]); data = qspi_endian_xchg(data); memcpy(rxbuf, &data, 4); rxbuf++; size -= 4; i++; } } qspi_write32(®s->mcr, mcr_reg); }
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; u32 reg_val, smpr_val; u32 total_size, seq_id; if (bus >= ARRAY_SIZE(spi_bases)) 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]; qspi->slave.max_write_size = TX_BUFFER_SIZE; regs = (struct fsl_qspi_regs *)qspi->reg_base; qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); smpr_val = qspi_read32(®s->smpr); qspi_write32(®s->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK)); 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); qspi_set_lut(qspi); smpr_val = qspi_read32(®s->smpr); smpr_val &= ~QSPI_SMPR_DDRSMP_MASK; 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); return &qspi->slave; }
/* If not use AHB read, read data from ip interface */ static void qspi_op_read(struct fsl_qspi_priv *priv, u32 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg, data; int i, size; u32 to_or_from; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); to_or_from = priv->sf_addr + priv->cur_amba_base; while (len > 0) { WATCHDOG_RESET(); qspi_write32(priv->flags, ®s->sfar, to_or_from); size = (len > RX_BUFFER_SIZE) ? RX_BUFFER_SIZE : len; qspi_write32(priv->flags, ®s->ipcr, (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; to_or_from += size; len -= size; i = 0; while ((RX_BUFFER_SIZE >= size) && (size > 0)) { data = qspi_read32(priv->flags, ®s->rbdr[i]); data = qspi_endian_xchg(data); memcpy(rxbuf, &data, 4); rxbuf++; size -= 4; i++; } qspi_write32(priv->flags, ®s->mcr, qspi_read32(priv->flags, ®s->mcr) | QSPI_MCR_CLR_RXF_MASK); } qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits) { u32 smpr_val; smpr_val = qspi_read32(priv->flags, &priv->regs->smpr); smpr_val &= ~clear_bits; smpr_val |= set_bits; qspi_write32(priv->flags, &priv->regs->smpr, smpr_val); }
void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable) { u32 mcr_val; mcr_val = qspi_read32(priv->flags, &priv->regs->mcr); if (disable) mcr_val |= QSPI_MCR_MDIS_MASK; else mcr_val &= ~QSPI_MCR_MDIS_MASK; qspi_write32(priv->flags, &priv->regs->mcr, mcr_val); }
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); }
/* Bank register read/write, EAR register read/write */ static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 reg, mcr_reg, data, seqid; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); qspi_write32(priv->flags, ®s->sfar, priv->cur_amba_base); if (priv->cur_seqid == QSPI_CMD_BRRD) seqid = SEQID_BRRD; else seqid = SEQID_RDEAR; qspi_write32(priv->flags, ®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | len); /* Wait previous command complete */ while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; while (1) { reg = qspi_read32(priv->flags, ®s->rbsr); if (reg & QSPI_RBSR_RDBFL_MASK) { data = qspi_read32(priv->flags, ®s->rbdr[0]); data = qspi_endian_xchg(data); memcpy(rxbuf, &data, len); qspi_write32(priv->flags, ®s->mcr, qspi_read32(priv->flags, ®s->mcr) | QSPI_MCR_CLR_RXF_MASK); break; } } qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len) { struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; u32 mcr_reg, data, reg, status_reg; int i, size, tx_size; u32 to_or_from = 0; 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); status_reg = 0; while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { qspi_write32(®s->ipcr, (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(®s->ipcr, (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; reg = qspi_read32(®s->rbsr); if (reg & QSPI_RBSR_RDBFL_MASK) { status_reg = qspi_read32(®s->rbdr[0]); status_reg = qspi_endian_xchg(status_reg); } qspi_write32(®s->mcr, qspi_read32(®s->mcr) | QSPI_MCR_CLR_RXF_MASK); } 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; for (i = 0; i < size; i++) { data = qspi_endian_xchg(*txbuf); qspi_write32(®s->tbdr, data); txbuf++; } qspi_write32(®s->ipcr, (SEQID_PP << QSPI_IPCR_SEQID_SHIFT) | tx_size); while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(®s->mcr, 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); }
/* * 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_priv *priv) { struct fsl_qspi_regs *regs = priv->regs; u32 reg; reg = qspi_read32(priv->flags, ®s->mcr); reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; qspi_write32(priv->flags, ®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(priv->flags, ®s->mcr, reg); }
static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len) { struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg, data, reg, status_reg, seqid; int i, size, tx_size; u32 to_or_from = 0; mcr_reg = qspi_read32(priv->flags, ®s->mcr); qspi_write32(priv->flags, ®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE); qspi_write32(priv->flags, ®s->rbct, QSPI_RBCT_RXBRD_USEIPS); status_reg = 0; while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) { WATCHDOG_RESET(); qspi_write32(priv->flags, ®s->ipcr, (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(priv->flags, ®s->ipcr, (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; reg = qspi_read32(priv->flags, ®s->rbsr); if (reg & QSPI_RBSR_RDBFL_MASK) { status_reg = qspi_read32(priv->flags, ®s->rbdr[0]); status_reg = qspi_endian_xchg(status_reg); } qspi_write32(priv->flags, ®s->mcr, qspi_read32(priv->flags, ®s->mcr) | QSPI_MCR_CLR_RXF_MASK); } /* Default is page programming */ seqid = SEQID_PP; #ifdef CONFIG_SPI_FLASH_BAR if (priv->cur_seqid == QSPI_CMD_BRWR) seqid = SEQID_BRWR; else if (priv->cur_seqid == QSPI_CMD_WREAR) seqid = SEQID_WREAR; #endif to_or_from = priv->sf_addr + priv->cur_amba_base; qspi_write32(priv->flags, ®s->sfar, to_or_from); tx_size = (len > TX_BUFFER_SIZE) ? TX_BUFFER_SIZE : len; size = tx_size / 4; for (i = 0; i < size; i++) { memcpy(&data, txbuf, 4); data = qspi_endian_xchg(data); qspi_write32(priv->flags, ®s->tbdr, data); txbuf += 4; } size = tx_size % 4; if (size) { data = 0; memcpy(&data, txbuf, size); data = qspi_endian_xchg(data); qspi_write32(priv->flags, ®s->tbdr, data); } qspi_write32(priv->flags, ®s->ipcr, (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size); while (qspi_read32(priv->flags, ®s->sr) & QSPI_SR_BUSY_MASK) ; qspi_write32(priv->flags, ®s->mcr, mcr_reg); }
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; 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]; /* * 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; regs = (struct fsl_qspi_regs *)qspi->reg_base; qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); smpr_val = qspi_read32(®s->smpr); qspi_write32(®s->smpr, smpr_val & ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK)); qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; /* * 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); smpr_val = qspi_read32(®s->smpr); smpr_val &= ~QSPI_SMPR_DDRSMP_MASK; qspi_write32(®s->smpr, smpr_val); qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK); #ifdef CONFIG_SYS_FSL_QSPI_AHB qspi_init_ahb_read(regs); #endif return &qspi->slave; }