@@ -142,10 +142,14 @@
* | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
* ---------------------------------------------------
*/
-#define OPRND0_SHIFT 0
-#define PAD0_SHIFT 8
-#define INSTR0_SHIFT 10
-#define OPRND1_SHIFT 16
+#define PAD_SHIFT 8
+#define INSTR_SHIFT 10
+#define OPRND_SHIFT 16
+
+/* Macros for constructing the LUT register. */
+#define LUT_DEF(idx, ins, pad, opr) \
+ ((((ins) << INSTR_SHIFT) | ((pad) << PAD_SHIFT) | \
+ (opr)) << (((idx) % 2) * OPRND_SHIFT))
/* Instruction set for the LUT register. */
#define LUT_STOP 0
@@ -167,44 +171,31 @@
#define LUT_DATA_LEARN 16
/*
- * The PAD definitions for LUT register.
+ * Calculate number of required PAD bits 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.
+ * For example, Quad read need four IO lines, so this Macro
+ * returns 2 i.e. use four (2^2) IO lines for read.
*/
-#define LUT_PAD1 0
-#define LUT_PAD2 1
-#define LUT_PAD4 2
+#define LUT_PAD(x) (fls(x) - 1)
/* 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_READ 0
-#define SEQID_WREN 1
-#define SEQID_WRDI 2
-#define SEQID_RDSR 3
-#define SEQID_SE 4
-#define SEQID_CHIP_ERASE 5
-#define SEQID_PP 6
-#define SEQID_RDID 7
-#define SEQID_WRSR 8
-#define SEQID_RDCR 9
-#define SEQID_EN4B 10
-#define SEQID_BRWR 11
+/*
+ * SEQID -- we can have 16 seqids at most.
+ * LUT0 programmed by bootloader
+ * LUT1 programmed for IP register access cmds
+ * LUT2 programmed for AHB read, required for READ from devmem interface
+ */
+#define SEQID_LUT0_BOOTLOADER 0
+#define SEQID_LUT1_IPCMD 1
+#define SEQID_LUT2_AHBREAD 2
#define QUADSPI_MIN_IOMAP SZ_4M
@@ -268,6 +259,68 @@ struct fsl_qspi_devtype_data {
};
#define FSL_QSPI_MAX_CHIP 4
+
+/* enum qspi_mem_data_dir - describes the direction of a QSPI memory data
+ * transfer from QSPI controller prespective.
+ * QSPI_MEM_NO_DATA - no data transfer initiated
+ * QSPI_MEM_DATA_IN - data coming from the SPI memory
+ * QSPI_MEM_DATA_OUT - data sent to the SPI memory
+ */
+enum qspi_mem_data_dir {
+ QSPI_MEM_NO_DATA,
+ QSPI_MEM_DATA_IN,
+ QSPI_MEM_DATA_OUT,
+};
+
+/* enum qspi_cmd__mode - describes the mode of the running command
+ * QSPI_CMD_MODE_IP - data transfer using IP register access
+ * QSPI_CMD_MODE_AHB - data transfer via AMBA AHB bus directly
+ */
+enum qspi_cmd_mode {
+ QSPI_CMD_MODE_IP,
+ QSPI_CMD_MODE_AHB,
+};
+
+/* struct fsl_qspi_mem_op - describes the QSPI memory operation
+ * cmd.opcode: operation opcode
+ * cmd.pad: number of IO lines used to transmit the command
+ * addr.addrlen: QSPI working in 3/4-byte mode. Can be zero if the operation
+ * does not need to send an address
+ * addr.pad: number of IO lines used to transmit the address cycles
+ * dummy.ncycles: number of dummy cycles to send after an opcode or address.
+ * Can be zero if the operation does not require dummy cycles
+ * dummy.pad: number of IO lines used to transmit the dummy bytes
+ * data.dir: direction of the transfer
+ * data.nbytes: number of data bytes to send. Can be zero for fsl_qspi_write,
+ * actual transfer size provided when CMD is triggered.
+ * data.pad: number of IO lines used to transmit the data bytes
+ * mode: mode of the running command, default is IP mode
+ */
+struct fsl_qspi_mem_op {
+ struct {
+ u8 opcode;
+ u8 pad;
+ } cmd;
+
+ struct {
+ u8 addrlen;
+ u8 pad;
+ } addr;
+
+ struct {
+ u8 ncycles;
+ u8 pad;
+ } dummy;
+
+ struct {
+ enum qspi_mem_data_dir dir;
+ unsigned int nbytes;
+ u8 pad;
+ } data;
+
+ enum qspi_cmd_mode mode;
+};
+
struct fsl_qspi {
struct spi_nor nor[FSL_QSPI_MAX_CHIP];
void __iomem *iobase;
@@ -368,143 +421,84 @@ static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void fsl_qspi_init_lut(struct fsl_qspi *q)
+/*
+ * Prepare LUT values for requested CMD using struct fsl_qspi_mem_op
+ * LUT prepared in format:
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ * values from struct fsl_qspi_mem_op are saved for different
+ * operands like CMD, ADDR, DUMMY and DATA in above format based
+ * on provided input value.
+ * For case of AHB (XIP) operation, use different LUT seqid,
+ * as read from QSPI controller can be triggered using this driver
+ * and also using "devmem" utility.
+ * For read trigger using "devmem" controller use LUT seqid saved in
+ * QUADSPI_BFGENCR register.
+ */
+static void fsl_qspi_prepare_lut(struct spi_nor *nor,
+ struct fsl_qspi_mem_op *op)
{
+ struct fsl_qspi *q = nor->priv;
void __iomem *base = q->iobase;
- int rxfifo = q->devtype_data->rxfifo;
u32 lut_base;
- int i;
+ u32 lutval[4] = {};
+ int lutidx = 0, i;
+
+ lutval[lutidx / 2] |= LUT_DEF(lutidx,
+ LUT_CMD,
+ LUT_PAD(op->cmd.pad),
+ op->cmd.opcode);
+ lutidx++;
+
+ if (op->addr.addrlen) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx,
+ LUT_ADDR,
+ LUT_PAD(op->addr.pad),
+ op->addr.addrlen);
+ lutidx++;
+ }
- struct spi_nor *nor = &q->nor[0];
- u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
- u8 read_op = nor->read_opcode;
- u8 read_dm = nor->read_dummy;
+ if (op->dummy.ncycles) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx,
+ LUT_DUMMY,
+ LUT_PAD(op->dummy.pad),
+ op->dummy.ncycles);
+ lutidx++;
+ }
- fsl_qspi_unlock_lut(q);
+ if (op->data.dir) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx,
+ op->data.dir == QSPI_MEM_DATA_IN ?
+ LUT_FSL_READ : LUT_FSL_WRITE,
+ LUT_PAD(op->data.pad),
+ op->data.nbytes);
+ lutidx++;
+ }
- /* Clear all the LUT table */
- for (i = 0; i < QUADSPI_LUT_NUM; i++)
- qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
-
- /* Read */
- lut_base = SEQID_READ * 4;
-
- qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen),
- base + QUADSPI_LUT(lut_base));
- qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
- LUT1(FSL_READ, PAD4, rxfifo),
- base + QUADSPI_LUT(lut_base + 1));
-
- /* Write enable */
- lut_base = SEQID_WREN * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
- base + QUADSPI_LUT(lut_base));
-
- /* Page Program */
- lut_base = SEQID_PP * 4;
-
- qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) |
- LUT1(ADDR, PAD1, addrlen),
- base + QUADSPI_LUT(lut_base));
- qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
- base + QUADSPI_LUT(lut_base + 1));
-
- /* Read Status */
- lut_base = SEQID_RDSR * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDSR) |
- LUT1(FSL_READ, PAD1, 0x1),
- base + QUADSPI_LUT(lut_base));
-
- /* Erase a sector */
- lut_base = SEQID_SE * 4;
-
- qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
- LUT1(ADDR, PAD1, addrlen),
- base + QUADSPI_LUT(lut_base));
-
- /* Erase the whole chip */
- lut_base = SEQID_CHIP_ERASE * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
- base + QUADSPI_LUT(lut_base));
-
- /* READ ID */
- lut_base = SEQID_RDID * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDID) |
- LUT1(FSL_READ, PAD1, 0x8),
- base + QUADSPI_LUT(lut_base));
-
- /* Write Register */
- lut_base = SEQID_WRSR * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRSR) |
- LUT1(FSL_WRITE, PAD1, 0x2),
- base + QUADSPI_LUT(lut_base));
-
- /* Read Configuration Register */
- lut_base = SEQID_RDCR * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RDCR) |
- LUT1(FSL_READ, PAD1, 0x1),
- base + QUADSPI_LUT(lut_base));
-
- /* Write disable */
- lut_base = SEQID_WRDI * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WRDI),
- base + QUADSPI_LUT(lut_base));
-
- /* Enter 4 Byte Mode (Micron) */
- lut_base = SEQID_EN4B * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_EN4B),
- base + QUADSPI_LUT(lut_base));
-
- /* Enter 4 Byte Mode (Spansion) */
- lut_base = SEQID_BRWR * 4;
- qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
- base + QUADSPI_LUT(lut_base));
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_STOP, 0, 0);
+ lutidx++;
- fsl_qspi_lock_lut(q);
-}
+ dev_dbg(q->dev, "cmd:%x lut:[%x, %x, %x, %x]\n", op->cmd.opcode,
+ lutval[0], lutval[1], lutval[2], lutval[3]);
-/* Get the SEQID for the command */
-static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
-{
- switch (cmd) {
- case SPINOR_OP_READ_1_1_4:
- return SEQID_READ;
- case SPINOR_OP_WREN:
- return SEQID_WREN;
- case SPINOR_OP_WRDI:
- return SEQID_WRDI;
- case SPINOR_OP_RDSR:
- return SEQID_RDSR;
- case SPINOR_OP_SE:
- return SEQID_SE;
- case SPINOR_OP_CHIP_ERASE:
- return SEQID_CHIP_ERASE;
- case SPINOR_OP_PP:
- return SEQID_PP;
- case SPINOR_OP_RDID:
- return SEQID_RDID;
- case SPINOR_OP_WRSR:
- return SEQID_WRSR;
- case SPINOR_OP_RDCR:
- return SEQID_RDCR;
- case SPINOR_OP_EN4B:
- return SEQID_EN4B;
- case SPINOR_OP_BRWR:
- return SEQID_BRWR;
- default:
- if (cmd == q->nor[0].erase_opcode)
- return SEQID_SE;
- dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
- break;
- }
- return -EINVAL;
+ /* Dynamic LUT */
+ if (op->mode == QSPI_CMD_MODE_IP)
+ lut_base = SEQID_LUT1_IPCMD * 4;
+ else
+ lut_base = SEQID_LUT2_AHBREAD * 4;
+
+ /* Write values in LUT register. */
+ fsl_qspi_unlock_lut(q);
+ for (i = 0; i < ARRAY_SIZE(lutval); i++)
+ qspi_writel(q, lutval[i], base + QUADSPI_LUT(lut_base + i));
+ fsl_qspi_lock_lut(q);
}
static int
fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
{
void __iomem *base = q->iobase;
- int seqid;
u32 reg, reg2;
int err;
@@ -532,8 +526,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
} while (1);
/* trigger the LUT now */
- seqid = fsl_qspi_get_seqid(q, cmd);
- qspi_writel(q, (seqid << QUADSPI_IPCR_SEQID_SHIFT) | len,
+ qspi_writel(q, (SEQID_LUT1_IPCMD << QUADSPI_IPCR_SEQID_SHIFT) | len,
base + QUADSPI_IPCR);
/* Wait for the interrupt. */
@@ -648,6 +641,19 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
}
+/* Clear only decision making fields of struct fsl_qspi_mem_op.
+ * Not used memset to clear whole structure as clearing of fields required
+ * to be done for every CMD and it would be performance hit.
+ */
+static inline void fsl_clr_qspi_mem_data(struct fsl_qspi_mem_op *op)
+{
+ op->cmd.opcode = 0;
+ op->addr.addrlen = 0;
+ op->dummy.ncycles = 0;
+ op->data.dir = QSPI_MEM_NO_DATA;
+ op->mode = QSPI_CMD_MODE_IP;
+}
+
/*
* There are two different ways to read out the data from the flash:
* the "IP Command Read" and the "AHB Command Read".
@@ -664,7 +670,6 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
- int seqid;
/* AHB configuration for access buffer 0/1/2 .*/
qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
@@ -684,12 +689,38 @@ static void fsl_qspi_init_ahb_read(struct fsl_qspi *q)
qspi_writel(q, 0, base + QUADSPI_BUF1IND);
qspi_writel(q, 0, base + QUADSPI_BUF2IND);
- /* Set the default lut sequence for AHB Read. */
- seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
- qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
+ /* Save SEQID_LUT2_AHBREAD in QUADSPI_BFGENCR, required for AHB Read */
+ qspi_writel(q, SEQID_LUT2_AHBREAD << QUADSPI_BFGENCR_SEQID_SHIFT,
q->iobase + QUADSPI_BFGENCR);
}
+/* Prepare LUT for AHB read - required for read from devmem interface */
+static void fsl_qspi_prep_ahb_read(struct fsl_qspi *q)
+{
+ struct fsl_qspi_mem_op op;
+ struct spi_nor *nor = q->nor;
+ enum spi_nor_protocol protocol = nor->read_proto;
+
+ fsl_clr_qspi_mem_data(&op);
+ op.cmd.opcode = nor->read_opcode;
+ op.cmd.pad = spi_nor_get_protocol_inst_nbits(protocol);
+
+ op.addr.addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
+ op.addr.pad = spi_nor_get_protocol_addr_nbits(protocol);
+
+ op.dummy.ncycles = nor->read_dummy;
+ op.dummy.pad = spi_nor_get_protocol_data_nbits(protocol);
+
+ op.data.dir = QSPI_MEM_DATA_IN;
+ op.data.pad = spi_nor_get_protocol_data_nbits(protocol);
+ /* Data size ignored for AHB Read. */
+ op.data.nbytes = 0;
+
+ op.mode = QSPI_CMD_MODE_AHB;
+
+ fsl_qspi_prepare_lut(nor, &op);
+}
+
/* This function was used to prepare and enable QSPI clock */
static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q)
{
@@ -728,7 +759,6 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
void __iomem *base = q->iobase;
u32 reg;
int ret;
-
/* disable and unprepare clock to avoid glitch pass to controller */
fsl_qspi_clk_disable_unprep(q);
@@ -746,9 +776,6 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
base + QUADSPI_MCR);
udelay(1);
- /* Init the LUT table. */
- fsl_qspi_init_lut(q);
-
/* Disable the module */
qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
base + QUADSPI_MCR);
@@ -791,12 +818,12 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
if (ret)
return ret;
- /* Init the LUT table again. */
- fsl_qspi_init_lut(q);
-
/* Init for AHB read */
fsl_qspi_init_ahb_read(q);
+ /* Prepare LUT for AHB read - required for read from devmem interface */
+ fsl_qspi_prep_ahb_read(q);
+
return 0;
}
@@ -819,7 +846,24 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
int ret;
struct fsl_qspi *q = nor->priv;
+ struct fsl_qspi_mem_op op;
+ enum spi_nor_protocol protocol = nor->reg_proto;
+
+ fsl_clr_qspi_mem_data(&op);
+ /*
+ * Fill required entry of struct fsl_qspi_mem_op to prepare
+ * LUT for requested cmd.
+ */
+ op.cmd.opcode = opcode;
+ op.cmd.pad = spi_nor_get_protocol_inst_nbits(protocol);
+
+ op.data.dir = QSPI_MEM_DATA_IN;
+ op.data.pad = spi_nor_get_protocol_data_nbits(protocol);
+ /* Data size provided when QSPI cmd trigger. */
+ op.data.nbytes = 0;
+ /* Addrlen and Dummy info not required for READ_REG cmds */
+ fsl_qspi_prepare_lut(nor, &op);
ret = fsl_qspi_runcmd(q, opcode, 0, len);
if (ret)
return ret;
@@ -832,8 +876,20 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
struct fsl_qspi *q = nor->priv;
int ret;
+ struct fsl_qspi_mem_op op;
+ enum spi_nor_protocol protocol = nor->reg_proto;
+
+ fsl_clr_qspi_mem_data(&op);
+ /*
+ * Fill required entry of struct fsl_qspi_mem_op to prepare
+ * LUT for requested cmd.
+ */
+ op.cmd.opcode = opcode;
+ op.cmd.pad = spi_nor_get_protocol_inst_nbits(protocol);
if (!buf) {
+ /* Addrlen, Dummy and Data info not required for WRITE_REG */
+ fsl_qspi_prepare_lut(nor, &op);
ret = fsl_qspi_runcmd(q, opcode, 0, 1);
if (ret)
return ret;
@@ -842,6 +898,13 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
fsl_qspi_invalid(q);
} else if (len > 0) {
+ /* Addrlen and Dummy not requ with BUF as non-null */
+ op.data.dir = QSPI_MEM_DATA_OUT;
+ op.data.pad = spi_nor_get_protocol_data_nbits(protocol);
+ /* Data size provided when QSPI cmd trigger. */
+ op.data.nbytes = 0;
+
+ fsl_qspi_prepare_lut(nor, &op);
ret = fsl_qspi_nor_write(q, nor, opcode, 0,
(u32 *)buf, len);
if (ret > 0)
@@ -858,8 +921,31 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
size_t len, const u_char *buf)
{
struct fsl_qspi *q = nor->priv;
- ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
- (u32 *)buf, len);
+ ssize_t ret;
+ struct fsl_qspi_mem_op op;
+ enum spi_nor_protocol protocol = nor->write_proto;
+
+ fsl_clr_qspi_mem_data(&op);
+ /*
+ * Fill required entry of struct fsl_qspi_mem_op to prepare
+ * LUT for requested cmd.
+ */
+ op.cmd.opcode = nor->program_opcode;
+ op.cmd.pad = spi_nor_get_protocol_inst_nbits(protocol);
+
+ op.addr.addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
+ op.addr.pad = spi_nor_get_protocol_addr_nbits(protocol);
+
+ op.data.dir = QSPI_MEM_DATA_OUT;
+ op.data.pad = spi_nor_get_protocol_data_nbits(protocol);
+
+ /* TX data size provided when QSPI cmd trigger. */
+ op.data.nbytes = 0;
+
+ /* Dummy info not required for WRITE cmd */
+ fsl_qspi_prepare_lut(nor, &op);
+ ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
+ (u32 *)buf, len);
/* invalid the data in the AHB buffer. */
fsl_qspi_invalid(q);
@@ -871,6 +957,31 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
{
struct fsl_qspi *q = nor->priv;
u8 cmd = nor->read_opcode;
+ struct fsl_qspi_mem_op op;
+ enum spi_nor_protocol protocol = nor->read_proto;
+
+ fsl_clr_qspi_mem_data(&op);
+ /*
+ * Fill required entry of struct fsl_qspi_mem_op to prepare
+ * LUT for requested cmd.
+ */
+ op.cmd.opcode = cmd;
+ op.cmd.pad = spi_nor_get_protocol_inst_nbits(protocol);
+
+ op.addr.addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
+ op.addr.pad = spi_nor_get_protocol_addr_nbits(protocol);
+
+ op.dummy.ncycles = nor->read_dummy;
+ op.dummy.pad = spi_nor_get_protocol_data_nbits(protocol);
+
+ op.data.dir = QSPI_MEM_DATA_IN;
+ op.data.pad = spi_nor_get_protocol_data_nbits(protocol);
+ /* Data size ignored for AHB Read. */
+ op.data.nbytes = 0;
+
+ op.mode = QSPI_CMD_MODE_AHB;
+
+ fsl_qspi_prepare_lut(nor, &op);
/* if necessary,ioremap buffer before AHB read, */
if (!q->ahb_addr) {
@@ -916,6 +1027,23 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
{
struct fsl_qspi *q = nor->priv;
int ret;
+ struct fsl_qspi_mem_op op;
+
+ fsl_clr_qspi_mem_data(&op);
+
+ /*
+ * Fill required entry of struct fsl_qspi_mem_op to prepare
+ * LUT for requested cmd.
+ * Erase operation works on single pad.
+ */
+ op.cmd.opcode = nor->erase_opcode;
+ op.cmd.pad = 1;
+
+ op.addr.addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
+ op.addr.pad = 1;
+
+ /* Dummy and Data info not required for Erase cmd */
+ fsl_qspi_prepare_lut(nor, &op);
dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
nor->mtd.erasesize / 1024, q->chip_base_addr, (u32)offs);