summaryrefslogtreecommitdiff
path: root/drivers/mtd/spi-nor/fsl-quadspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi-nor/fsl-quadspi.c')
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c327
1 files changed, 270 insertions, 57 deletions
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4e..33ecc27 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -41,6 +41,8 @@
#define QUADSPI_QUIRK_TKT253890 (1 << 2)
/* Controller cannot wake up from wait mode, TKT245618 */
#define QUADSPI_QUIRK_TKT245618 (1 << 3)
+/* QSPI_AMBA_BASE is internally added by SOC design */
+#define QUADSPI_AMBA_BASE_INTERNAL (0x10000)
/* The registers */
#define QUADSPI_MCR 0x00
@@ -193,7 +195,7 @@
#define QUADSPI_LUT_NUM 64
/* SEQID -- we can have 16 seqids at most. */
-#define SEQID_QUAD_READ 0
+#define SEQID_READ 0
#define SEQID_WREN 1
#define SEQID_WRDI 2
#define SEQID_RDSR 3
@@ -205,15 +207,22 @@
#define SEQID_RDCR 9
#define SEQID_EN4B 10
#define SEQID_BRWR 11
+#define SEQID_RDAR_OR_RD_EVCR 12
+#define SEQID_WRAR 13
+#define SEQID_WD_EVCR 14
#define QUADSPI_MIN_IOMAP SZ_4M
+#define FLASH_VENDOR_SPANSION_FS "s25fs"
+#define SPANSION_S25FS_FAMILY (1 << 1)
+
enum fsl_qspi_devtype {
FSL_QUADSPI_VYBRID,
FSL_QUADSPI_IMX6SX,
FSL_QUADSPI_IMX7D,
FSL_QUADSPI_IMX6UL,
FSL_QUADSPI_LS1021A,
+ FSL_QUADSPI_LS2080A,
};
struct fsl_qspi_devtype_data {
@@ -224,7 +233,7 @@ struct fsl_qspi_devtype_data {
int driver_data;
};
-static struct fsl_qspi_devtype_data vybrid_data = {
+static const struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128,
.txfifo = 64,
@@ -232,7 +241,7 @@ static struct fsl_qspi_devtype_data vybrid_data = {
.driver_data = QUADSPI_QUIRK_SWAP_ENDIAN,
};
-static struct fsl_qspi_devtype_data imx6sx_data = {
+static const struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128,
.txfifo = 512,
@@ -241,7 +250,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = {
| QUADSPI_QUIRK_TKT245618,
};
-static struct fsl_qspi_devtype_data imx7d_data = {
+static const struct fsl_qspi_devtype_data imx7d_data = {
.devtype = FSL_QUADSPI_IMX7D,
.rxfifo = 512,
.txfifo = 512,
@@ -250,7 +259,7 @@ static struct fsl_qspi_devtype_data imx7d_data = {
| QUADSPI_QUIRK_4X_INT_CLK,
};
-static struct fsl_qspi_devtype_data imx6ul_data = {
+static const struct fsl_qspi_devtype_data imx6ul_data = {
.devtype = FSL_QUADSPI_IMX6UL,
.rxfifo = 128,
.txfifo = 512,
@@ -267,6 +276,14 @@ static struct fsl_qspi_devtype_data ls1021a_data = {
.driver_data = 0,
};
+static struct fsl_qspi_devtype_data ls2080a_data = {
+ .devtype = FSL_QUADSPI_LS2080A,
+ .rxfifo = 128,
+ .txfifo = 64,
+ .ahb_buf_size = 1024,
+ .driver_data = QUADSPI_AMBA_BASE_INTERNAL | QUADSPI_QUIRK_TKT253890,
+};
+
#define FSL_QSPI_MAX_CHIP 4
struct fsl_qspi {
struct spi_nor nor[FSL_QSPI_MAX_CHIP];
@@ -282,6 +299,7 @@ struct fsl_qspi {
u32 nor_size;
u32 nor_num;
u32 clk_rate;
+ u32 ddr_smp;
unsigned int chip_base_addr; /* We may support two chips. */
bool has_second_chip;
bool big_endian;
@@ -309,6 +327,23 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
}
+static inline int has_added_amba_base_internal(struct fsl_qspi *q)
+{
+ return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL;
+}
+
+static u32 fsl_get_nor_vendor(struct spi_nor *nor)
+{
+ u32 vendor_id;
+
+ if (nor->vendor) {
+ if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS,
+ sizeof(FLASH_VENDOR_SPANSION_FS) - 1))
+ vendor_id = SPANSION_S25FS_FAMILY;
+ }
+ return vendor_id;
+}
+
/*
* R/W functions for big- or little-endian registers:
* The qSPI controller's endian is independent of the CPU core's endian.
@@ -331,6 +366,31 @@ static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr)
return ioread32(addr);
}
+static inline u32 *u8tou32(u32 *dest, const u8 *src, size_t n)
+{
+ size_t i;
+ *dest = 0;
+
+ n = n > 4 ? 4 : n;
+ for (i = 0; i < n; i++)
+ *dest |= *src++ << i * 8;
+
+ return dest;
+
+}
+
+static inline u8 *u32tou8(u8 *dest, const u32 *src, size_t n)
+{
+ size_t i;
+ u8 *xdest = dest;
+
+ n = n > 4 ? 4 : n;
+ for (i = 0; i < n; i++)
+ *xdest++ = *src >> i * 8;
+
+ return dest;
+}
+
/*
* An IC bug makes us to re-arrange the 32-bit data.
* The following chips, such as IMX6SLX, have fixed this bug.
@@ -373,8 +433,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
void __iomem *base = q->iobase;
int rxfifo = q->devtype_data->rxfifo;
u32 lut_base;
- u8 cmd, addrlen, dummy;
int i;
+ u32 vendor;
+
+ 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;
+
+ vendor = fsl_get_nor_vendor(nor);
fsl_qspi_unlock_lut(q);
@@ -382,25 +449,51 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
for (i = 0; i < QUADSPI_LUT_NUM; i++)
qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
- /* Quad Read */
- lut_base = SEQID_QUAD_READ * 4;
-
- if (q->nor_size <= SZ_16M) {
- cmd = SPINOR_OP_READ_1_1_4;
- addrlen = ADDR24BIT;
- dummy = 8;
- } else {
- /* use the 4-byte address */
- cmd = SPINOR_OP_READ_1_1_4;
- addrlen = ADDR32BIT;
- dummy = 8;
- }
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ /* Read */
+ lut_base = SEQID_READ * 4;
+
+ if (nor->flash_read == SPI_NOR_FAST) {
+ 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, PAD1, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+ } else if (nor->flash_read == SPI_NOR_QUAD) {
+ if (q->nor_size == 0x4000000) {
+ read_op = 0xEC;
+ qspi_writel(q,
+ LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen),
+ base + QUADSPI_LUT(lut_base));
+ qspi_writel(q,
+ LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm),
+ base + QUADSPI_LUT(lut_base + 1));
+ qspi_writel(q,
+ LUT0(FSL_READ, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 2));
+ } else {
+ 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));
+ }
+ } else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
+ /* read mode : 1-4-4, such as Spansion s25fl128s. */
+ qspi_writel(q, LUT0(CMD, PAD1, read_op)
+ | LUT1(ADDR_DDR, PAD4, addrlen),
base + QUADSPI_LUT(lut_base));
- qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
+
+ qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff)
+ | LUT1(DUMMY, PAD1, read_dm),
base + QUADSPI_LUT(lut_base + 1));
+ qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo)
+ | LUT1(JMP_ON_CS, PAD1, 0),
+ base + QUADSPI_LUT(lut_base + 2));
+ }
+
/* Write enable */
lut_base = SEQID_WREN * 4;
qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN),
@@ -409,16 +502,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Page Program */
lut_base = SEQID_PP * 4;
- if (q->nor_size <= SZ_16M) {
- cmd = SPINOR_OP_PP;
- addrlen = ADDR24BIT;
- } else {
- /* use the 4-byte address */
- cmd = SPINOR_OP_PP;
- addrlen = ADDR32BIT;
- }
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ 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));
@@ -432,10 +517,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Erase a sector */
lut_base = SEQID_SE * 4;
- cmd = q->nor[0].erase_opcode;
- addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) |
+ LUT1(ADDR, PAD1, addrlen),
base + QUADSPI_LUT(lut_base));
/* Erase the whole chip */
@@ -476,6 +559,44 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
base + QUADSPI_LUT(lut_base));
+
+ /*
+ * Flash Micron and Spansion command confilict
+ * use the same value 0x65. But it indicates different meaning.
+ */
+ lut_base = SEQID_RDAR_OR_RD_EVCR * 4;
+
+ if (vendor == SPANSION_S25FS_FAMILY) {
+ /*
+ * Read any device register.
+ * Used for Spansion S25FS-S family flash only.
+ */
+ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_RDAR) |
+ LUT1(ADDR, PAD1, ADDR24BIT),
+ base + QUADSPI_LUT(lut_base));
+ qspi_writel(q, LUT0(DUMMY, PAD1, 8) | LUT1(FSL_READ, PAD1, 1),
+ base + QUADSPI_LUT(lut_base + 1));
+ } else {
+ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR),
+ base + QUADSPI_LUT(lut_base));
+ }
+
+ /*
+ * Write any device register.
+ * Used for Spansion S25FS-S family flash only.
+ */
+ lut_base = SEQID_WRAR * 4;
+ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_WRAR) |
+ LUT1(ADDR, PAD1, ADDR24BIT),
+ base + QUADSPI_LUT(lut_base));
+ qspi_writel(q, LUT0(FSL_WRITE, PAD1, 1),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ /* Write EVCR register */
+ lut_base = SEQID_WD_EVCR * 4;
+ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR),
+ base + QUADSPI_LUT(lut_base));
+
fsl_qspi_lock_lut(q);
}
@@ -483,8 +604,24 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
{
switch (cmd) {
+ case SPINOR_OP_READ_1_4_4_D:
+ case SPINOR_OP_READ4_1_4_4_D:
+ case SPINOR_OP_READ4_1_1_4:
case SPINOR_OP_READ_1_1_4:
- return SEQID_QUAD_READ;
+ case SPINOR_OP_READ_FAST:
+ case SPINOR_OP_READ4_FAST:
+ return SEQID_READ;
+ /*
+ * Spansion & Micron use the same command value 0x65
+ * Spansion: SPINOR_OP_SPANSION_RDAR, read any register.
+ * Micron: SPINOR_OP_RD_EVCR,
+ * read enhanced volatile configuration register.
+ * case SPINOR_OP_RD_EVCR:
+ */
+ case SPINOR_OP_SPANSION_RDAR:
+ return SEQID_RDAR_OR_RD_EVCR;
+ case SPINOR_OP_SPANSION_WRAR:
+ return SEQID_WRAR;
case SPINOR_OP_WREN:
return SEQID_WREN;
case SPINOR_OP_WRDI:
@@ -496,6 +633,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
case SPINOR_OP_CHIP_ERASE:
return SEQID_CHIP_ERASE;
case SPINOR_OP_PP:
+ case SPINOR_OP_PP_4B:
return SEQID_PP;
case SPINOR_OP_RDID:
return SEQID_RDID;
@@ -507,6 +645,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
return SEQID_EN4B;
case SPINOR_OP_BRWR:
return SEQID_BRWR;
+ case SPINOR_OP_WD_EVCR:
+ return SEQID_WD_EVCR;
default:
if (cmd == q->nor[0].erase_opcode)
return SEQID_SE;
@@ -531,8 +671,11 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
/* save the reg */
reg = qspi_readl(q, base + QUADSPI_MCR);
- qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
- base + QUADSPI_SFAR);
+ if (has_added_amba_base_internal(q))
+ qspi_writel(q, q->chip_base_addr + addr, base + QUADSPI_SFAR);
+ else
+ qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr,
+ base + QUADSPI_SFAR);
qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
base + QUADSPI_RBCT);
qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
@@ -582,10 +725,10 @@ static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
q->chip_base_addr, tmp);
if (len >= 4) {
- *((u32 *)rxbuf) = tmp;
+ u32tou8(rxbuf, &tmp, 4);
rxbuf += 4;
} else {
- memcpy(rxbuf, &tmp, len);
+ u32tou8(rxbuf, &tmp, len);
break;
}
@@ -619,11 +762,12 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q)
}
static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
- u8 opcode, unsigned int to, u32 *txbuf,
+ u8 opcode, unsigned int to, u8 *txbuf,
unsigned count)
{
int ret, i, j;
u32 tmp;
+ u8 byts;
dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
q->chip_base_addr, to, count);
@@ -633,10 +777,13 @@ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR);
/* fill the TX data to the FIFO */
+ byts = count;
for (j = 0, i = ((count + 3) / 4); j < i; j++) {
- tmp = fsl_qspi_endian_xchg(q, *txbuf);
+ u8tou32(&tmp, txbuf, byts);
+ tmp = fsl_qspi_endian_xchg(q, tmp);
qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR);
- txbuf++;
+ txbuf += 4;
+ byts -= 4;
}
/* fill the TXFIFO upto 16 bytes for i.MX7d */
@@ -657,11 +804,43 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
{
int nor_size = q->nor_size;
void __iomem *base = q->iobase;
+ u32 mem_base;
+
+ if (has_added_amba_base_internal(q))
+ mem_base = 0x0;
+ else
+ mem_base = q->memmap_phy;
+
+ qspi_writel(q, nor_size + mem_base, base + QUADSPI_SFA1AD);
+ qspi_writel(q, nor_size * 2 + mem_base, base + QUADSPI_SFA2AD);
+ qspi_writel(q, nor_size * 3 + mem_base, base + QUADSPI_SFB1AD);
+ qspi_writel(q, nor_size * 4 + mem_base, base + QUADSPI_SFB2AD);
+}
+
+/*
+ * enable controller ddr quad mode to support different
+ * vender flashes ddr quad mode.
+ */
+static void set_ddr_quad_mode(struct fsl_qspi *q)
+{
+ u32 reg, reg2;
+
+ reg = qspi_readl(q, q->iobase + QUADSPI_MCR);
+
+ /* Firstly, disable the module */
+ qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+
+ /* Set the Sampling Register for DDR */
+ reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR);
+ reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK;
+ reg2 |= (((q->ddr_smp) << QUADSPI_SMPR_DDRSMP_SHIFT) &
+ QUADSPI_SMPR_DDRSMP_MASK);
+ qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR);
+
+ /* Enable the module again (enable the DDR too) */
+ reg |= QUADSPI_MCR_DDR_EN_MASK;
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
- qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
- qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
- qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
- qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
}
/*
@@ -704,6 +883,11 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
q->iobase + QUADSPI_BFGENCR);
+
+ /* enable the DDR quad read */
+ if (q->nor->flash_read == SPI_NOR_DDR_QUAD)
+ set_ddr_quad_mode(q);
+
}
/* This function was used to prepare and enable QSPI clock */
@@ -822,6 +1006,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
+ { .compatible = "fsl,ls2080a-qspi", .data = (void *)&ls2080a_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
@@ -835,8 +1020,12 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
int ret;
struct fsl_qspi *q = nor->priv;
+ u32 to = 0;
- ret = fsl_qspi_runcmd(q, opcode, 0, len);
+ if (opcode == SPINOR_OP_SPANSION_RDAR)
+ u8tou32(&to, nor->cmd_buf, 4);
+
+ ret = fsl_qspi_runcmd(q, opcode, to, len);
if (ret)
return ret;
@@ -848,9 +1037,13 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
struct fsl_qspi *q = nor->priv;
int ret;
+ u32 to = 0;
+
+ if (opcode == SPINOR_OP_SPANSION_WRAR)
+ u8tou32(&to, nor->cmd_buf, 4);
if (!buf) {
- ret = fsl_qspi_runcmd(q, opcode, 0, 1);
+ ret = fsl_qspi_runcmd(q, opcode, to, 1);
if (ret)
return ret;
@@ -859,7 +1052,7 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
} else if (len > 0) {
ret = fsl_qspi_nor_write(q, nor, opcode, 0,
- (u32 *)buf, len);
+ buf, len);
if (ret > 0)
return 0;
} else {
@@ -875,7 +1068,7 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
{
struct fsl_qspi *q = nor->priv;
ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
- (u32 *)buf, len);
+ (u8 *)buf, len);
/* invalid the data in the AHB buffer. */
fsl_qspi_invalid(q);
@@ -922,7 +1115,7 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
len);
/* Read out the data directly from the AHB buffer.*/
- memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
+ memcpy_toio(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
len);
return len;
@@ -980,6 +1173,8 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct spi_nor *nor;
struct mtd_info *mtd;
int ret, i = 0;
+ int find_node;
+ enum read_mode mode = SPI_NOR_QUAD;
q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
if (!q)
@@ -1027,6 +1222,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
goto clk_failed;
}
+ /* find ddrsmp value */
+ ret = of_property_read_u32(dev->of_node, "fsl,ddr-sampling-point",
+ &q->ddr_smp);
+ if (ret)
+ q->ddr_smp = 0;
+
/* find the irq */
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
@@ -1050,6 +1251,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
mutex_init(&q->lock);
+ find_node = 0;
/* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) {
/* skip the holes */
@@ -1076,18 +1278,25 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = of_property_read_u32(np, "spi-max-frequency",
&q->clk_rate);
if (ret < 0)
- goto mutex_failed;
+ continue;
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
- ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+ ret = of_property_read_bool(np, "m25p,fast-read");
+ mode = (ret) ? SPI_NOR_FAST : SPI_NOR_QUAD;
+ /* Can we enable the DDR Quad Read? */
+ ret = of_property_read_bool(np, "ddr-quad-read");
if (ret)
- goto mutex_failed;
+ mode = SPI_NOR_DDR_QUAD;
+
+ ret = spi_nor_scan(nor, NULL, mode);
+ if (ret)
+ continue;
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
- goto mutex_failed;
+ continue;
/* Set the correct NOR size now. */
if (q->nor_size == 0) {
@@ -1110,8 +1319,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
nor->page_size = q->devtype_data->txfifo;
i++;
+ find_node++;
}
+ if (find_node == 0)
+ goto mutex_failed;
+
/* finish the rest init. */
ret = fsl_qspi_nor_setup_last(q);
if (ret)