aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/socfpga/patches-4.4/0023-mtd-spi-nor-configure-the-number-of-dummy-clock-cycl.patch
blob: 7153a9f1714616c51e23cca31ea08799c9f8fd99 (plain)
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
From 16410a33d6655d6c85c8c522bc6f2cfebf7c06a4 Mon Sep 17 00:00:00 2001
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Date: Fri, 8 Jan 2016 17:02:20 +0100
Subject: [PATCH 23/33] mtd: spi-nor: configure the number of dummy clock
 cycles by manufacturer

This is a transitional patch which let us set the number of dummy clock
cycles by manufacturer.

More patches will follow by manufacturer to actually configure the
relevant number of dummy clock cycles following the dedicated procedure.

For instance, some manufacturers like Spansion configure the number of
dummy clock cycles to be used by Fast Read command through some
non-volatile register. In such a case, we should avoid updating its value
but instead read it then set the nor->read_dummy accordingly.

On the other hand, some manufacturers like Micron use some volatile
register. In this case, we'd rather update this register to use a number
of dummy clock cycles, which is a multiple of 8.
Indeed some drivers, like m25p80, only support writing bytes, hence
multiples of 8 bits.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 99 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 74 insertions(+), 25 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 8a042ab..ae3e9d8 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -139,24 +139,6 @@ static int read_cr(struct spi_nor *nor)
 }
 
 /*
- * Dummy Cycle calculation for different type of read.
- * 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)
-{
-	switch (nor->flash_read) {
-	case SPI_NOR_FAST:
-	case SPI_NOR_DUAL:
-	case SPI_NOR_QUAD:
-		return 8;
-	case SPI_NOR_NORMAL:
-		return 0;
-	}
-	return 0;
-}
-
-/*
  * Write status register 1 byte
  * Returns negative if error occurred.
  */
@@ -1217,6 +1199,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
 		 * read (performance enhance) mode by mistake!
 		 */
 		nor->read_opcode = SPINOR_OP_READ_1_4_4;
+		nor->read_dummy = 8;
 		return 0;
 	}
 
@@ -1238,6 +1221,7 @@ static int macronix_set_quad_mode(struct spi_nor *nor)
 	}
 	nor->read_proto = SNOR_PROTO_1_1_4;
 	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	nor->read_dummy = 8;
 	return 0;
 }
 
@@ -1251,12 +1235,27 @@ static int macronix_set_dual_mode(struct spi_nor *nor)
 {
 	nor->read_proto = SNOR_PROTO_1_1_2;
 	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	nor->read_dummy = 8;
 	return 0;
 }
 
 static int macronix_set_single_mode(struct spi_nor *nor)
 {
+	u8 read_dummy;
+
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+
 	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->read_dummy = read_dummy;
 	return 0;
 }
 
@@ -1277,6 +1276,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
 		 * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
 		 */
 		nor->read_opcode = SPINOR_OP_READ_FAST;
+		nor->read_dummy = 8;
 		return 0;
 	}
 
@@ -1295,6 +1295,7 @@ static int winbond_set_quad_mode(struct spi_nor *nor)
 	}
 	nor->read_proto = SNOR_PROTO_1_1_4;
 	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	nor->read_dummy = 8;
 	return 0;
 }
 
@@ -1308,12 +1309,27 @@ static int winbond_set_dual_mode(struct spi_nor *nor)
 {
 	nor->read_proto = SNOR_PROTO_1_1_2;
 	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	nor->read_dummy = 8;
 	return 0;
 }
 
 static int winbond_set_single_mode(struct spi_nor *nor)
 {
+	u8 read_dummy;
+
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+
 	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->read_dummy = read_dummy;
 	return 0;
 }
 
@@ -1405,6 +1421,7 @@ static int micron_set_quad_mode(struct spi_nor *nor)
 	if (nor->read_proto != SNOR_PROTO_4_4_4)
 		nor->read_proto = SNOR_PROTO_1_1_4;
 	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	nor->read_dummy = 8;
 	return 0;
 }
 
@@ -1434,11 +1451,14 @@ static int micron_set_dual_mode(struct spi_nor *nor)
 	if (nor->read_proto != SNOR_PROTO_2_2_2)
 		nor->read_proto = SNOR_PROTO_1_1_2;
 	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	nor->read_dummy = 8;
 	return 0;
 }
 
 static int micron_set_single_mode(struct spi_nor *nor)
 {
+	u8 read_dummy;
+
 	/* Check whether either the Dual or Quad mode is enabled. */
 	if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
 		int ret;
@@ -1455,6 +1475,18 @@ static int micron_set_single_mode(struct spi_nor *nor)
 		nor->read_proto = SNOR_PROTO_1_1_1;
 	}
 
+	/* Force the number of dummy cycles to 8 for Fast Read, 0 for Read. */
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+	nor->read_dummy = read_dummy;
 	return 0;
 }
 
@@ -1469,6 +1501,7 @@ static int spansion_set_quad_mode(struct spi_nor *nor)
 	}
 	nor->read_proto = SNOR_PROTO_1_1_4;
 	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	nor->read_dummy = 8;
 	return 0;
 }
 
@@ -1476,12 +1509,27 @@ static int spansion_set_dual_mode(struct spi_nor *nor)
 {
 	nor->read_proto = SNOR_PROTO_1_1_2;
 	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	nor->read_dummy = 8;
 	return 0;
 }
 
 static int spansion_set_single_mode(struct spi_nor *nor)
 {
+	u8 read_dummy;
+
+	switch (nor->read_opcode) {
+	case SPINOR_OP_READ:
+	case SPINOR_OP_READ4:
+		read_dummy = 0;
+		break;
+
+	default:
+		read_dummy = 8;
+		break;
+	}
+
 	nor->read_proto = SNOR_PROTO_1_1_1;
+	nor->read_dummy = read_dummy;
 	return 0;
 }
 
@@ -1696,11 +1744,14 @@ 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;
 
-	/* Default commands */
-	if (nor->flash_read == SPI_NOR_NORMAL)
+	/* Default commands and number of dummy cycles */
+	if (nor->flash_read == SPI_NOR_NORMAL) {
 		nor->read_opcode = SPINOR_OP_READ;
-	else
+		nor->read_dummy = 0;
+	} else {
 		nor->read_opcode = SPINOR_OP_READ_FAST;
+		nor->read_dummy = 8;
+	}
 
 	nor->program_opcode = SPINOR_OP_PP;
 
@@ -1715,8 +1766,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 	 *  - SNOR_PROTO_2_2_2 is either:
 	 *    + Micron Dual mode enabled
 	 *
-	 * The opcodes and the protocols are updated depending on the
-	 * manufacturer.
+	 * The opcodes, the protocols and the number of dummy cycles are updated
+	 * depending on the manufacturer.
 	 * The read opcode and protocol should be updated by the relevant
 	 * function when entering Quad or Dual mode.
 	 */
@@ -1780,8 +1831,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 		return -EINVAL;
 	}
 
-	nor->read_dummy = spi_nor_read_dummy_cycles(nor);
-
 	dev_info(dev, "%s (%lld Kbytes)\n", info->name,
 			(long long)mtd->size >> 10);
 
-- 
2.8.1