diff options
author | Han Xu <han.xu@nxp.com> | 2018-04-11 11:59:26 -0500 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:29:06 +0800 |
commit | 0e88f922b84e590d74ee377e7021ce56df17ad7e (patch) | |
tree | ae5fa651d00c77a4d5713b511e68164225ad0489 | |
parent | 6b3a60b40202e462c8569eb672b4af86b7b0696b (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.c | 91 | ||||
-rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 38 |
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 = ¶ms->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. */ |