diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 5e0b069274..868df5f121 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 Freescale Semiconductor, Inc. + * Copyright 2013-2015 Freescale Semiconductor, Inc. * * Freescale Quad Serial Peripheral Interface (QSPI) driver * @@ -11,8 +11,12 @@ #include #include #include +#include +#include #include "fsl_qspi.h" +DECLARE_GLOBAL_DATA_PTR; + #define RX_BUFFER_SIZE 0x80 #ifdef CONFIG_MX6SX #define TX_BUFFER_SIZE 0x200 @@ -63,35 +67,85 @@ #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 -#define qspi_write32 out_le32 -#elif defined(CONFIG_SYS_FSL_QSPI_BE) -#define qspi_read32 in_be32 -#define qspi_write32 out_be32 +/* fsl_qspi_platdata flags */ +#define QSPI_FLAG_REGMAP_ENDIAN_BIG (1 << 0) + +/* default SCK frequency, unit: HZ */ +#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000 + +/* QSPI max chipselect signals number */ +#define FSL_QSPI_MAX_CHIPSELECT_NUM 4 + +#ifdef CONFIG_DM_SPI +/** + * struct fsl_qspi_platdata - platform data for Freescale QSPI + * + * @flags: Flags for QSPI QSPI_FLAG_... + * @speed_hz: Default SCK frequency + * @reg_base: Base address of QSPI registers + * @amba_base: Base address of QSPI memory mapping + * @amba_total_size: size of QSPI memory mapping + * @flash_num: Number of active slave devices + * @num_chipselect: Number of QSPI chipselect signals + */ +struct fsl_qspi_platdata { + u32 flags; + u32 speed_hz; + u32 reg_base; + u32 amba_base; + u32 amba_total_size; + u32 flash_num; + u32 num_chipselect; +}; #endif -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_priv - private data for Freescale QSPI + * + * @flags: Flags for QSPI QSPI_FLAG_... + * @bus_clk: QSPI input clk frequency + * @speed_hz: Default SCK frequency + * @cur_seqid: current LUT table sequence id + * @sf_addr: flash access offset + * @amba_base: Base address of QSPI memory mapping of every CS + * @amba_total_size: size of QSPI memory mapping + * @cur_amba_base: Base address of QSPI memory mapping of current CS + * @flash_num: Number of active slave devices + * @num_chipselect: Number of QSPI chipselect signals + * @regs: Point to QSPI register structure for I/O access + */ +struct fsl_qspi_priv { + u32 flags; + u32 bus_clk; + u32 speed_hz; + u32 cur_seqid; + u32 sf_addr; + u32 amba_base[FSL_QSPI_MAX_CHIPSELECT_NUM]; + u32 amba_total_size; + u32 cur_amba_base; + u32 flash_num; + u32 num_chipselect; + struct fsl_qspi_regs *regs; }; +#ifndef CONFIG_DM_SPI struct fsl_qspi { struct spi_slave slave; - unsigned long reg_base; - unsigned long amba_base; - u32 sf_addr; - u8 cur_seqid; + struct fsl_qspi_priv priv; }; +#endif + +static u32 qspi_read32(u32 flags, u32 *addr) +{ + return flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? + in_be32(addr) : in_le32(addr); +} + +static void qspi_write32(u32 flags, u32 *addr, u32 val) +{ + flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? + out_be32(addr, val) : out_le32(addr, val); +} /* QSPI support swapping the flash read/write data * in hardware for LS102xA, but not for VF610 */ @@ -104,131 +158,135 @@ static inline u32 qspi_endian_xchg(u32 data) #endif } -static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) +static void qspi_set_lut(struct fsl_qspi_priv *priv) { - return container_of(slave, struct fsl_qspi, slave); -} - -static void qspi_set_lut(struct fsl_qspi *qspi) -{ - struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; + struct fsl_qspi_regs *regs = priv->regs; u32 lut_base; /* Unlock the LUT */ - qspi_write32(®s->lutkey, LUT_KEY_VALUE); - qspi_write32(®s->lckcr, QSPI_LCKCR_UNLOCK); + qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); + qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_UNLOCK); /* Write Enable */ lut_base = SEQID_WREN * 4; - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_WREN) | + qspi_write32(priv->flags, ®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); - qspi_write32(®s->lut[lut_base + 3], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* 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) | + qspi_write32(priv->flags, ®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(QSPI_CMD_FAST_READ) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®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], + qspi_write32(priv->flags, ®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)); - qspi_write32(®s->lut[lut_base + 2], 0); - qspi_write32(®s->lut[lut_base + 3], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], + OPRND0(8) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) | + OPRND1(RX_BUFFER_SIZE) | PAD1(LUT_PAD1) | + INSTR1(LUT_READ)); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* Read Status */ lut_base = SEQID_RDSR * 4; - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_RDSR) | + qspi_write32(priv->flags, ®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); - qspi_write32(®s->lut[lut_base + 2], 0); - qspi_write32(®s->lut[lut_base + 3], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* Erase a sector */ lut_base = SEQID_SE * 4; #ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_SE) | + qspi_write32(priv->flags, ®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(QSPI_CMD_SE) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®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(QSPI_CMD_SE_4B) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* Erase the whole chip */ lut_base = SEQID_CHIP_ERASE * 4; - 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); - qspi_write32(®s->lut[lut_base + 3], 0); + qspi_write32(priv->flags, ®s->lut[lut_base], + OPRND0(QSPI_CMD_CHIP_ERASE) | + PAD0(LUT_PAD1) | INSTR0(LUT_CMD)); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* Page Program */ lut_base = SEQID_PP * 4; #ifdef CONFIG_SPI_FLASH_BAR - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_PP) | + qspi_write32(priv->flags, ®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(QSPI_CMD_PP) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®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(QSPI_CMD_PP_4B) | - PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) | - PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); + qspi_write32(priv->flags, ®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) | + qspi_write32(priv->flags, ®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)); + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 3], 0); /* READ ID */ lut_base = SEQID_RDID * 4; - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_RDID) | + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->lut[lut_base + 1], 0); + qspi_write32(priv->flags, ®s->lut[lut_base + 2], 0); + qspi_write32(priv->flags, ®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) | + qspi_write32(priv->flags, ®s->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) | PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) | PAD1(LUT_PAD1) | INSTR1(LUT_ADDR)); @@ -239,28 +297,28 @@ static void qspi_set_lut(struct fsl_qspi *qspi) * initialization. */ lut_base = SEQID_BRRD * 4; - qspi_write32(®s->lut[lut_base], OPRND0(QSPI_CMD_BRRD) | + qspi_write32(priv->flags, ®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) | + qspi_write32(priv->flags, ®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) | + qspi_write32(priv->flags, ®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) | + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->lutkey, LUT_KEY_VALUE); + qspi_write32(priv->flags, ®s->lckcr, QSPI_LCKCR_LOCK); } #if defined(CONFIG_SYS_FSL_QSPI_AHB) @@ -270,14 +328,14 @@ static void qspi_set_lut(struct fsl_qspi *qspi) * 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) +static inline void qspi_ahb_invalid(struct fsl_qspi_priv *priv) { - struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + struct fsl_qspi_regs *regs = priv->regs; u32 reg; - reg = qspi_read32(®s->mcr); + reg = qspi_read32(priv->flags, ®s->mcr); reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK; - qspi_write32(®s->mcr, reg); + qspi_write32(priv->flags, ®s->mcr, reg); /* * The minimum delay : 1 AHB + 2 SFCK clocks. @@ -286,46 +344,48 @@ static inline void qspi_ahb_invalid(struct fsl_qspi *q) udelay(1); reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK); - qspi_write32(®s->mcr, reg); + qspi_write32(priv->flags, ®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) +static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len) { - struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)q->reg_base; + struct fsl_qspi_regs *regs = priv->regs; u32 mcr_reg; - mcr_reg = qspi_read32(®s->mcr); + mcr_reg = qspi_read32(priv->flags, ®s->mcr); - qspi_write32(®s->mcr, QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK | + 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); /* Read out the data directly from the AHB buffer. */ - memcpy(rxbuf, (u8 *)(q->amba_base + q->sf_addr), len); + memcpy(rxbuf, (u8 *)(priv->cur_amba_base + priv->sf_addr), len); - qspi_write32(®s->mcr, mcr_reg); + qspi_write32(priv->flags, ®s->mcr, mcr_reg); } -static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs) +static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv) { u32 reg, reg2; + struct fsl_qspi_regs *regs = priv->regs; - reg = qspi_read32(®s->mcr); + reg = qspi_read32(priv->flags, ®s->mcr); /* Disable the module */ - qspi_write32(®s->mcr, reg | QSPI_MCR_MDIS_MASK); + qspi_write32(priv->flags, ®s->mcr, reg | QSPI_MCR_MDIS_MASK); /* Set the Sampling Register for DDR */ - reg2 = qspi_read32(®s->smpr); + reg2 = qspi_read32(priv->flags, ®s->smpr); reg2 &= ~QSPI_SMPR_DDRSMP_MASK; reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT); - qspi_write32(®s->smpr, reg2); + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->mcr, reg); } /* @@ -341,35 +401,412 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_regs *regs) * 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) +static void qspi_init_ahb_read(struct fsl_qspi_priv *priv) { + struct fsl_qspi_regs *regs = priv->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 | + qspi_write32(priv->flags, ®s->buf0cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(priv->flags, ®s->buf1cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(priv->flags, ®s->buf2cr, QSPI_BUFXCR_INVALID_MSTRID); + qspi_write32(priv->flags, ®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); + qspi_write32(priv->flags, ®s->buf0ind, 0); + qspi_write32(priv->flags, ®s->buf1ind, 0); + qspi_write32(priv->flags, ®s->buf2ind, 0); /* * Set the default lut sequence for AHB Read. * Parallel mode is disabled. */ - qspi_write32(®s->bfgencr, + qspi_write32(priv->flags, ®s->bfgencr, SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT); /*Enable DDR Mode*/ - qspi_enable_ddr_mode(regs); + qspi_enable_ddr_mode(priv); } #endif -void spi_init() +#ifdef CONFIG_SPI_FLASH_BAR +/* Bank register read/write, EAR register read/write */ +static void qspi_op_rdbank(struct fsl_qspi_priv *priv, u8 *rxbuf, u32 len) { - /* do nothing */ + 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); +} +#endif + +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; + int i, size; + + 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; + size = len; + while ((RX_BUFFER_SIZE >= size) && (size > 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); + memcpy(rxbuf, &data, 4); + rxbuf++; + size -= 4; + i++; + } + } + + qspi_write32(priv->flags, ®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_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) { + 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); +} +#endif + +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) { + 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); +} + +static void qspi_op_rdsr(struct fsl_qspi_priv *priv, u32 *rxbuf) +{ + 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, 4); + 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_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); +} + +int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + u32 bytes = DIV_ROUND_UP(bitlen, 8); + static u32 wr_sfaddr; + u32 txbuf; + + if (dout) { + if (flags & SPI_XFER_BEGIN) { + priv->cur_seqid = *(u8 *)dout; + memcpy(&txbuf, dout, 4); + } + + if (flags == SPI_XFER_END) { + priv->sf_addr = wr_sfaddr; + qspi_op_write(priv, (u8 *)dout, bytes); + return 0; + } + + if (priv->cur_seqid == QSPI_CMD_FAST_READ) { + priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + } else if ((priv->cur_seqid == QSPI_CMD_SE) || + (priv->cur_seqid == QSPI_CMD_BE_4K)) { + priv->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; + qspi_op_erase(priv); + } else if (priv->cur_seqid == QSPI_CMD_PP) { + wr_sfaddr = swab32(txbuf) & OFFSET_BITS_MASK; + } else if ((priv->cur_seqid == QSPI_CMD_BRWR) || + (priv->cur_seqid == QSPI_CMD_WREAR)) { +#ifdef CONFIG_SPI_FLASH_BAR + wr_sfaddr = 0; +#endif + } + } + + if (din) { + if (priv->cur_seqid == QSPI_CMD_FAST_READ) { +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_ahb_read(priv, din, bytes); +#else + qspi_op_read(priv, din, bytes); +#endif + } else if (priv->cur_seqid == QSPI_CMD_RDID) + qspi_op_rdid(priv, din, bytes); + else if (priv->cur_seqid == QSPI_CMD_RDSR) + qspi_op_rdsr(priv, din); +#ifdef CONFIG_SPI_FLASH_BAR + else if ((priv->cur_seqid == QSPI_CMD_BRRD) || + (priv->cur_seqid == QSPI_CMD_RDEAR)) { + priv->sf_addr = 0; + qspi_op_rdbank(priv, din, bytes); + } +#endif + } + +#ifdef CONFIG_SYS_FSL_QSPI_AHB + if ((priv->cur_seqid == QSPI_CMD_SE) || + (priv->cur_seqid == QSPI_CMD_PP) || + (priv->cur_seqid == QSPI_CMD_BE_4K) || + (priv->cur_seqid == QSPI_CMD_WREAR) || + (priv->cur_seqid == QSPI_CMD_BRWR)) + qspi_ahb_invalid(priv); +#endif + + return 0; +} + +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); +} + +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); +} +#ifndef CONFIG_DM_SPI +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 +}; + +static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave) +{ + return container_of(slave, struct fsl_qspi, slave); } struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, @@ -377,7 +814,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, { struct fsl_qspi *qspi; struct fsl_qspi_regs *regs; - u32 smpr_val; u32 total_size; if (bus >= ARRAY_SIZE(spi_bases)) @@ -390,7 +826,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (!qspi) return NULL; - qspi->reg_base = spi_bases[bus]; +#ifdef CONFIG_SYS_FSL_QSPI_BE + qspi->priv.flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG; +#endif + + regs = (struct fsl_qspi_regs *)spi_bases[bus]; + qspi->priv.regs = regs; /* * According cs, use different amba_base to choose the * corresponding flash devices. @@ -398,17 +839,16 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, * 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->priv.cur_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); + qspi_write32(qspi->priv.flags, ®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); + qspi_cfg_smpr(&qspi->priv, + ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | + QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0); total_size = FSL_QSPI_FLASH_SIZE * FSL_QSPI_FLASH_NUM; /* @@ -421,21 +861,23 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, * 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_write32(qspi->priv.flags, ®s->sfa1ad, + FSL_QSPI_FLASH_SIZE | amba_bases[bus]); + qspi_write32(qspi->priv.flags, ®s->sfa2ad, + FSL_QSPI_FLASH_SIZE | amba_bases[bus]); + qspi_write32(qspi->priv.flags, ®s->sfb1ad, + total_size | amba_bases[bus]); + qspi_write32(qspi->priv.flags, ®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); + qspi_set_lut(&qspi->priv); #ifdef CONFIG_SYS_FSL_QSPI_AHB - qspi_init_ahb_read(regs); + qspi_init_ahb_read(&qspi->priv); #endif + + qspi_module_disable(&qspi->priv, 0); + return &qspi->slave; } @@ -451,334 +893,219 @@ 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) +void spi_release_bus(struct spi_slave *slave) { - 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; - 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); -} - -#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; - u32 mcr_reg, data; - int i, size; - u32 to_or_from; - - 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; - - while (len > 0) { - qspi_write32(®s->sfar, to_or_from); - - size = (len > RX_BUFFER_SIZE) ? - RX_BUFFER_SIZE : len; - - qspi_write32(®s->ipcr, - (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) | size); - while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK) - ; - - to_or_from += size; - len -= size; - - i = 0; - while ((RX_BUFFER_SIZE >= size) && (size > 0)) { - data = qspi_read32(®s->rbdr[i]); - data = qspi_endian_xchg(data); - memcpy(rxbuf, &data, 4); - rxbuf++; - size -= 4; - i++; - } - qspi_write32(®s->mcr, qspi_read32(®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - } - - qspi_write32(®s->mcr, mcr_reg); -} -#endif - -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, seqid; - 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); - } - - /* 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 / 4; - for (i = 0; i < size; i++) { - memcpy(&data, txbuf, 4); - data = qspi_endian_xchg(data); - qspi_write32(®s->tbdr, data); - txbuf += 4; - } - - 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) - ; - - qspi_write32(®s->mcr, mcr_reg); -} - -static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf) -{ - struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base; - u32 mcr_reg, reg, data; - - 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_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0); - 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, 4); - qspi_write32(®s->mcr, qspi_read32(®s->mcr) | - QSPI_MCR_CLR_RXF_MASK); - break; - } - } - - qspi_write32(®s->mcr, mcr_reg); -} - -static void qspi_op_erase(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) - ; - - 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) - ; - - qspi_write32(®s->mcr, mcr_reg); + /* Nothing to do */ } int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct fsl_qspi *qspi = to_qspi_spi(slave); - u32 bytes = DIV_ROUND_UP(bitlen, 8); - static u32 wr_sfaddr; - u32 txbuf; - if (dout) { - if (flags & SPI_XFER_BEGIN) { - qspi->cur_seqid = *(u8 *)dout; - memcpy(&txbuf, dout, 4); - } + return qspi_xfer(&qspi->priv, bitlen, dout, din, flags); +} - if (flags == SPI_XFER_END) { - qspi->sf_addr = wr_sfaddr; - qspi_op_write(qspi, (u8 *)dout, bytes); - return 0; - } - - if (qspi->cur_seqid == QSPI_CMD_FAST_READ) { - qspi->sf_addr = swab32(txbuf) & OFFSET_BITS_MASK; - } 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_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 == QSPI_CMD_FAST_READ) { -#ifdef CONFIG_SYS_FSL_QSPI_AHB - qspi_ahb_read(qspi, din, bytes); +void spi_init(void) +{ + /* Nothing to do */ +} #else - qspi_op_read(qspi, din, bytes); -#endif - } - else if (qspi->cur_seqid == QSPI_CMD_RDID) - qspi_op_rdid(qspi, din, bytes); - 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 - } +static int fsl_qspi_child_pre_probe(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parentdata(dev); -#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 + slave->max_write_size = TX_BUFFER_SIZE; return 0; } -void spi_release_bus(struct spi_slave *slave) +static int fsl_qspi_probe(struct udevice *bus) +{ + u32 total_size; + struct fsl_qspi_platdata *plat = dev_get_platdata(bus); + struct fsl_qspi_priv *priv = dev_get_priv(bus); + struct dm_spi_bus *dm_spi_bus; + + dm_spi_bus = bus->uclass_priv; + + dm_spi_bus->max_hz = plat->speed_hz; + + priv->regs = (struct fsl_qspi_regs *)plat->reg_base; + priv->flags = plat->flags; + + priv->speed_hz = plat->speed_hz; + priv->amba_base[0] = plat->amba_base; + priv->amba_total_size = plat->amba_total_size; + priv->flash_num = plat->flash_num; + priv->num_chipselect = plat->num_chipselect; + + qspi_write32(priv->flags, &priv->regs->mcr, + QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK); + + qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK | + QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0); + + 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(priv->flags, &priv->regs->sfa1ad, + FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); + qspi_write32(priv->flags, &priv->regs->sfa2ad, + FSL_QSPI_FLASH_SIZE | priv->amba_base[0]); + qspi_write32(priv->flags, &priv->regs->sfb1ad, + total_size | priv->amba_base[0]); + qspi_write32(priv->flags, &priv->regs->sfb2ad, + total_size | priv->amba_base[0]); + + qspi_set_lut(priv); + +#ifdef CONFIG_SYS_FSL_QSPI_AHB + qspi_init_ahb_read(priv); +#endif + + qspi_module_disable(priv, 0); + + return 0; +} + +static int fsl_qspi_ofdata_to_platdata(struct udevice *bus) +{ + struct reg_data { + u32 addr; + u32 size; + } regs_data[2]; + struct fsl_qspi_platdata *plat = bus->platdata; + const void *blob = gd->fdt_blob; + int node = bus->of_offset; + int ret, flash_num = 0, subnode; + + if (fdtdec_get_bool(blob, node, "big-endian")) + plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG; + + ret = fdtdec_get_int_array(blob, node, "reg", (u32 *)regs_data, + sizeof(regs_data)/sizeof(u32)); + if (ret) { + debug("Error: can't get base addresses (ret = %d)!\n", ret); + return -ENOMEM; + } + + /* Count flash numbers */ + fdt_for_each_subnode(blob, subnode, node) + ++flash_num; + + if (flash_num == 0) { + debug("Error: Missing flashes!\n"); + return -ENODEV; + } + + plat->speed_hz = fdtdec_get_int(blob, node, "spi-max-frequency", + FSL_QSPI_DEFAULT_SCK_FREQ); + plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs", + FSL_QSPI_MAX_CHIPSELECT_NUM); + + plat->reg_base = regs_data[0].addr; + plat->amba_base = regs_data[1].addr; + plat->amba_total_size = regs_data[1].size; + plat->flash_num = flash_num; + + debug("%s: regs=<0x%x> <0x%x, 0x%x>, max-frequency=%d, endianess=%s\n", + __func__, + plat->reg_base, + plat->amba_base, + plat->amba_total_size, + plat->speed_hz, + plat->flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le" + ); + + return 0; +} + +static int fsl_qspi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct fsl_qspi_priv *priv; + struct udevice *bus; + + bus = dev->parent; + priv = dev_get_priv(bus); + + return qspi_xfer(priv, bitlen, dout, din, flags); +} + +static int fsl_qspi_claim_bus(struct udevice *dev) +{ + struct fsl_qspi_priv *priv; + struct udevice *bus; + struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + + bus = dev->parent; + priv = dev_get_priv(bus); + + priv->cur_amba_base = + priv->amba_base[0] + FSL_QSPI_FLASH_SIZE * slave_plat->cs; + + qspi_module_disable(priv, 0); + + return 0; +} + +static int fsl_qspi_release_bus(struct udevice *dev) +{ + struct fsl_qspi_priv *priv; + struct udevice *bus; + + bus = dev->parent; + priv = dev_get_priv(bus); + + qspi_module_disable(priv, 1); + + return 0; +} + +static int fsl_qspi_set_speed(struct udevice *bus, uint speed) { /* Nothing to do */ + return 0; } + +static int fsl_qspi_set_mode(struct udevice *bus, uint mode) +{ + /* Nothing to do */ + return 0; +} + +static const struct dm_spi_ops fsl_qspi_ops = { + .claim_bus = fsl_qspi_claim_bus, + .release_bus = fsl_qspi_release_bus, + .xfer = fsl_qspi_xfer, + .set_speed = fsl_qspi_set_speed, + .set_mode = fsl_qspi_set_mode, +}; + +static const struct udevice_id fsl_qspi_ids[] = { + { .compatible = "fsl,vf610-qspi" }, + { .compatible = "fsl,imx6sx-qspi" }, + { } +}; + +U_BOOT_DRIVER(fsl_qspi) = { + .name = "fsl_qspi", + .id = UCLASS_SPI, + .of_match = fsl_qspi_ids, + .ops = &fsl_qspi_ops, + .ofdata_to_platdata = fsl_qspi_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct fsl_qspi_platdata), + .priv_auto_alloc_size = sizeof(struct fsl_qspi_priv), + .probe = fsl_qspi_probe, + .child_pre_probe = fsl_qspi_child_pre_probe, +}; +#endif