1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
From 924f021c0344554a4b61746e5c4dcfc91d618ce2 Mon Sep 17 00:00:00 2001
From: Yunhui Cui <yunhui.cui@nxp.com>
Date: Thu, 18 Feb 2016 16:41:53 +0800
Subject: [PATCH 105/113] 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.
[4] set dummy with 6 for Spansion family
Test this patch for Spansion s25fl128s NOR flash.
Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
---
drivers/mtd/spi-nor/spi-nor.c | 53 ++++++++++++++++++++++++++++++++++++-----
include/linux/mtd/spi-nor.h | 8 +++++--
2 files changed, 53 insertions(+), 8 deletions(-)
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -73,7 +73,8 @@ struct flash_info {
#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */
#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 0x80 /* Flash supports DDR Quad Read */
+#define USE_FSR 0x100 /* use flag status register */
};
#define JEDEC_MFR(info) ((info)->id[0])
@@ -144,13 +145,17 @@ static int read_cr(struct spi_nor *nor)
* It can be used to support more commands with
* different dummy cycle requirements.
*/
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
+static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor,
+ const struct flash_info *info)
{
switch (nor->flash_read) {
case SPI_NOR_FAST:
case SPI_NOR_DUAL:
case SPI_NOR_QUAD:
return 8;
+ case SPI_NOR_DDR_QUAD:
+ if (JEDEC_MFR(info) == SNOR_MFR_SPANSION)
+ return 6;
case SPI_NOR_NORMAL:
return 0;
}
@@ -797,7 +802,8 @@ static const struct flash_info spi_nor_i
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
- { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ
+ | SPI_NOR_DDR_QUAD_READ) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
@@ -1186,6 +1192,23 @@ static int spansion_quad_enable(struct s
return 0;
}
+static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+{
+ int status;
+
+ switch (JEDEC_MFR(info)) {
+ case SNOR_MFR_SPANSION:
+ 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, const struct flash_info *info)
{
int status;
@@ -1375,8 +1398,15 @@ int spi_nor_scan(struct spi_nor *nor, co
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");
@@ -1389,6 +1419,14 @@ int spi_nor_scan(struct spi_nor *nor, co
/* Default commands */
switch (nor->flash_read) {
+ case SPI_NOR_DDR_QUAD:
+ if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { /* 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;
@@ -1416,6 +1454,9 @@ int spi_nor_scan(struct spi_nor *nor, co
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
/* 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;
@@ -1445,7 +1486,7 @@ int spi_nor_scan(struct spi_nor *nor, co
return -EINVAL;
}
- nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor, info);
dev_info(dev, "%s (%lld Kbytes)\n", info->name,
(long long)mtd->size >> 10);
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -30,10 +30,11 @@
/*
* Note on opcode nomenclature: some opcodes have a format like
- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
+ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number
* of I/O lines used for the opcode, address, and data (respectively). The
* FUNCTION has an optional suffix of '4', to represent an opcode which
- * requires a 4-byte (32-bit) address.
+ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
+ * DDR mode.
*/
/* Flash opcodes. */
@@ -44,6 +45,7 @@
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_4_4_D 0xed /* Read data bytes (DDR Quad SPI) */
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
@@ -59,6 +61,7 @@
#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ4_1_4_4_D 0xee /* Read data bytes (DDR Quad SPI) */
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
@@ -107,6 +110,7 @@ enum read_mode {
SPI_NOR_FAST,
SPI_NOR_DUAL,
SPI_NOR_QUAD,
+ SPI_NOR_DDR_QUAD,
};
#define SPI_NOR_MAX_CMD_SIZE 8
|