summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHan Xu <han.xu@nxp.com>2018-04-11 11:59:26 -0500
committerJason Liu <jason.hui.liu@nxp.com>2019-02-12 10:29:06 +0800
commit0e88f922b84e590d74ee377e7021ce56df17ad7e (patch)
treeae5fa651d00c77a4d5713b511e68164225ad0489
parent6b3a60b40202e462c8569eb672b4af86b7b0696b (diff)
MLK-18002-2: mtd: fsl-quadspi: enable ddr mode
Enable the DDR mode with for SFDP. The code mapped the STR cmd to DTR cmd and en/disable DDR module according to protocol type. Signed-off-by: Han Xu <han.xu@nxp.com>
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c91
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c38
2 files changed, 123 insertions, 6 deletions
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 1c9beb4738e6..e3f9448ca02b 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -45,6 +45,9 @@
/* The registers */
#define QUADSPI_MCR 0x00
+#define MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_SHIFT 29
+#define MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_MASK \
+ (1 << MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_SHIFT)
#define QUADSPI_MCR_RESERVED_SHIFT 16
#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT)
#define QUADSPI_MCR_MDIS_SHIFT 14
@@ -66,6 +69,11 @@
#define QUADSPI_IPCR_SEQID_SHIFT 24
#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT)
+#define QUADSPI_FLSHCR 0x0c
+#define QUADSPI_FLSHCR_TDH_SHIFT 16
+#define QUADSPI_FLSHCR_TDH_MASK (3 << QUADSPI_FLSHCR_TDH_SHIFT)
+#define QUADSPI_FLSHCR_TDH_DDR_EN (1 << QUADSPI_FLSHCR_TDH_SHIFT)
+
#define QUADSPI_BUF0CR 0x10
#define QUADSPI_BUF1CR 0x14
#define QUADSPI_BUF2CR 0x18
@@ -478,23 +486,42 @@ static void fsl_qspi_prepare_lut(struct spi_nor *nor,
LUT1(ADDR, pad_count(addr_pad), addrlen),
base + QUADSPI_LUT(lut_base));
+ if (spi_nor_protocol_is_dtr(protocol))
+ qspi_writel(q, LUT0(CMD, pad_count(cmd_pad), opcode) |
+ LUT1(ADDR_DDR, pad_count(addr_pad), addrlen),
+ base + QUADSPI_LUT(lut_base));
/*
* For cmds SPINOR_OP_READ and SPINOR_OP_READ_4B value
* of dummy cycles are 0.
*/
- if (read_dm)
+ if (read_dm) {
qspi_writel(q,
LUT0(DUMMY, pad_count(dummy_pad),
read_dm) |
LUT1(FSL_READ, pad_count(data_pad),
0),
base + QUADSPI_LUT(lut_base + 1));
- else
+
+ if (spi_nor_protocol_is_dtr(protocol))
+ qspi_writel(q,
+ LUT0(DUMMY, pad_count(dummy_pad),
+ read_dm) |
+ LUT1(FSL_READ_DDR, pad_count(data_pad),
+ 0),
+ base + QUADSPI_LUT(lut_base + 1));
+ } else {
qspi_writel(q,
LUT0(FSL_READ, pad_count(data_pad),
0),
base + QUADSPI_LUT(lut_base + 1));
+ if (spi_nor_protocol_is_dtr(protocol))
+ qspi_writel(q,
+ LUT0(FSL_READ_DDR, pad_count(data_pad),
+ 0),
+ base + QUADSPI_LUT(lut_base + 1));
+ }
+
stop_lut = 2;
/* TODO Add condition to check if READ is IP/AHB. */
@@ -892,6 +919,53 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to,
return ret;
}
+static void __fsl_qspi_enable_ddr_mode(struct spi_nor *nor, bool v)
+{
+ struct fsl_qspi *q = nor->priv;
+ u32 reg;
+ /* 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);
+
+ /* reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR); */
+ /* reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK; */
+
+ /* Set the Sampling Register for DDR, if to enable it */
+ /* if (v) */
+ /* reg2 |= ((q->ddr_smp << QUADSPI_SMPR_DDRSMP_SHIFT) & */
+ /* QUADSPI_SMPR_DDRSMP_MASK); */
+
+ /* qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR); */
+
+ /* Enable the module again and enable the DDR, if need */
+ if (v) {
+ reg |= QUADSPI_MCR_DDR_EN_MASK;
+ if (q->devtype_data->devtype == FSL_QUADSPI_IMX6SX)
+ reg |= MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_MASK;
+ }
+
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
+
+ if ((q->devtype_data->devtype == FSL_QUADSPI_IMX6UL) ||
+ (q->devtype_data->devtype == FSL_QUADSPI_IMX7D)) {
+
+ reg = qspi_readl(q, q->iobase + QUADSPI_FLSHCR);
+ reg &= ~QUADSPI_FLSHCR_TDH_MASK;
+
+ if (v)
+ reg |= QUADSPI_FLSHCR_TDH_DDR_EN;
+
+ qspi_writel(q, reg, q->iobase + QUADSPI_FLSHCR);
+ }
+}
+
+#define fsl_qspi_enable_ddr_mode(x) __fsl_qspi_enable_ddr_mode(x, true)
+#define fsl_qspi_disable_ddr_mode(x) __fsl_qspi_enable_ddr_mode(x, false)
+
static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
size_t len, u_char *buf)
{
@@ -901,6 +975,11 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
fsl_qspi_prepare_lut(nor, FSL_QSPI_OPS_READ, nor->read_opcode, len);
+ if (spi_nor_protocol_is_dtr(nor->read_proto))
+ fsl_qspi_enable_ddr_mode(nor);
+ else
+ fsl_qspi_disable_ddr_mode(nor);
+
/* if necessary,ioremap buffer before AHB read, */
if (!q->ahb_addr) {
q->memmap_offs = q->chip_base_addr + from;
@@ -999,7 +1078,7 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
static int fsl_qspi_probe(struct platform_device *pdev)
{
const struct spi_nor_hwcaps hwcaps = {
- .mask = SNOR_HWCAPS_READ_1_1_4 |
+ .mask = SNOR_HWCAPS_READ_1_4_4_DTR |
SNOR_HWCAPS_PP,
};
struct device_node *np = pdev->dev.of_node;
@@ -1059,6 +1138,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
if (IS_ERR(q->clk))
return PTR_ERR(q->clk);
+ /* find ddrsmp value */
+ /* ret = of_property_read_u32(dev->of_node, "ddrsmp", */
+ /* &q->ddr_smp); */
+ /* if (ret) */
+ /* q->ddr_smp = 0; */
+
ret = fsl_qspi_clk_prep_enable(q);
if (ret) {
dev_err(dev, "can not enable the clock\n");
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 37fbc68034ac..babbe2b44252 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -197,6 +197,18 @@ static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size)
return opcode;
}
+static inline u8 spi_nor_convert_str_to_dtr_read(u8 opcode)
+{
+ static const u8 spi_nor_sdr_to_dtr_read[][2] = {
+ { SPINOR_OP_READ_FAST, SPINOR_OP_READ_1_1_1_DTR },
+ { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_DTR },
+ { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_DTR },
+ };
+
+ return spi_nor_convert_opcode(opcode, spi_nor_sdr_to_dtr_read,
+ ARRAY_SIZE(spi_nor_sdr_to_dtr_read));
+};
+
static inline u8 spi_nor_convert_3to4_read(u8 opcode)
{
static const u8 spi_nor_3to4_read[][2] = {
@@ -1980,14 +1992,25 @@ struct sfdp_bfpt {
/* Fast Read settings. */
static inline void
-spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read,
+spi_nor_set_read_settings_from_bfpt(struct spi_nor *nor,
+ struct spi_nor_read_command *read,
u16 half,
enum spi_nor_protocol proto)
{
+ u8 opcode;
+
read->num_mode_clocks = (half >> 5) & 0x07;
read->num_wait_states = (half >> 0) & 0x1f;
- read->opcode = (half >> 8) & 0xff;
read->proto = proto;
+ opcode = (half >> 8) & 0xff;
+
+ if (spi_nor_protocol_is_dtr(proto))
+ opcode = spi_nor_convert_str_to_dtr_read(opcode);
+ if (nor->addr_width == 4)
+ opcode = spi_nor_convert_3to4_read(opcode);
+
+ read->opcode = opcode;
+
}
struct sfdp_bfpt_read {
@@ -2054,6 +2077,14 @@ static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = {
SNOR_PROTO_1_4_4,
},
+ /* Fast Read 1-4-4-DTR */
+ {
+ SNOR_HWCAPS_READ_1_4_4_DTR,
+ BFPT_DWORD(1), BIT(21), /* Supported bit */
+ BFPT_DWORD(3), 0, /* Settings */
+ SNOR_PROTO_1_4_4_DTR,
+ },
+
/* Fast Read 4-4-4 */
{
SNOR_HWCAPS_READ_4_4_4,
@@ -2193,7 +2224,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps);
read = &params->reads[cmd];
half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift;
- spi_nor_set_read_settings_from_bfpt(read, half, rd->proto);
+ spi_nor_set_read_settings_from_bfpt(nor, read, half, rd->proto);
}
/* Sector Erase settings. */
@@ -2596,6 +2627,7 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
* Keep only the hardware capabilities supported by both the SPI
* controller and the SPI flash memory.
*/
+
shared_mask = hwcaps->mask & params->hwcaps.mask;
/* SPI n-n-n protocols are not supported yet. */