summaryrefslogtreecommitdiff
path: root/drivers/spi/fsl_qspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/fsl_qspi.c')
-rw-r--r--drivers/spi/fsl_qspi.c1584
1 files changed, 670 insertions, 914 deletions
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index cb8d929..a214d34 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -1,35 +1,174 @@
/*
- * Copyright 2013-2015 Freescale Semiconductor, Inc.
+ * Freescale QuadSPI driver.
*
- * Freescale Quad Serial Peripheral Interface (QSPI) driver
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*/
-
#include <common.h>
#include <malloc.h>
#include <spi.h>
+
#include <asm/io.h>
-#include <linux/sizes.h>
-#include <dm.h>
-#include <errno.h>
-#include <watchdog.h>
-#include "fsl_qspi.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define RX_BUFFER_SIZE 0x80
-#ifdef CONFIG_MX6SX
-#define TX_BUFFER_SIZE 0x200
-#else
-#define TX_BUFFER_SIZE 0x40
-#endif
-#define OFFSET_BITS_MASK GENMASK(23, 0)
+#define QUADSPI_AHBMAP_BANK_MAXSIZE SZ_64M
+
+/* The registers */
+#define QUADSPI_MCR 0x00
+#define QUADSPI_MCR_RESERVED_SHIFT 16
+#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT)
+#define QUADSPI_MCR_MDIS_SHIFT 14
+#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT)
+#define QUADSPI_MCR_CLR_TXF_SHIFT 11
+#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT)
+#define QUADSPI_MCR_CLR_RXF_SHIFT 10
+#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT)
+#define QUADSPI_MCR_DDR_EN_SHIFT 7
+#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT)
+#define QUADSPI_MCR_END_CFG_SHIFT 2
+#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT)
+#define QUADSPI_MCR_SWRSTHD_SHIFT 1
+#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT)
+#define QUADSPI_MCR_SWRSTSD_SHIFT 0
+#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT)
+
+#define QUADSPI_IPCR 0x08
+#define QUADSPI_IPCR_SEQID_SHIFT 24
+#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0CR 0x10
+#define QUADSPI_BUF1CR 0x14
+#define QUADSPI_BUF2CR 0x18
+#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe
+
+#define QUADSPI_BUF3CR 0x1c
+#define QUADSPI_BUF3CR_ALLMST_SHIFT 31
+#define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
+#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8
+#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT)
+
+#define QUADSPI_BFGENCR 0x20
+#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16
+#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT))
+#define QUADSPI_BFGENCR_SEQID_SHIFT 12
+#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT)
+
+#define QUADSPI_BUF0IND 0x30
+#define QUADSPI_BUF1IND 0x34
+#define QUADSPI_BUF2IND 0x38
+#define QUADSPI_SFAR 0x100
+
+#define QUADSPI_SMPR 0x108
+#define QUADSPI_SMPR_DDRSMP_SHIFT 16
+#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT)
+#define QUADSPI_SMPR_FSDLY_SHIFT 6
+#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT)
+#define QUADSPI_SMPR_FSPHS_SHIFT 5
+#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT)
+#define QUADSPI_SMPR_HSENA_SHIFT 0
+#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT)
+
+#define QUADSPI_RBSR 0x10c
+#define QUADSPI_RBSR_RDBFL_SHIFT 8
+#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT)
+
+#define QUADSPI_RBCT 0x110
+#define QUADSPI_RBCT_WMRK_MASK 0x1F
+#define QUADSPI_RBCT_RXBRD_SHIFT 8
+#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT)
+
+#define QUADSPI_TBSR 0x150
+#define QUADSPI_TBDR 0x154
+#define QUADSPI_SR 0x15c
+#define QUADSPI_SR_IP_ACC_SHIFT 1
+#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT)
+#define QUADSPI_SR_AHB_ACC_SHIFT 2
+#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT)
+
+
+#define QUADSPI_FR 0x160
+#define QUADSPI_FR_TFF_MASK 0x1
+
+#define QUADSPI_SFA1AD 0x180
+#define QUADSPI_SFA2AD 0x184
+#define QUADSPI_SFB1AD 0x188
+#define QUADSPI_SFB2AD 0x18c
+#define QUADSPI_RBDR 0x200
+
+#define QUADSPI_LUTKEY 0x300
+#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0
+
+#define QUADSPI_LCKCR 0x304
+#define QUADSPI_LCKER_LOCK 0x1
+#define QUADSPI_LCKER_UNLOCK 0x2
+
+#define QUADSPI_RSER 0x164
+#define QUADSPI_RSER_TFIE (0x1 << 0)
+
+#define QUADSPI_LUT_BASE 0x310
-#define FLASH_STATUS_WEL 0x02
+/*
+ * The definition of the LUT register shows below:
+ *
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ */
+#define OPRND0_SHIFT 0
+#define PAD0_SHIFT 8
+#define INSTR0_SHIFT 10
+#define OPRND1_SHIFT 16
+
+/* Instruction set for the LUT register. */
+#define LUT_STOP 0
+#define LUT_CMD 1
+#define LUT_ADDR 2
+#define LUT_DUMMY 3
+#define LUT_MODE 4
+#define LUT_MODE2 5
+#define LUT_MODE4 6
+#define LUT_READ 7
+#define LUT_WRITE 8
+#define LUT_JMP_ON_CS 9
+#define LUT_ADDR_DDR 10
+#define LUT_MODE_DDR 11
+#define LUT_MODE2_DDR 12
+#define LUT_MODE4_DDR 13
+#define LUT_READ_DDR 14
+#define LUT_WRITE_DDR 15
+#define LUT_DATA_LEARN 16
-/* SEQID */
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the lines number of IO[0:3].
+ * For example, the Quad read need four IO lines, so you should
+ * set LUT_PAD4 which means we use four IO lines.
+ */
+#define LUT_PAD1 0
+#define LUT_PAD2 1
+#define LUT_PAD4 2
+
+/* Oprands for the LUT register. */
+#define ADDR24BIT 0x18
+#define ADDR32BIT 0x20
+
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr) \
+ (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+ ((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT)
+
+/* other macros for LUT register. */
+#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4)
+#define QUADSPI_LUT_NUM 64
+
+/* SEQID -- we can have 16 seqids at most. */
+#define SEQID_QUAD_READ 0
#define SEQID_WREN 1
#define SEQID_FAST_READ 2
#define SEQID_RDSR 3
@@ -37,356 +176,269 @@ DECLARE_GLOBAL_DATA_PTR;
#define SEQID_CHIP_ERASE 5
#define SEQID_PP 6
#define SEQID_RDID 7
-#define SEQID_BE_4K 8
+#define SEQID_WRSR 8
+#define SEQID_RDCR 9
+#define SEQID_DDR_QUAD_READ 10
+#define SEQID_BE_4K 11
#ifdef CONFIG_SPI_FLASH_BAR
-#define SEQID_BRRD 9
-#define SEQID_BRWR 10
-#define SEQID_RDEAR 11
-#define SEQID_WREAR 12
+#define SEQID_BRRD 12
+#define SEQID_BRWR 13
+#define SEQID_RDEAR 14
+#define SEQID_WREAR 15
#endif
-/* 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 */
+/* Flash opcodes. */
+#define OPCODE_WREN 0x06 /* Write enable */
+#define OPCODE_RDSR 0x05 /* Read status register */
+#define OPCODE_WRSR 0x01 /* Write status register 1 byte */
+#define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */
+#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define OPCODE_QUAD_READ 0x6b /* Read data bytes */
+#define OPCODE_DDR_QUAD_READ 0x6d /* Read data bytes in DDR mode*/
+#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
+#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
+#define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
+#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
+#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
+#define OPCODE_RDID 0x9f /* Read JEDEC ID */
+#define OPCODE_RDCR 0x35 /* Read configuration register */
+
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+#define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */
+#define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */
+#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */
+#define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */
+#define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */
+
+/* Used for SST flashes only. */
+#define OPCODE_BP 0x02 /* Byte program */
+#define OPCODE_WRDI 0x04 /* Write disable */
+#define OPCODE_AAI_WP 0xad /* Auto address increment word program */
+
+/* Used for Macronix and Winbond flashes. */
+#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
+#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
/* Used for Micron, winbond and Macronix flashes */
-#define QSPI_CMD_WREAR 0xc5 /* EAR register write */
-#define QSPI_CMD_RDEAR 0xc8 /* EAR reigster read */
+#define OPCODE_WREAR 0xc5 /* EAR register write */
+#define OPCODE_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 */
+#define OPCODE_BRRD 0x16 /* Bank register read */
+#define OPCODE_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) */
+/* Status Register bits. */
+#define SR_WIP 1 /* Write in progress */
+#define SR_WEL 2 /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
+#define SR_BP0 4 /* Block protect 0 */
+#define SR_BP1 8 /* Block protect 1 */
+#define SR_BP2 0x10 /* Block protect 2 */
+#define SR_SRWD 0x80 /* SR write protect */
-/* fsl_qspi_platdata flags */
-#define QSPI_FLAG_REGMAP_ENDIAN_BIG BIT(0)
+#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */
-/* default SCK frequency, unit: HZ */
-#define FSL_QSPI_DEFAULT_SCK_FREQ 50000000
+/* Configuration Register bits. */
+#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */
-/* QSPI max chipselect signals number */
-#define FSL_QSPI_MAX_CHIPSELECT_NUM 4
+/* Endianess Configuration */
+#define BE_64 0x00
+#define LE_32 0x01
+#define BE_32 0x02
+#define LE_64 0x03
-#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;
+
+
+enum fsl_qspi_devtype {
+ FSL_QUADSPI_VYBRID,
+ FSL_QUADSPI_IMX6SX,
};
-#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;
+struct fsl_qspi_devtype_data {
+ enum fsl_qspi_devtype devtype;
+ int rxfifo;
+ int txfifo;
};
-#ifndef CONFIG_DM_SPI
struct fsl_qspi {
struct spi_slave slave;
- struct fsl_qspi_priv priv;
+ uint32_t max_khz;
+ uint32_t mode;
+ u32 iobase;
+ u32 ahb_base; /* Used when read from AHB bus */
+ u32 bank_memmap_phy[4];
+ struct fsl_qspi_devtype_data *devtype_data;
};
-#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)
+static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
{
- flags & QSPI_FLAG_REGMAP_ENDIAN_BIG ?
- out_be32(addr, val) : out_le32(addr, val);
+ writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
}
-/* QSPI support swapping the flash read/write data
- * in hardware for LS102xA, but not for VF610 */
-static inline u32 qspi_endian_xchg(u32 data)
+static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
{
-#ifdef CONFIG_VF610
- return swab32(data);
-#else
- return data;
-#endif
+ writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
+ writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
}
-static void qspi_set_lut(struct fsl_qspi_priv *priv)
+static void fsl_qspi_init_lut(struct fsl_qspi *q)
{
- struct fsl_qspi_regs *regs = priv->regs;
+ u32 base = q->iobase;
+ int rxfifo = q->devtype_data->rxfifo;
u32 lut_base;
+ u8 cmd, addrlen, dummy;
+ int i;
+
+ fsl_qspi_unlock_lut(q);
+
+ /* Clear all the LUT table */
+ for (i = 0; i < QUADSPI_LUT_NUM; i++)
+ writel(0, base + QUADSPI_LUT_BASE + i * 4);
- /* Unlock the LUT */
- qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(priv->flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);
+ /* Quad Read */
+ lut_base = SEQID_QUAD_READ * 4;
- /* Write Enable */
+ /* U-boot SPI flash only support 24bits address*/
+ cmd = OPCODE_QUAD_READ;
+ addrlen = ADDR24BIT;
+ dummy = 8;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ /* Write enable */
lut_base = SEQID_WREN * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREN) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ writel(LUT0(CMD, PAD1, OPCODE_WREN), base + QUADSPI_LUT(lut_base));
/* Fast Read */
lut_base = SEQID_FAST_READ * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &regs->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(priv->flags, &regs->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(priv->flags, &regs->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(priv->flags, &regs->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, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ cmd = OPCODE_FAST_READ;
+ addrlen = ADDR24BIT;
+ dummy = 8;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD1, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ /* Page Program */
+ lut_base = SEQID_PP * 4;
+ cmd = OPCODE_PP;
+ addrlen = ADDR24BIT;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
/* Read Status */
lut_base = SEQID_RDSR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDSR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ writel(LUT0(CMD, PAD1, OPCODE_RDSR) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
/* Erase a sector */
lut_base = SEQID_SE * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &regs->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(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_SE) | PAD0(LUT_PAD1) |
- INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
- else
- qspi_write32(priv->flags, &regs->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(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ cmd = OPCODE_SE;
+ addrlen = ADDR24BIT;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
/* Erase the whole chip */
lut_base = SEQID_CHIP_ERASE * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_CHIP_ERASE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
-
- /* Page Program */
- lut_base = SEQID_PP * 4;
-#ifdef CONFIG_SPI_FLASH_BAR
- qspi_write32(priv->flags, &regs->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(priv->flags, &regs->lut[lut_base],
- OPRND0(QSPI_CMD_PP) | PAD0(LUT_PAD1) |
- INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
- else
- qspi_write32(priv->flags, &regs->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(priv->flags, &regs->lut[lut_base + 1], OPRND0(0) |
- PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
-#else
- qspi_write32(priv->flags, &regs->lut[lut_base + 1],
- OPRND0(TX_BUFFER_SIZE) |
- PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
-#endif
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ writel(LUT0(CMD, PAD1, OPCODE_CHIP_ERASE),
+ base + QUADSPI_LUT(lut_base));
/* READ ID */
lut_base = SEQID_RDID * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDID) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(8) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
- qspi_write32(priv->flags, &regs->lut[lut_base + 1], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 2], 0);
- qspi_write32(priv->flags, &regs->lut[lut_base + 3], 0);
+ writel(LUT0(CMD, PAD1, OPCODE_RDID) | LUT1(READ, PAD1, 0x8),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Write Register */
+ lut_base = SEQID_WRSR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_WRSR) | LUT1(WRITE, PAD1, 0x2),
+ base + QUADSPI_LUT(lut_base));
+
+ /* Read Configuration Register */
+ lut_base = SEQID_RDCR * 4;
+ writel(LUT0(CMD, PAD1, OPCODE_RDCR) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
+
+ /* DDR QUAD Read */
+ lut_base = SEQID_DDR_QUAD_READ * 4;
+ cmd = OPCODE_DDR_QUAD_READ;
+ addrlen = ADDR24BIT;
+ dummy = 6;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR_DDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ_DDR, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+ writel(LUT0(JMP_ON_CS, PAD1, 0),
+ base + QUADSPI_LUT(lut_base + 2));
/* SUB SECTOR 4K ERASE */
lut_base = SEQID_BE_4K * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BE_4K) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(ADDR24BIT) |
- PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
+ cmd = OPCODE_BE_4K;
+ addrlen = ADDR24BIT;
+
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
#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.
+ * dynamically check whether to set BRRD BRWR or RDEAR WREAR.
*/
lut_base = SEQID_BRRD * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRRD) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+ cmd = OPCODE_BRRD;
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
lut_base = SEQID_BRWR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_BRWR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
+ cmd = OPCODE_BRWR;
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
lut_base = SEQID_RDEAR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_RDEAR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_READ));
+ cmd = OPCODE_RDEAR;
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(READ, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
lut_base = SEQID_WREAR * 4;
- qspi_write32(priv->flags, &regs->lut[lut_base], OPRND0(QSPI_CMD_WREAR) |
- PAD0(LUT_PAD1) | INSTR0(LUT_CMD) | OPRND1(1) |
- PAD1(LUT_PAD1) | INSTR1(LUT_WRITE));
+ cmd = OPCODE_WREAR;
+ writel(LUT0(CMD, PAD1, cmd) | LUT1(WRITE, PAD1, 0x1),
+ base + QUADSPI_LUT(lut_base));
#endif
- /* Lock the LUT */
- qspi_write32(priv->flags, &regs->lutkey, LUT_KEY_VALUE);
- qspi_write32(priv->flags, &regs->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_priv *priv)
-{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 reg;
- reg = qspi_read32(priv->flags, &regs->mcr);
- reg |= QSPI_MCR_SWRSTHD_MASK | QSPI_MCR_SWRSTSD_MASK;
- qspi_write32(priv->flags, &regs->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, &regs->mcr, reg);
-}
-
-/* Read out the data from the AHB buffer. */
-static inline void qspi_ahb_read(struct fsl_qspi_priv *priv, u8 *rxbuf, int len)
-{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
-
- qspi_write32(priv->flags, &regs->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 *)(priv->cur_amba_base + priv->sf_addr), len);
-
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ fsl_qspi_lock_lut(q);
}
-static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
+/*Enable DDR Read Mode*/
+static void fsl_enable_ddr_mode(struct fsl_qspi *q)
{
+ u32 base = q->iobase;
u32 reg, reg2;
- struct fsl_qspi_regs *regs = priv->regs;
- reg = qspi_read32(priv->flags, &regs->mcr);
- /* Disable the module */
- qspi_write32(priv->flags, &regs->mcr, reg | QSPI_MCR_MDIS_MASK);
+ reg = readl(base + QUADSPI_MCR);
+ /* Firstly, disable the module */
+ writel(reg | QUADSPI_MCR_MDIS_MASK, base + QUADSPI_MCR);
/* Set the Sampling Register for DDR */
- reg2 = qspi_read32(priv->flags, &regs->smpr);
- reg2 &= ~QSPI_SMPR_DDRSMP_MASK;
- reg2 |= (2 << QSPI_SMPR_DDRSMP_SHIFT);
- qspi_write32(priv->flags, &regs->smpr, reg2);
+ reg2 = readl(base + QUADSPI_SMPR);
+ reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK;
+ reg2 |= (2 << QUADSPI_SMPR_DDRSMP_SHIFT);
+ writel(reg2, base + QUADSPI_SMPR);
/* Enable the module again (enable the DDR too) */
- reg |= QSPI_MCR_DDR_EN_MASK;
- /* Enable bit 29 for imx6sx */
- reg |= BIT(29);
+ reg |= QUADSPI_MCR_DDR_EN_MASK;
+ reg |= (1 << 29); /* enable bit 29 for imx6sx */
+
+ writel(reg, base + QUADSPI_MCR);
- qspi_write32(priv->flags, &regs->mcr, reg);
}
/*
@@ -402,715 +454,419 @@ static void qspi_enable_ddr_mode(struct fsl_qspi_priv *priv)
* 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_priv *priv)
+static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
{
- struct fsl_qspi_regs *regs = priv->regs;
+ u32 base = q->iobase;
+
+ /* Map the SPI NOR to accessiable address, arrage max space for each bank*/
+ writel(q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE,
+ base + QUADSPI_SFA1AD);
+ writel(q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE,
+ base + QUADSPI_SFA2AD);
+ writel(q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE,
+ base + QUADSPI_SFB1AD);
+ writel(q->bank_memmap_phy[3] + QUADSPI_AHBMAP_BANK_MAXSIZE,
+ base + QUADSPI_SFB2AD);
/* AHB configuration for access buffer 0/1/2 .*/
- qspi_write32(priv->flags, &regs->buf0cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf1cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf2cr, QSPI_BUFXCR_INVALID_MSTRID);
- qspi_write32(priv->flags, &regs->buf3cr, QSPI_BUF3CR_ALLMST_MASK |
- (0x80 << QSPI_BUF3CR_ADATSZ_SHIFT));
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
+ writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
+ writel(QUADSPI_BUF3CR_ALLMST_MASK | (0x80 << QUADSPI_BUF3CR_ADATSZ_SHIFT),
+ base + QUADSPI_BUF3CR);
/* We only use the buffer3 */
- qspi_write32(priv->flags, &regs->buf0ind, 0);
- qspi_write32(priv->flags, &regs->buf1ind, 0);
- qspi_write32(priv->flags, &regs->buf2ind, 0);
+ writel(0, base + QUADSPI_BUF0IND);
+ writel(0, base + QUADSPI_BUF1IND);
+ writel(0, base + QUADSPI_BUF2IND);
- /*
- * Set the default lut sequence for AHB Read.
- * Parallel mode is disabled.
- */
- qspi_write32(priv->flags, &regs->bfgencr,
- SEQID_FAST_READ << QSPI_BFGENCR_SEQID_SHIFT);
+ /* Set the default lut sequence for AHB Read. */
+ writel(SEQID_FAST_READ << QUADSPI_BFGENCR_SEQID_SHIFT,
+ base + QUADSPI_BFGENCR);
/*Enable DDR Mode*/
- qspi_enable_ddr_mode(priv);
+ fsl_enable_ddr_mode(q);
}
-#endif
-#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)
+static int fsl_qspi_init(struct fsl_qspi *q)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 reg, mcr_reg, data, seqid;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
+ u32 base = q->iobase;
+ u32 reg;
+ void *ptr;
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
+ ptr = malloc(sizeof(struct fsl_qspi_devtype_data));
+ if (!ptr) {
+ puts("FSL_QSPI: per-type data not allocated !\n");
+ return 1;
+ }
+ q->devtype_data = ptr;
+ q->devtype_data->rxfifo = 128;
+ q->devtype_data->txfifo = 512;
- if (priv->cur_seqid == QSPI_CMD_BRRD)
- seqid = SEQID_BRRD;
- else
- seqid = SEQID_RDEAR;
+ /* init the LUT table */
+ fsl_qspi_init_lut(q);
- qspi_write32(priv->flags, &regs->ipcr,
- (seqid << QSPI_IPCR_SEQID_SHIFT) | len);
+ /* Disable the module */
+ writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
+ base + QUADSPI_MCR);
- /* Wait previous command complete */
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
+ reg = readl(base + QUADSPI_SMPR);
+ writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
+ | QUADSPI_SMPR_FSPHS_MASK
+ | QUADSPI_SMPR_HSENA_MASK
+ | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
- while (1) {
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[0]);
- data = qspi_endian_xchg(data);
- memcpy(rxbuf, &data, len);
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- break;
- }
- }
+ /* Enable the module */
+ writel(QUADSPI_MCR_RESERVED_MASK | LE_64 << QUADSPI_MCR_END_CFG_SHIFT,
+ base + QUADSPI_MCR);
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
-}
-#endif
+ /* We do not enable the interrupt */
-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;
+ /* init for AHB read */
+ fsl_qspi_init_abh_read(q);
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDID << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- i = 0;
- while ((RX_BUFFER_SIZE >= len) && (len > 0)) {
- rbsr_reg = qspi_read32(priv->flags, &regs->rbsr);
- if (rbsr_reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[i]);
- data = qspi_endian_xchg(data);
- size = (len < 4) ? len : 4;
- memcpy(rxbuf, &data, size);
- len -= size;
- rxbuf++;
- i++;
- }
- }
+ /*
+ * High level code use page_size and max_write_size to calculate
+ * the number of bytes that should be programmed once.
+ */
+ q->slave.max_write_size = q->devtype_data->txfifo;
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ return 0;
}
-#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)
+void spi_init(void)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg, data;
- int i, size;
- u32 to_or_from;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- to_or_from = priv->sf_addr + priv->cur_amba_base;
-
- while (len > 0) {
- WATCHDOG_RESET();
-
- qspi_write32(priv->flags, &regs->sfar, to_or_from);
-
- size = (len > RX_BUFFER_SIZE) ?
- RX_BUFFER_SIZE : len;
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_FAST_READ << QSPI_IPCR_SEQID_SHIFT) |
- size);
- while (qspi_read32(priv->flags, &regs->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, &regs->rbdr[i]);
- data = qspi_endian_xchg(data);
- memcpy(rxbuf, &data, 4);
- rxbuf++;
- size -= 4;
- i++;
- }
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- }
-
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
}
-#endif
-static void qspi_op_write(struct fsl_qspi_priv *priv, u8 *txbuf, u32 len)
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
{
- 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, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- status_reg = 0;
- while ((status_reg & FLASH_STATUS_WEL) != FLASH_STATUS_WEL) {
- WATCHDOG_RESET();
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 1);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- status_reg = qspi_read32(priv->flags, &regs->rbdr[0]);
- status_reg = qspi_endian_xchg(status_reg);
- }
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- }
+ struct fsl_qspi *q;
+ int ret;
- /* 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, &regs->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, &regs->tbdr, data);
- txbuf += 4;
+ if (bus > 1) {
+ puts("FSL_QSPI: Not a valid bus !\n");
+ return NULL;
}
- size = tx_size % 4;
- if (size) {
- data = 0;
- memcpy(&data, txbuf, size);
- data = qspi_endian_xchg(data);
- qspi_write32(priv->flags, &regs->tbdr, data);
+ if (cs > 1) {
+ puts("FSL_QSPI: Not a valid cs !\n");
+ return NULL;
}
- qspi_write32(priv->flags, &regs->ipcr,
- (seqid << QSPI_IPCR_SEQID_SHIFT) | tx_size);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- qspi_write32(priv->flags, &regs->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, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- qspi_write32(priv->flags, &regs->sfar, priv->cur_amba_base);
+ q = spi_alloc_slave(struct fsl_qspi, bus, cs);
+ if (!q) {
+ puts("FSL_QSPI: SPI Slave not allocated !\n");
+ return NULL;
+ }
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_RDSR << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
+ q->iobase = CONFIG_QSPI_BASE;
+ q->bank_memmap_phy[0] = CONFIG_QSPI_MEMMAP_BASE;
+ q->bank_memmap_phy[1] = q->bank_memmap_phy[0] + QUADSPI_AHBMAP_BANK_MAXSIZE;
+ q->bank_memmap_phy[2] = q->bank_memmap_phy[1] + QUADSPI_AHBMAP_BANK_MAXSIZE;
+ q->bank_memmap_phy[3] = q->bank_memmap_phy[2] + QUADSPI_AHBMAP_BANK_MAXSIZE;
- while (1) {
- reg = qspi_read32(priv->flags, &regs->rbsr);
- if (reg & QSPI_RBSR_RDBFL_MASK) {
- data = qspi_read32(priv->flags, &regs->rbdr[0]);
- data = qspi_endian_xchg(data);
- memcpy(rxbuf, &data, len);
- qspi_write32(priv->flags, &regs->mcr,
- qspi_read32(priv->flags, &regs->mcr) |
- QSPI_MCR_CLR_RXF_MASK);
- break;
- }
+ /* Init the QuadSPI controller */
+ ret = fsl_qspi_init(q);
+ if (ret) {
+ puts("FSL_QSPI: init failed!\n");
+ return NULL;
}
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ return &q->slave;
}
-static void qspi_op_erase(struct fsl_qspi_priv *priv)
+void spi_free_slave(struct spi_slave *slave)
{
- struct fsl_qspi_regs *regs = priv->regs;
- u32 mcr_reg;
- u32 to_or_from = 0;
-
- mcr_reg = qspi_read32(priv->flags, &regs->mcr);
- qspi_write32(priv->flags, &regs->mcr,
- QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
- qspi_write32(priv->flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);
-
- to_or_from = priv->sf_addr + priv->cur_amba_base;
- qspi_write32(priv->flags, &regs->sfar, to_or_from);
-
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_WREN << QSPI_IPCR_SEQID_SHIFT) | 0);
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
-
- if (priv->cur_seqid == QSPI_CMD_SE) {
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_SE << QSPI_IPCR_SEQID_SHIFT) | 0);
- } else if (priv->cur_seqid == QSPI_CMD_BE_4K) {
- qspi_write32(priv->flags, &regs->ipcr,
- (SEQID_BE_4K << QSPI_IPCR_SEQID_SHIFT) | 0);
- }
- while (qspi_read32(priv->flags, &regs->sr) & QSPI_SR_BUSY_MASK)
- ;
+ struct fsl_qspi *q;
- qspi_write32(priv->flags, &regs->mcr, mcr_reg);
+ q = container_of(slave, struct fsl_qspi, slave);
+ free(q->devtype_data);
+ free(q);
}
-int qspi_xfer(struct fsl_qspi_priv *priv, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
+int spi_claim_bus(struct spi_slave *q)
{
- 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
- }
- }
+ return 0;
+}
- 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, bytes);
+void spi_release_bus(struct spi_slave *q)
+{
+}
+
+/* Get the SEQID for the command */
+static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
+{
+ switch (cmd) {
+ case OPCODE_QUAD_READ:
+ case OPCODE_QUAD_READ_4B:
+ return SEQID_QUAD_READ;
+ case OPCODE_FAST_READ:
+ case OPCODE_FAST_READ_4B:
+ return SEQID_FAST_READ;
+ case OPCODE_WREN:
+ return SEQID_WREN;
+ case OPCODE_RDSR:
+ return SEQID_RDSR;
+ case OPCODE_SE:
+ return SEQID_SE;
+ case OPCODE_CHIP_ERASE:
+ return SEQID_CHIP_ERASE;
+ case OPCODE_PP:
+ case OPCODE_PP_4B:
+ return SEQID_PP;
+ case OPCODE_RDID:
+ return SEQID_RDID;
+ case OPCODE_WRSR:
+ return SEQID_WRSR;
+ case OPCODE_RDCR:
+ return SEQID_RDCR;
+ case OPCODE_DDR_QUAD_READ:
+ return SEQID_DDR_QUAD_READ;
+ case OPCODE_BE_4K:
+ return SEQID_BE_4K;
#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);
- }
+ case OPCODE_BRRD:
+ return SEQID_BRRD;
+ case OPCODE_BRWR:
+ return SEQID_BRWR;
+ case OPCODE_RDEAR:
+ return SEQID_RDEAR;
+ case OPCODE_WREAR:
+ return SEQID_WREAR;
#endif
+ default:
+ break;
}
-
-#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;
+ return -1;
}
-void qspi_module_disable(struct fsl_qspi_priv *priv, u8 disable)
+/* return 1 on success */
+static int fsl_qspi_wait_to_complete(struct fsl_qspi *q)
{
- u32 mcr_val;
+ u32 base = q->iobase;
+ u32 reg;
- 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);
+ /*printf("QuadSPI: poll the busy bit\n");*/
+ while (1) {
+ reg = readl(base + QUADSPI_SR);
+ if (reg & 1)
+ continue;
+ else
+ return 1;
+ }
+
+ return 0;
}
-void qspi_cfg_smpr(struct fsl_qspi_priv *priv, u32 clear_bits, u32 set_bits)
+/*
+ * 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 fsl_qspi_invalid(struct fsl_qspi *q)
{
- u32 smpr_val;
+ u32 reg;
- 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
-};
+ reg = readl(q->iobase + QUADSPI_MCR);
+ reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
+ writel(reg, q->iobase + QUADSPI_MCR);
-static unsigned long amba_bases[] = {
- QSPI0_AMBA_BASE,
-#ifdef CONFIG_MX6SX
- QSPI1_AMBA_BASE,
-#endif
-};
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ udelay(1);
-static inline struct fsl_qspi *to_qspi_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct fsl_qspi, slave);
+ reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
+ writel(reg, q->iobase + QUADSPI_MCR);
}
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
- unsigned int max_hz, unsigned int mode)
+static int
+fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
{
- struct fsl_qspi *qspi;
- struct fsl_qspi_regs *regs;
- 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;
-
-#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.
- *
- * If not, only one flash device is used even if passing
- * different cs using `sf probe`
- */
- qspi->priv.cur_amba_base = amba_bases[bus] + cs * FSL_QSPI_FLASH_SIZE;
-
- qspi->slave.max_write_size = TX_BUFFER_SIZE;
+ u32 base = q->iobase;
+ int seqid;
+ u32 reg, reg2;
+ int err;
+ int bank_id;
+
+ /* check the SR first, wait previous cmd completed*/
+ do {
+ reg2 = readl(base + QUADSPI_SR);
+ if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
+ udelay(1);
+ printf("The controller is busy, 0x%x\n", reg2);
+ continue;
+ }
+ break;
+ } while (1);
- qspi_write32(qspi->priv.flags, &regs->mcr,
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+ /* save the reg */
+ reg = readl(base + QUADSPI_MCR);
- qspi_cfg_smpr(&qspi->priv,
- ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
- QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+ /* get the bank index */
+ bank_id = ((q->slave.bus) << 1) + (q->slave.cs);
- 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(qspi->priv.flags, &regs->sfa1ad,
- FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(qspi->priv.flags, &regs->sfa2ad,
- FSL_QSPI_FLASH_SIZE | amba_bases[bus]);
- qspi_write32(qspi->priv.flags, &regs->sfb1ad,
- total_size | amba_bases[bus]);
- qspi_write32(qspi->priv.flags, &regs->sfb2ad,
- total_size | amba_bases[bus]);
-
- qspi_set_lut(&qspi->priv);
-
-#ifdef CONFIG_SYS_FSL_QSPI_AHB
- qspi_init_ahb_read(&qspi->priv);
-#endif
+ writel(q->bank_memmap_phy[bank_id] + addr, base + QUADSPI_SFAR);
+ writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
+ base + QUADSPI_RBCT);
+ writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
- qspi_module_disable(&qspi->priv, 0);
+ /* trigger the LUT now */
+ seqid = fsl_qspi_get_seqid(q, cmd);
+ writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
- return &qspi->slave;
-}
+ /* Wait until completed */
+ err = fsl_qspi_wait_to_complete(q);
+ if (!err)
+ err = -1;
+ else
+ err = 0;
-void spi_free_slave(struct spi_slave *slave)
-{
- struct fsl_qspi *qspi = to_qspi_spi(slave);
+ /* restore the MCR */
+ writel(reg, base + QUADSPI_MCR);
- free(qspi);
+ /* After switch BANK, AHB buffer should also be invalid. */
+ if ((OPCODE_SE == cmd) || (OPCODE_PP == cmd) ||
+ (OPCODE_BE_4K == cmd) || (OPCODE_WREAR == cmd) ||
+ (OPCODE_BRWR == cmd))
+ fsl_qspi_invalid(q);
+ return err;
}
-int spi_claim_bus(struct spi_slave *slave)
+/*
+ * An IC bug makes us to re-arrange the 32-bit data.
+ * The following chips, such as IMX6SLX, have fixed this bug.
+ */
+static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
{
- return 0;
+ return a;
}
-void spi_release_bus(struct spi_slave *slave)
+/* Read out the data from the AHB buffer. */
+static void fsl_qspi_ahb_read(struct fsl_qspi *q,
+ unsigned int addr, int len, u8 *rxbuf)
{
- /* Nothing to do */
-}
+ int bank_id;
-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);
+ /* get the bank index */
+ bank_id = ((q->slave.bus) << 1) + (q->slave.cs);
- return qspi_xfer(&qspi->priv, bitlen, dout, din, flags);
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(rxbuf, (u8 *)(q->bank_memmap_phy[bank_id] + addr), len);
}
-void spi_init(void)
-{
- /* Nothing to do */
-}
-#else
-static int fsl_qspi_child_pre_probe(struct udevice *dev)
+/* Read out the data from the QUADSPI_RBDR buffer registers. */
+static void fsl_qspi_ip_read(struct fsl_qspi *q, int len, u8 *rxbuf)
{
- struct spi_slave *slave = dev_get_parent_priv(dev);
+ u32 tmp;
+ int i = 0;
- slave->max_write_size = TX_BUFFER_SIZE;
+ while (len > 0) {
+ tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
+ tmp = fsl_qspi_endian_xchg(q, tmp);
+
+ if (len >= 4) {
+ memcpy(rxbuf, &tmp, 4);
+ rxbuf += 4;
+ } else {
+ memcpy(rxbuf, &tmp, len);
+ break;
+ }
- return 0;
+ len -= 4;
+ i++;
+ }
}
-static int fsl_qspi_probe(struct udevice *bus)
+/* Write data to the QUADSPI_TBDR buffer registers. */
+static void fsl_qspi_write_data(struct fsl_qspi *q, int len, u8* txbuf)
{
- 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;
+ u32 tmp;
+ u32 t1, t2;
+ int j;
- priv->regs = (struct fsl_qspi_regs *)(uintptr_t)plat->reg_base;
- priv->flags = plat->flags;
+ /* clear the TX FIFO. */
+ tmp = readl(q->iobase + QUADSPI_MCR);
+ writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
- 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;
+ /* fill the TX data to the FIFO */
+ t2 = len % 4;
+ t1 = len >> 2; /* 4 Bytes aligned */
- qspi_write32(priv->flags, &priv->regs->mcr,
- QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK);
+ for (j = 0; j < t1; j++) {
+ memcpy(&tmp, txbuf, 4);
+ tmp = fsl_qspi_endian_xchg(q, tmp);
+ writel(tmp, q->iobase + QUADSPI_TBDR);
+ txbuf += 4;
+ }
- qspi_cfg_smpr(priv, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
- QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);
+ if (t2) {
+ tmp = 0;
+ memcpy(&tmp, txbuf, t2);
+ tmp = fsl_qspi_endian_xchg(q, tmp);
+ writel(tmp, q->iobase + QUADSPI_TBDR);
+ }
- 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);
+#if defined(CONFIG_MX7D) || defined(CONFIG_MX6UL)
+ u32 t3;
+ /* iMX7D and MX6UL TXFIFO must be at least 16 bytes*/
+ t3 = t1 + ((t2 + 3) >> 2);
+ for (; t3 < 4; t3++)
+ writel(0, q->iobase + QUADSPI_TBDR);
#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;
+/* see the spi_flash_read_write() */
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct fsl_qspi *q = container_of(slave, struct fsl_qspi, slave);
+ int len = bitlen / 8;
+ int ret = 0;
+ u8 *buf;
+ static u8 opcode;
+ static unsigned int addr;
+
+ if (!opcode && (flags & SPI_XFER_BEGIN)) {
+ /* spi_xfer for cmd phase */
+ buf = (u8 *)dout;
+ opcode = buf[0];
+ if (len > 1)
+ addr = buf[1] << 16 | buf[2] << 8 | buf[3];
+
+ /* if transfer cmd only */
+ if (flags & SPI_XFER_END)
+ ret = fsl_qspi_runcmd(q, opcode, addr, 0);
+
+ } else if (opcode) {
+ /* spi_xfer for data phase */
+ if (din) {
+ /* read*/
+ buf = (u8 *)din;
+ if (OPCODE_FAST_READ == opcode) {
+ fsl_qspi_ahb_read(q, addr, len, buf);
+ } else {
+ ret = fsl_qspi_runcmd(q, opcode, addr, len);
+ if (!ret)
+ fsl_qspi_ip_read(q, len, buf);
+ }
+ } else if (dout) {
+ /* write data, prepare data first */
+ buf = (u8 *)dout;
+ fsl_qspi_write_data(q, len, buf);
+ /* then run page program cmd */
+ ret = fsl_qspi_runcmd(q, opcode, addr, len);
+ }
}
- /* Count flash numbers */
- fdt_for_each_subnode(blob, subnode, node)
- ++flash_num;
-
- if (flash_num == 0) {
- debug("Error: Missing flashes!\n");
- return -ENODEV;
+ if (ret || (flags & SPI_XFER_END)) {
+ opcode = 0;
+ addr = 0;
}
- 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;
+ return ret;
}
-
-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