* [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd
2014-09-10 6:16 [U-Boot] [PATCH 0/3] Add QSPI support for mx6sxsabresd board Peng Fan
@ 2014-09-10 6:16 ` Peng Fan
2014-09-10 12:40 ` Fabio Estevam
2014-09-10 6:16 ` [U-Boot] [PATCH 2/3] QSPI: Enable write device registers Peng Fan
2014-09-10 6:16 ` [U-Boot] [PATCH 3/3] QSPI: Enable QSPI AHB read for MX6SX Peng Fan
2 siblings, 1 reply; 6+ messages in thread
From: Peng Fan @ 2014-09-10 6:16 UTC (permalink / raw)
To: u-boot
From: Peng Fan <van.freenix@gmail.com>
Add QuadSPI support for mx6sxsabresd board.
There are two 16MB S25FL128S flashes on board. They are connected to
QSPI2 interface. i.MX6SX supports two QuadSPI interfaces, QSPI1/2.
The two flash devices are connected to A1/B1 of QSPI2.
Signed-off-by: Peng Fan <van.freenix@gmail.com>
---
arch/arm/cpu/armv7/mx6/clock.c | 50 +++++++++++++++++++++++++++++
arch/arm/include/asm/arch-mx6/clock.h | 3 ++
board/freescale/mx6sxsabresd/mx6sxsabresd.c | 40 +++++++++++++++++++++++
drivers/spi/fsl_qspi.c | 30 +++++++++++++++++
include/configs/mx6sxsabresd.h | 14 ++++++++
5 files changed, 137 insertions(+)
diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c
index 820b8d5..8caa61d 100644
--- a/arch/arm/cpu/armv7/mx6/clock.c
+++ b/arch/arm/cpu/armv7/mx6/clock.c
@@ -340,6 +340,56 @@ static u32 get_mmdc_ch0_clk(void)
}
#endif
+#ifdef CONFIG_MX6SX
+/* qspi_num can be from 0 - 1 */
+void enable_qspi_clk(int qspi_num)
+{
+ u32 reg = 0;
+ /* Enable QuadSPI clock */
+ switch (qspi_num) {
+ case 0:
+ /* disable the clock gate */
+ clrbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK);
+
+ /* set 50M : (50 = 396 / 2 / 4) */
+ reg = readl(&imx_ccm->cscmr1);
+ reg &= ~(MXC_CCM_CSCMR1_QSPI1_PODF_MASK |
+ MXC_CCM_CSCMR1_QSPI1_CLK_SEL_MASK);
+ reg |= ((1 << MXC_CCM_CSCMR1_QSPI1_PODF_OFFSET) |
+ (2 << MXC_CCM_CSCMR1_QSPI1_CLK_SEL_OFFSET));
+ writel(reg, &imx_ccm->cscmr1);
+
+ /* enable the clock gate */
+ setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK);
+ break;
+ case 1:
+ /*
+ * disable the clock gate
+ * QSPI2 and GPMI_BCH_INPUT_GPMI_IO share the same clock gate,
+ * disable both of them.
+ */
+ clrbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK |
+ MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK);
+
+ /* set 50M : (50 = 396 / 2 / 4) */
+ reg = readl(&imx_ccm->cs2cdr);
+ reg &= ~(MXC_CCM_CS2CDR_QSPI2_CLK_PODF_MASK |
+ MXC_CCM_CS2CDR_QSPI2_CLK_PRED_MASK |
+ MXC_CCM_CS2CDR_QSPI2_CLK_SEL_MASK);
+ reg |= (MXC_CCM_CS2CDR_QSPI2_CLK_PRED(0x1) |
+ MXC_CCM_CS2CDR_QSPI2_CLK_SEL(0x3));
+ writel(reg, &imx_ccm->cs2cdr);
+
+ /*enable the clock gate*/
+ setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK |
+ MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK);
+ break;
+ default:
+ break;
+ }
+}
+#endif
+
#ifdef CONFIG_FEC_MXC
int enable_fec_anatop_clock(enum enet_freq freq)
{
diff --git a/arch/arm/include/asm/arch-mx6/clock.h b/arch/arm/include/asm/arch-mx6/clock.h
index 339c789..9d0ba7a 100644
--- a/arch/arm/include/asm/arch-mx6/clock.h
+++ b/arch/arm/include/asm/arch-mx6/clock.h
@@ -60,4 +60,7 @@ int enable_i2c_clk(unsigned char enable, unsigned i2c_num);
int enable_spi_clk(unsigned char enable, unsigned spi_num);
void enable_ipu_clock(void);
int enable_fec_anatop_clock(enum enet_freq freq);
+#ifdef CONFIG_MX6SX
+void enable_qspi_clk(int qspi_num);
+#endif
#endif /* __ASM_ARCH_CLOCK_H */
diff --git a/board/freescale/mx6sxsabresd/mx6sxsabresd.c b/board/freescale/mx6sxsabresd/mx6sxsabresd.c
index 5eaec1b..f9cad5a 100644
--- a/board/freescale/mx6sxsabresd/mx6sxsabresd.c
+++ b/board/freescale/mx6sxsabresd/mx6sxsabresd.c
@@ -272,11 +272,51 @@ int board_mmc_init(bd_t *bis)
return fsl_esdhc_initialize(bis, &usdhc_cfg[0]);
}
+#ifdef CONFIG_FSL_QSPI
+
+#define QSPI_PAD_CTRL1 \
+ (PAD_CTL_SRE_FAST | PAD_CTL_SPEED_HIGH | \
+ PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_40ohm)
+
+static iomux_v3_cfg_t const quadspi_pads[] = {
+ MX6_PAD_NAND_WP_B__QSPI2_A_DATA_0 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_READY_B__QSPI2_A_DATA_1 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_CE0_B__QSPI2_A_DATA_2 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_CE1_B__QSPI2_A_DATA_3 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_ALE__QSPI2_A_SS0_B | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_CLE__QSPI2_A_SCLK | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA07__QSPI2_A_DQS | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA01__QSPI2_B_DATA_0 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA00__QSPI2_B_DATA_1 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_WE_B__QSPI2_B_DATA_2 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_RE_B__QSPI2_B_DATA_3 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA03__QSPI2_B_SS0_B | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA02__QSPI2_B_SCLK | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+ MX6_PAD_NAND_DATA05__QSPI2_B_DQS | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+};
+
+int board_qspi_init(void)
+{
+ /* Set the iomux */
+ imx_iomux_v3_setup_multiple_pads(quadspi_pads,
+ ARRAY_SIZE(quadspi_pads));
+
+ /* Set the clock */
+ enable_qspi_clk(1);
+
+ return 0;
+}
+#endif
+
int board_init(void)
{
/* Address of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+#ifdef CONFIG_FSL_QSPI
+ board_qspi_init();
+#endif
+
return 0;
}
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index ba20bef..7e8d07e 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
@@ -52,11 +56,19 @@
#endif
static unsigned long spi_bases[] = {
+#ifdef CONFIG_MX6SX
+ CONFIG_QSPI_BASE,
+#else
QSPI0_BASE_ADDR,
+#endif
};
static unsigned long amba_bases[] = {
+#ifdef CONFIG_MX6SX
+ CONFIG_QSPI_MEMMAP_BASE,
+#else
QSPI0_AMBA_BASE,
+#endif
};
struct fsl_qspi {
@@ -157,8 +169,14 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_PP_4B) |
PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+#ifdef CONFIG_MX6SX
+ /* Use IDATSZ in IPCR to determine the size */
+ 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);
@@ -191,6 +209,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
if (bus >= ARRAY_SIZE(spi_bases))
return NULL;
+#ifdef CONFIG_MX6SX
+ if (cs > 1)
+ return NULL;
+#endif
qspi = spi_alloc_slave(struct fsl_qspi, bus, cs);
if (!qspi)
@@ -215,6 +237,14 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
qspi_write32(®s->sfb1ad, total_size | qspi->amba_base);
qspi_write32(®s->sfb2ad, total_size | qspi->amba_base);
+#ifdef CONFIG_MX6SX
+ /*
+ * According to cs, change the amba_base to choose the flashes
+ * bus:cs 0:0--A1, 0:1--B1
+ */
+ qspi->amba_base = qspi->amba_base + cs * FSL_QSPI_FLASH_SIZE;
+#endif
+
qspi_set_lut(qspi);
smpr_val = qspi_read32(®s->smpr);
diff --git a/include/configs/mx6sxsabresd.h b/include/configs/mx6sxsabresd.h
index 1eda65e..00031ec 100644
--- a/include/configs/mx6sxsabresd.h
+++ b/include/configs/mx6sxsabresd.h
@@ -201,6 +201,20 @@
/* FLASH and environment organization */
#define CONFIG_SYS_NO_FLASH
+#define CONFIG_FSL_QSPI
+
+#ifdef CONFIG_FSL_QSPI
+#define CONFIG_CMD_SF
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI_FLASH_SPANSION
+#define CONFIG_SPI_FLASH_STMICRO
+#define CONFIG_SYS_FSL_QSPI_LE
+#define CONFIG_QSPI_BASE QSPI2_BASE_ADDR
+#define CONFIG_QSPI_MEMMAP_BASE QSPI2_ARB_BASE_ADDR
+#define FSL_QSPI_FLASH_SIZE SZ_16M
+#define FSL_QSPI_FLASH_NUM 2
+#endif
+
#define CONFIG_ENV_OFFSET (6 * SZ_64K)
#define CONFIG_ENV_SIZE SZ_8K
#define CONFIG_ENV_IS_IN_MMC
--
1.8.4
^ permalink raw reply related [flat|nested] 6+ messages in thread* [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd
2014-09-10 6:16 ` [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd Peng Fan
@ 2014-09-10 12:40 ` Fabio Estevam
2014-09-10 13:43 ` Peng Fan
0 siblings, 1 reply; 6+ messages in thread
From: Fabio Estevam @ 2014-09-10 12:40 UTC (permalink / raw)
To: u-boot
On Wed, Sep 10, 2014 at 3:16 AM, Peng Fan <Peng.Fan@freescale.com> wrote:
> From: Peng Fan <van.freenix@gmail.com>
>
> Add QuadSPI support for mx6sxsabresd board.
>
> There are two 16MB S25FL128S flashes on board. They are connected to
> QSPI2 interface. i.MX6SX supports two QuadSPI interfaces, QSPI1/2.
> The two flash devices are connected to A1/B1 of QSPI2.
>
> Signed-off-by: Peng Fan <van.freenix@gmail.com>
> ---
> arch/arm/cpu/armv7/mx6/clock.c | 50 +++++++++++++++++++++++++++++
> arch/arm/include/asm/arch-mx6/clock.h | 3 ++
> board/freescale/mx6sxsabresd/mx6sxsabresd.c | 40 +++++++++++++++++++++++
> drivers/spi/fsl_qspi.c | 30 +++++++++++++++++
> include/configs/mx6sxsabresd.h | 14 ++++++++
I would split this in two patches: one that adds qspi support for the
mx6solox SoC and another one that adds qspi support to the
mx6sxsabresd board.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd
2014-09-10 12:40 ` Fabio Estevam
@ 2014-09-10 13:43 ` Peng Fan
0 siblings, 0 replies; 6+ messages in thread
From: Peng Fan @ 2014-09-10 13:43 UTC (permalink / raw)
To: u-boot
On 09/10/2014 08:40 PM, Fabio Estevam wrote:
> On Wed, Sep 10, 2014 at 3:16 AM, Peng Fan <Peng.Fan@freescale.com> wrote:
>> From: Peng Fan <van.freenix@gmail.com>
>>
>> Add QuadSPI support for mx6sxsabresd board.
>>
>> There are two 16MB S25FL128S flashes on board. They are connected to
>> QSPI2 interface. i.MX6SX supports two QuadSPI interfaces, QSPI1/2.
>> The two flash devices are connected to A1/B1 of QSPI2.
>>
>> Signed-off-by: Peng Fan <van.freenix@gmail.com>
>> ---
>> arch/arm/cpu/armv7/mx6/clock.c | 50 +++++++++++++++++++++++++++++
>> arch/arm/include/asm/arch-mx6/clock.h | 3 ++
>> board/freescale/mx6sxsabresd/mx6sxsabresd.c | 40 +++++++++++++++++++++++
>> drivers/spi/fsl_qspi.c | 30 +++++++++++++++++
>> include/configs/mx6sxsabresd.h | 14 ++++++++
>
> I would split this in two patches: one that adds qspi support for the
> mx6solox SoC and another one that adds qspi support to the
> mx6sxsabresd board.
ok. I'll correct this. Thanks for reviewing.
Regards,
Peng.
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [U-Boot] [PATCH 2/3] QSPI: Enable write device registers
2014-09-10 6:16 [U-Boot] [PATCH 0/3] Add QSPI support for mx6sxsabresd board Peng Fan
2014-09-10 6:16 ` [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd Peng Fan
@ 2014-09-10 6:16 ` Peng Fan
2014-09-10 6:16 ` [U-Boot] [PATCH 3/3] QSPI: Enable QSPI AHB read for MX6SX Peng Fan
2 siblings, 0 replies; 6+ messages in thread
From: Peng Fan @ 2014-09-10 6:16 UTC (permalink / raw)
To: u-boot
From: Peng Fan <van.freenix@gmail.com>
Add qspi_op_wrr to support status and configuration register write in
flash devices.
Signed-off-by: Peng Fan <van.freenix@gmail.com>
---
drivers/spi/fsl_qspi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 74 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index 7e8d07e..b1d75e7 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -32,12 +32,16 @@
#define SEQID_CHIP_ERASE 5
#define SEQID_PP 6
#define SEQID_RDID 7
+#define SEQID_WRR 8
+#define SEQID_RDCR 9
/* Flash opcodes */
+#define OPCODE_WRR 0x01 /* Write status/config register */
#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_RDCR 0x35 /* Read configuration register */
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
@@ -189,6 +193,18 @@ static void qspi_set_lut(struct fsl_qspi *qspi)
qspi_write32(®s->lut[lut_base + 2], 0);
qspi_write32(®s->lut[lut_base + 3], 0);
+ /* Write Register */
+ lut_base = SEQID_WRR * 4;
+ qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_WRR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(LUT_WRITE) |
+ PAD1(LUT_PAD1) | INSTR1(0x2));
+
+ /* Read Configuration Register */
+ lut_base = SEQID_RDCR * 4;
+ qspi_write32(®s->lut[lut_base], OPRND0(OPCODE_RDCR) |
+ PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(LUT_READ) |
+ PAD1(LUT_PAD1) | INSTR1(0x1));
+
/* Lock the LUT */
qspi_write32(®s->lutkey, LUT_KEY_VALUE);
qspi_write32(®s->lckcr, QSPI_LCKCR_LOCK);
@@ -352,6 +368,55 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(®s->mcr, mcr_reg);
}
+static void qspi_op_wrr(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 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);
+
+ 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->amba_base;
+ qspi_write32(®s->sfar, to_or_from);
+
+ /* The max len is 2 for OPCODE_WRR */
+ data = 0;
+ memcpy(&data, txbuf, len);
+ data = qspi_endian_xchg(data);
+ qspi_write32(®s->tbdr, data);
+
+ qspi_write32(®s->ipcr,
+ (SEQID_WRR << QSPI_IPCR_SEQID_SHIFT) | len);
+ while (qspi_read32(®s->sr) & QSPI_SR_BUSY_MASK)
+ ;
+
+ qspi_write32(®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;
@@ -476,11 +541,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (dout) {
memcpy(&txbuf, dout, 4);
- qspi->cur_seqid = *(u8 *)dout;
+ /* extract cmd when SPI_XFER_BEGIN is set */
+ if (flags & SPI_XFER_BEGIN)
+ qspi->cur_seqid = *(u8 *)dout;
if (flags == SPI_XFER_END) {
- qspi->sf_addr = pp_sfaddr;
- qspi_op_pp(qspi, (u32 *)dout, bytes);
+ if (qspi->cur_seqid == OPCODE_WRR) {
+ qspi_op_wrr(qspi, (u8 *)dout, bytes);
+ } else if (qspi->cur_seqid == OPCODE_PP) {
+ qspi->sf_addr = pp_sfaddr;
+ qspi_op_pp(qspi, (u32 *)dout, bytes);
+ }
return 0;
}
--
1.8.4
^ permalink raw reply related [flat|nested] 6+ messages in thread* [U-Boot] [PATCH 3/3] QSPI: Enable QSPI AHB read for MX6SX
2014-09-10 6:16 [U-Boot] [PATCH 0/3] Add QSPI support for mx6sxsabresd board Peng Fan
2014-09-10 6:16 ` [U-Boot] [PATCH 1/3] ARM:MX6SX Add QuadSPI support for mx6sxsabresd Peng Fan
2014-09-10 6:16 ` [U-Boot] [PATCH 2/3] QSPI: Enable write device registers Peng Fan
@ 2014-09-10 6:16 ` Peng Fan
2 siblings, 0 replies; 6+ messages in thread
From: Peng Fan @ 2014-09-10 6:16 UTC (permalink / raw)
To: u-boot
From: Peng Fan <van.freenix@gmail.com>
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.
Signed-off-by: Peng Fan <van.freenix@gmail.com>
---
drivers/spi/fsl_qspi.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/spi/fsl_qspi.h | 11 +++++++
2 files changed, 92 insertions(+)
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index b1d75e7..95b36f0 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -215,6 +215,52 @@ void spi_init()
/* do nothing */
}
+#ifdef CONFIG_MX6SX
+static void qspi_ahb_read(struct fsl_qspi *qspi, u8 *rxbuf, u32 len)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg;
+ u32 to_or_from;
+
+ to_or_from = qspi->sf_addr + qspi->amba_base;
+
+ 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_64);
+
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(rxbuf, (u8 *)to_or_from, 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_invalid_buf(struct fsl_qspi *qspi)
+{
+ struct fsl_qspi_regs *regs = (struct fsl_qspi_regs *)qspi->reg_base;
+ u32 mcr_reg;
+
+ mcr_reg = qspi_read32(®s->mcr);
+ mcr_reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
+ qspi_write32(®s->mcr, mcr_reg);
+
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ udelay(1);
+
+ mcr_reg &= ~(QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK);
+ qspi_write32(®s->mcr, mcr_reg);
+}
+#endif
+
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
@@ -266,9 +312,30 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
smpr_val = qspi_read32(®s->smpr);
smpr_val &= ~QSPI_SMPR_DDRSMP_MASK;
qspi_write32(®s->smpr, smpr_val);
+
+#ifdef CONFIG_MX6SX
+ qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK |
+ QSPI_MCR_END_CFD_LE << QSPI_MCR_END_CFD_SHIFT);
+#else
qspi_write32(®s->mcr, QSPI_MCR_RESERVED_MASK);
+#endif
+#ifdef CONFIG_MX6SX
+ /* 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));
+
+ qspi_write32(®s->buf0ind, 0);
+ qspi_write32(®s->buf1ind, 0);
+ qspi_write32(®s->buf2ind, 0);
+
+ seq_id = SEQID_FAST_READ;
+#else
seq_id = 0;
+#endif
reg_val = qspi_read32(®s->bfgencr);
reg_val &= ~QSPI_BFGENCR_SEQID_MASK;
reg_val |= (seq_id << QSPI_BFGENCR_SEQID_SHIFT);
@@ -324,6 +391,7 @@ static void qspi_op_rdid(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(®s->mcr, mcr_reg);
}
+#ifndef CONFIG_MX6SX
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;
@@ -367,6 +435,7 @@ static void qspi_op_read(struct fsl_qspi *qspi, u32 *rxbuf, u32 len)
qspi_write32(®s->mcr, mcr_reg);
}
+#endif
static void qspi_op_wrr(struct fsl_qspi *qspi, u8 *txbuf, u32 len)
{
@@ -470,6 +539,10 @@ static void qspi_op_pp(struct fsl_qspi *qspi, u32 *txbuf, u32 len)
;
qspi_write32(®s->mcr, mcr_reg);
+
+#ifdef CONFIG_MX6SX
+ qspi_invalid_buf(qspi);
+#endif
}
static void qspi_op_rdsr(struct fsl_qspi *qspi, u32 *rxbuf)
@@ -529,6 +602,10 @@ static void qspi_op_se(struct fsl_qspi *qspi)
;
qspi_write32(®s->mcr, mcr_reg);
+
+#ifdef CONFIG_MX6SX
+ qspi_invalid_buf(qspi);
+#endif
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
@@ -567,7 +644,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (din) {
if (qspi->cur_seqid == OPCODE_FAST_READ)
+#ifdef CONFIG_MX6SX
+ qspi_ahb_read(qspi, din, bytes);
+#else
qspi_op_read(qspi, din, bytes);
+#endif
else if (qspi->cur_seqid == OPCODE_RDID)
qspi_op_rdid(qspi, din, bytes);
else if (qspi->cur_seqid == OPCODE_RDSR)
diff --git a/drivers/spi/fsl_qspi.h b/drivers/spi/fsl_qspi.h
index db400e6..80c5ac9 100644
--- a/drivers/spi/fsl_qspi.h
+++ b/drivers/spi/fsl_qspi.h
@@ -56,9 +56,14 @@ struct fsl_qspi_regs {
#define QSPI_IPCR_SEQID_SHIFT 24
#define QSPI_IPCR_SEQID_MASK (0xf << QSPI_IPCR_SEQID_SHIFT)
+#define QSPI_MCR_SWRSTSD_SHIFT 0
+#define QSPI_MCR_SWRSTSD_MASK (1 << QSPI_MCR_SWRSTSD_SHIFT)
+#define QSPI_MCR_SWRSTHD_SHIFT 1
+#define QSPI_MCR_SWRSTHD_MASK (1 << QSPI_MCR_SWRSTHD_SHIFT)
#define QSPI_MCR_END_CFD_SHIFT 2
#define QSPI_MCR_END_CFD_MASK (3 << QSPI_MCR_END_CFD_SHIFT)
#define QSPI_MCR_END_CFD_LE (1 << QSPI_MCR_END_CFD_SHIFT)
+#define QSPI_MCR_END_CFD_LE_64 (3 << QSPI_MCR_END_CFD_SHIFT)
#define QSPI_MCR_DDR_EN_SHIFT 7
#define QSPI_MCR_DDR_EN_MASK (1 << QSPI_MCR_DDR_EN_SHIFT)
#define QSPI_MCR_CLR_RXF_SHIFT 10
@@ -79,6 +84,12 @@ struct fsl_qspi_regs {
#define QSPI_SMPR_DDRSMP_SHIFT 16
#define QSPI_SMPR_DDRSMP_MASK (7 << QSPI_SMPR_DDRSMP_SHIFT)
+#define QSPI_BUFXCR_INVALID_MSTRID 0xe
+#define QSPI_BUF3CR_ALLMST_SHIFT 31
+#define QSPI_BUF3CR_ALLMST_MASK (1 << QSPI_BUF3CR_ALLMST_SHIFT)
+#define QSPI_BUF3CR_ADATSZ_SHIFT 8
+#define QSPI_BUF3CR_ADATSZ_MASK (0xff << QSPI_BUF3CR_ADATSZ_SHIFT)
+
#define QSPI_BFGENCR_SEQID_SHIFT 12
#define QSPI_BFGENCR_SEQID_MASK (0xf << QSPI_BFGENCR_SEQID_SHIFT)
#define QSPI_BFGENCR_PAR_EN_SHIFT 16
--
1.8.4
^ permalink raw reply related [flat|nested] 6+ messages in thread