summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorHan Xu <b45815@freescale.com>2015-11-03 16:52:25 -0600
committerNitin Garg <nitin.garg@nxp.com>2016-01-14 11:02:32 -0600
commitcd0ace50b70739dfa2e054242ab77caa8784b857 (patch)
tree51b88a1aa1db9165ecaa2212c169b55ca05d9d39 /drivers/mtd
parente231d0400a1d8cbfcb7a974d897d32ce0112848c (diff)
MLK-11941: mtd: spi-nor: add DDR quad read support
This patch adds the DDR quad read support by the following: [1] add SPI_NOR_DDR_QUAD read mode. [2] add DDR Quad read opcodes: SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D [3] add set_ddr_quad_mode() to initialize for the DDR quad read. Currently it only works for Spansion NOR. [3] about the dummy cycles. We set the dummy with 8 for DDR quad read by default. The m25p80.c can not support the DDR quad read, but the SPI NOR controller can set the dummy value in its child DT node, and the SPI NOR framework can parse it out. Signed-off-by: Han Xu <b45815@freescale.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4efe7e84bf57..f708a465526d 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -55,6 +55,7 @@ struct flash_info {
#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */
#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */
#define USE_FSR 0x80 /* use flag status register */
+#define SPI_NOR_DDR_QUAD_READ 0x100 /* Flash supports DDR Quad Read */
};
#define JEDEC_MFR(info) ((info)->id[0])
@@ -125,7 +126,20 @@ static int read_cr(struct spi_nor *nor)
*/
static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
{
+ u32 dummy;
+
switch (nor->flash_read) {
+ case SPI_NOR_DDR_QUAD:
+ /*
+ * The m25p80.c can not support the DDR quad read.
+ * We set the dummy cycles to 8 by default. The SPI NOR
+ * controller driver can set it in its child DT node.
+ * We parse it out here.
+ */
+ if (nor->np && !of_property_read_u32(nor->np,
+ "spi-nor,ddr-quad-read-dummy", &dummy)) {
+ return dummy;
+ }
case SPI_NOR_FAST:
case SPI_NOR_DUAL:
case SPI_NOR_QUAD:
@@ -949,6 +963,24 @@ static int micron_quad_enable(struct spi_nor *nor)
return 0;
}
+static int set_ddr_quad_mode(struct spi_nor *nor, struct flash_info *info)
+{
+ int status;
+
+ switch (JEDEC_MFR(info)) {
+ case CFI_MFR_AMD: /* Spansion, actually */
+ status = spansion_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev,
+ "Spansion DDR quad-read not enabled\n");
+ return status;
+ }
+ return status;
+ default:
+ return -EINVAL;
+ }
+}
+
static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
{
int status;
@@ -1118,8 +1150,15 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (info->flags & SPI_NOR_NO_FR)
nor->flash_read = SPI_NOR_NORMAL;
- /* Quad/Dual-read mode takes precedence over fast/normal */
- if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+ /* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
+ if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
+ ret = set_ddr_quad_mode(nor, info);
+ if (ret) {
+ dev_err(dev, "DDR quad mode not supported\n");
+ return ret;
+ }
+ nor->flash_read = SPI_NOR_DDR_QUAD;
+ } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
ret = set_quad_mode(nor, info);
if (ret) {
dev_err(dev, "quad mode not supported\n");
@@ -1132,6 +1171,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
/* Default commands */
switch (nor->flash_read) {
+ case SPI_NOR_DDR_QUAD:
+ if (JEDEC_MFR(info) == CFI_MFR_AMD) { /* Spansion */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
+ } else {
+ dev_err(dev, "DDR Quad Read is not supported.\n");
+ return -EINVAL;
+ }
+ break;
case SPI_NOR_QUAD:
nor->read_opcode = SPINOR_OP_READ_1_1_4;
break;
@@ -1159,6 +1206,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (JEDEC_MFR(info) == CFI_MFR_AMD) {
/* Dedicated 4-byte command set */
switch (nor->flash_read) {
+ case SPI_NOR_DDR_QUAD:
+ nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
+ break;
case SPI_NOR_QUAD:
nor->read_opcode = SPINOR_OP_READ4_1_1_4;
break;