diff options
41 files changed, 2594 insertions, 1282 deletions
diff --git a/Documentation/mtd/nand_ecc.txt b/Documentation/mtd/nand_ecc.txt new file mode 100644 index 000000000000..bdf93b7f0f24 --- /dev/null +++ b/Documentation/mtd/nand_ecc.txt | |||
@@ -0,0 +1,714 @@ | |||
1 | Introduction | ||
2 | ============ | ||
3 | |||
4 | Having looked at the linux mtd/nand driver and more specific at nand_ecc.c | ||
5 | I felt there was room for optimisation. I bashed the code for a few hours | ||
6 | performing tricks like table lookup removing superfluous code etc. | ||
7 | After that the speed was increased by 35-40%. | ||
8 | Still I was not too happy as I felt there was additional room for improvement. | ||
9 | |||
10 | Bad! I was hooked. | ||
11 | I decided to annotate my steps in this file. Perhaps it is useful to someone | ||
12 | or someone learns something from it. | ||
13 | |||
14 | |||
15 | The problem | ||
16 | =========== | ||
17 | |||
18 | NAND flash (at least SLC one) typically has sectors of 256 bytes. | ||
19 | However NAND flash is not extremely reliable so some error detection | ||
20 | (and sometimes correction) is needed. | ||
21 | |||
22 | This is done by means of a Hamming code. I'll try to explain it in | ||
23 | laymans terms (and apologies to all the pro's in the field in case I do | ||
24 | not use the right terminology, my coding theory class was almost 30 | ||
25 | years ago, and I must admit it was not one of my favourites). | ||
26 | |||
27 | As I said before the ecc calculation is performed on sectors of 256 | ||
28 | bytes. This is done by calculating several parity bits over the rows and | ||
29 | columns. The parity used is even parity which means that the parity bit = 1 | ||
30 | if the data over which the parity is calculated is 1 and the parity bit = 0 | ||
31 | if the data over which the parity is calculated is 0. So the total | ||
32 | number of bits over the data over which the parity is calculated + the | ||
33 | parity bit is even. (see wikipedia if you can't follow this). | ||
34 | Parity is often calculated by means of an exclusive or operation, | ||
35 | sometimes also referred to as xor. In C the operator for xor is ^ | ||
36 | |||
37 | Back to ecc. | ||
38 | Let's give a small figure: | ||
39 | |||
40 | byte 0: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp2 rp4 ... rp14 | ||
41 | byte 1: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp2 rp4 ... rp14 | ||
42 | byte 2: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp3 rp4 ... rp14 | ||
43 | byte 3: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp3 rp4 ... rp14 | ||
44 | byte 4: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp2 rp5 ... rp14 | ||
45 | .... | ||
46 | byte 254: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp0 rp3 rp5 ... rp15 | ||
47 | byte 255: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 rp1 rp3 rp5 ... rp15 | ||
48 | cp1 cp0 cp1 cp0 cp1 cp0 cp1 cp0 | ||
49 | cp3 cp3 cp2 cp2 cp3 cp3 cp2 cp2 | ||
50 | cp5 cp5 cp5 cp5 cp4 cp4 cp4 cp4 | ||
51 | |||
52 | This figure represents a sector of 256 bytes. | ||
53 | cp is my abbreviaton for column parity, rp for row parity. | ||
54 | |||
55 | Let's start to explain column parity. | ||
56 | cp0 is the parity that belongs to all bit0, bit2, bit4, bit6. | ||
57 | so the sum of all bit0, bit2, bit4 and bit6 values + cp0 itself is even. | ||
58 | Similarly cp1 is the sum of all bit1, bit3, bit5 and bit7. | ||
59 | cp2 is the parity over bit0, bit1, bit4 and bit5 | ||
60 | cp3 is the parity over bit2, bit3, bit6 and bit7. | ||
61 | cp4 is the parity over bit0, bit1, bit2 and bit3. | ||
62 | cp5 is the parity over bit4, bit5, bit6 and bit7. | ||
63 | Note that each of cp0 .. cp5 is exactly one bit. | ||
64 | |||
65 | Row parity actually works almost the same. | ||
66 | rp0 is the parity of all even bytes (0, 2, 4, 6, ... 252, 254) | ||
67 | rp1 is the parity of all odd bytes (1, 3, 5, 7, ..., 253, 255) | ||
68 | rp2 is the parity of all bytes 0, 1, 4, 5, 8, 9, ... | ||
69 | (so handle two bytes, then skip 2 bytes). | ||
70 | rp3 is covers the half rp2 does not cover (bytes 2, 3, 6, 7, 10, 11, ...) | ||
71 | for rp4 the rule is cover 4 bytes, skip 4 bytes, cover 4 bytes, skip 4 etc. | ||
72 | so rp4 calculates parity over bytes 0, 1, 2, 3, 8, 9, 10, 11, 16, ...) | ||
73 | and rp5 covers the other half, so bytes 4, 5, 6, 7, 12, 13, 14, 15, 20, .. | ||
74 | The story now becomes quite boring. I guess you get the idea. | ||
75 | rp6 covers 8 bytes then skips 8 etc | ||
76 | rp7 skips 8 bytes then covers 8 etc | ||
77 | rp8 covers 16 bytes then skips 16 etc | ||
78 | rp9 skips 16 bytes then covers 16 etc | ||
79 | rp10 covers 32 bytes then skips 32 etc | ||
80 | rp11 skips 32 bytes then covers 32 etc | ||
81 | rp12 covers 64 bytes then skips 64 etc | ||
82 | rp13 skips 64 bytes then covers 64 etc | ||
83 | rp14 covers 128 bytes then skips 128 | ||
84 | rp15 skips 128 bytes then covers 128 | ||
85 | |||
86 | In the end the parity bits are grouped together in three bytes as | ||
87 | follows: | ||
88 | ECC Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 | ||
89 | ECC 0 rp07 rp06 rp05 rp04 rp03 rp02 rp01 rp00 | ||
90 | ECC 1 rp15 rp14 rp13 rp12 rp11 rp10 rp09 rp08 | ||
91 | ECC 2 cp5 cp4 cp3 cp2 cp1 cp0 1 1 | ||
92 | |||
93 | I detected after writing this that ST application note AN1823 | ||
94 | (http://www.st.com/stonline/books/pdf/docs/10123.pdf) gives a much | ||
95 | nicer picture.(but they use line parity as term where I use row parity) | ||
96 | Oh well, I'm graphically challenged, so suffer with me for a moment :-) | ||
97 | And I could not reuse the ST picture anyway for copyright reasons. | ||
98 | |||
99 | |||
100 | Attempt 0 | ||
101 | ========= | ||
102 | |||
103 | Implementing the parity calculation is pretty simple. | ||
104 | In C pseudocode: | ||
105 | for (i = 0; i < 256; i++) | ||
106 | { | ||
107 | if (i & 0x01) | ||
108 | rp1 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1; | ||
109 | else | ||
110 | rp0 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp1; | ||
111 | if (i & 0x02) | ||
112 | rp3 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp3; | ||
113 | else | ||
114 | rp2 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp2; | ||
115 | if (i & 0x04) | ||
116 | rp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp5; | ||
117 | else | ||
118 | rp4 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp4; | ||
119 | if (i & 0x08) | ||
120 | rp7 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp7; | ||
121 | else | ||
122 | rp6 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp6; | ||
123 | if (i & 0x10) | ||
124 | rp9 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp9; | ||
125 | else | ||
126 | rp8 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp8; | ||
127 | if (i & 0x20) | ||
128 | rp11 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp11; | ||
129 | else | ||
130 | rp10 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp10; | ||
131 | if (i & 0x40) | ||
132 | rp13 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp13; | ||
133 | else | ||
134 | rp12 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp12; | ||
135 | if (i & 0x80) | ||
136 | rp15 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp15; | ||
137 | else | ||
138 | rp14 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ bit3 ^ bit2 ^ bit1 ^ bit0 ^ rp14; | ||
139 | cp0 = bit6 ^ bit4 ^ bit2 ^ bit0 ^ cp0; | ||
140 | cp1 = bit7 ^ bit5 ^ bit3 ^ bit1 ^ cp1; | ||
141 | cp2 = bit5 ^ bit4 ^ bit1 ^ bit0 ^ cp2; | ||
142 | cp3 = bit7 ^ bit6 ^ bit3 ^ bit2 ^ cp3 | ||
143 | cp4 = bit3 ^ bit2 ^ bit1 ^ bit0 ^ cp4 | ||
144 | cp5 = bit7 ^ bit6 ^ bit5 ^ bit4 ^ cp5 | ||
145 | } | ||
146 | |||
147 | |||
148 | Analysis 0 | ||
149 | ========== | ||
150 | |||
151 | C does have bitwise operators but not really operators to do the above | ||
152 | efficiently (and most hardware has no such instructions either). | ||
153 | Therefore without implementing this it was clear that the code above was | ||
154 | not going to bring me a Nobel prize :-) | ||
155 | |||
156 | Fortunately the exclusive or operation is commutative, so we can combine | ||
157 | the values in any order. So instead of calculating all the bits | ||
158 | individually, let us try to rearrange things. | ||
159 | For the column parity this is easy. We can just xor the bytes and in the | ||
160 | end filter out the relevant bits. This is pretty nice as it will bring | ||
161 | all cp calculation out of the if loop. | ||
162 | |||
163 | Similarly we can first xor the bytes for the various rows. | ||
164 | This leads to: | ||
165 | |||
166 | |||
167 | Attempt 1 | ||
168 | ========= | ||
169 | |||
170 | const char parity[256] = { | ||
171 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
172 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
173 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
174 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
175 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
176 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
177 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
178 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
179 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
180 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
181 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
182 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
183 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
184 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
185 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
186 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 | ||
187 | }; | ||
188 | |||
189 | void ecc1(const unsigned char *buf, unsigned char *code) | ||
190 | { | ||
191 | int i; | ||
192 | const unsigned char *bp = buf; | ||
193 | unsigned char cur; | ||
194 | unsigned char rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; | ||
195 | unsigned char rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15; | ||
196 | unsigned char par; | ||
197 | |||
198 | par = 0; | ||
199 | rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0; | ||
200 | rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0; | ||
201 | rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0; | ||
202 | rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0; | ||
203 | |||
204 | for (i = 0; i < 256; i++) | ||
205 | { | ||
206 | cur = *bp++; | ||
207 | par ^= cur; | ||
208 | if (i & 0x01) rp1 ^= cur; else rp0 ^= cur; | ||
209 | if (i & 0x02) rp3 ^= cur; else rp2 ^= cur; | ||
210 | if (i & 0x04) rp5 ^= cur; else rp4 ^= cur; | ||
211 | if (i & 0x08) rp7 ^= cur; else rp6 ^= cur; | ||
212 | if (i & 0x10) rp9 ^= cur; else rp8 ^= cur; | ||
213 | if (i & 0x20) rp11 ^= cur; else rp10 ^= cur; | ||
214 | if (i & 0x40) rp13 ^= cur; else rp12 ^= cur; | ||
215 | if (i & 0x80) rp15 ^= cur; else rp14 ^= cur; | ||
216 | } | ||
217 | code[0] = | ||
218 | (parity[rp7] << 7) | | ||
219 | (parity[rp6] << 6) | | ||
220 | (parity[rp5] << 5) | | ||
221 | (parity[rp4] << 4) | | ||
222 | (parity[rp3] << 3) | | ||
223 | (parity[rp2] << 2) | | ||
224 | (parity[rp1] << 1) | | ||
225 | (parity[rp0]); | ||
226 | code[1] = | ||
227 | (parity[rp15] << 7) | | ||
228 | (parity[rp14] << 6) | | ||
229 | (parity[rp13] << 5) | | ||
230 | (parity[rp12] << 4) | | ||
231 | (parity[rp11] << 3) | | ||
232 | (parity[rp10] << 2) | | ||
233 | (parity[rp9] << 1) | | ||
234 | (parity[rp8]); | ||
235 | code[2] = | ||
236 | (parity[par & 0xf0] << 7) | | ||
237 | (parity[par & 0x0f] << 6) | | ||
238 | (parity[par & 0xcc] << 5) | | ||
239 | (parity[par & 0x33] << 4) | | ||
240 | (parity[par & 0xaa] << 3) | | ||
241 | (parity[par & 0x55] << 2); | ||
242 | code[0] = ~code[0]; | ||
243 | code[1] = ~code[1]; | ||
244 | code[2] = ~code[2]; | ||
245 | } | ||
246 | |||
247 | Still pretty straightforward. The last three invert statements are there to | ||
248 | give a checksum of 0xff 0xff 0xff for an empty flash. In an empty flash | ||
249 | all data is 0xff, so the checksum then matches. | ||
250 | |||
251 | I also introduced the parity lookup. I expected this to be the fastest | ||
252 | way to calculate the parity, but I will investigate alternatives later | ||
253 | on. | ||
254 | |||
255 | |||
256 | Analysis 1 | ||
257 | ========== | ||
258 | |||
259 | The code works, but is not terribly efficient. On my system it took | ||
260 | almost 4 times as much time as the linux driver code. But hey, if it was | ||
261 | *that* easy this would have been done long before. | ||
262 | No pain. no gain. | ||
263 | |||
264 | Fortunately there is plenty of room for improvement. | ||
265 | |||
266 | In step 1 we moved from bit-wise calculation to byte-wise calculation. | ||
267 | However in C we can also use the unsigned long data type and virtually | ||
268 | every modern microprocessor supports 32 bit operations, so why not try | ||
269 | to write our code in such a way that we process data in 32 bit chunks. | ||
270 | |||
271 | Of course this means some modification as the row parity is byte by | ||
272 | byte. A quick analysis: | ||
273 | for the column parity we use the par variable. When extending to 32 bits | ||
274 | we can in the end easily calculate p0 and p1 from it. | ||
275 | (because par now consists of 4 bytes, contributing to rp1, rp0, rp1, rp0 | ||
276 | respectively) | ||
277 | also rp2 and rp3 can be easily retrieved from par as rp3 covers the | ||
278 | first two bytes and rp2 the last two bytes. | ||
279 | |||
280 | Note that of course now the loop is executed only 64 times (256/4). | ||
281 | And note that care must taken wrt byte ordering. The way bytes are | ||
282 | ordered in a long is machine dependent, and might affect us. | ||
283 | Anyway, if there is an issue: this code is developed on x86 (to be | ||
284 | precise: a DELL PC with a D920 Intel CPU) | ||
285 | |||
286 | And of course the performance might depend on alignment, but I expect | ||
287 | that the I/O buffers in the nand driver are aligned properly (and | ||
288 | otherwise that should be fixed to get maximum performance). | ||
289 | |||
290 | Let's give it a try... | ||
291 | |||
292 | |||
293 | Attempt 2 | ||
294 | ========= | ||
295 | |||
296 | extern const char parity[256]; | ||
297 | |||
298 | void ecc2(const unsigned char *buf, unsigned char *code) | ||
299 | { | ||
300 | int i; | ||
301 | const unsigned long *bp = (unsigned long *)buf; | ||
302 | unsigned long cur; | ||
303 | unsigned long rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; | ||
304 | unsigned long rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15; | ||
305 | unsigned long par; | ||
306 | |||
307 | par = 0; | ||
308 | rp0 = 0; rp1 = 0; rp2 = 0; rp3 = 0; | ||
309 | rp4 = 0; rp5 = 0; rp6 = 0; rp7 = 0; | ||
310 | rp8 = 0; rp9 = 0; rp10 = 0; rp11 = 0; | ||
311 | rp12 = 0; rp13 = 0; rp14 = 0; rp15 = 0; | ||
312 | |||
313 | for (i = 0; i < 64; i++) | ||
314 | { | ||
315 | cur = *bp++; | ||
316 | par ^= cur; | ||
317 | if (i & 0x01) rp5 ^= cur; else rp4 ^= cur; | ||
318 | if (i & 0x02) rp7 ^= cur; else rp6 ^= cur; | ||
319 | if (i & 0x04) rp9 ^= cur; else rp8 ^= cur; | ||
320 | if (i & 0x08) rp11 ^= cur; else rp10 ^= cur; | ||
321 | if (i & 0x10) rp13 ^= cur; else rp12 ^= cur; | ||
322 | if (i & 0x20) rp15 ^= cur; else rp14 ^= cur; | ||
323 | } | ||
324 | /* | ||
325 | we need to adapt the code generation for the fact that rp vars are now | ||
326 | long; also the column parity calculation needs to be changed. | ||
327 | we'll bring rp4 to 15 back to single byte entities by shifting and | ||
328 | xoring | ||
329 | */ | ||
330 | rp4 ^= (rp4 >> 16); rp4 ^= (rp4 >> 8); rp4 &= 0xff; | ||
331 | rp5 ^= (rp5 >> 16); rp5 ^= (rp5 >> 8); rp5 &= 0xff; | ||
332 | rp6 ^= (rp6 >> 16); rp6 ^= (rp6 >> 8); rp6 &= 0xff; | ||
333 | rp7 ^= (rp7 >> 16); rp7 ^= (rp7 >> 8); rp7 &= 0xff; | ||
334 | rp8 ^= (rp8 >> 16); rp8 ^= (rp8 >> 8); rp8 &= 0xff; | ||
335 | rp9 ^= (rp9 >> 16); rp9 ^= (rp9 >> 8); rp9 &= 0xff; | ||
336 | rp10 ^= (rp10 >> 16); rp10 ^= (rp10 >> 8); rp10 &= 0xff; | ||
337 | rp11 ^= (rp11 >> 16); rp11 ^= (rp11 >> 8); rp11 &= 0xff; | ||
338 | rp12 ^= (rp12 >> 16); rp12 ^= (rp12 >> 8); rp12 &= 0xff; | ||
339 | rp13 ^= (rp13 >> 16); rp13 ^= (rp13 >> 8); rp13 &= 0xff; | ||
340 | rp14 ^= (rp14 >> 16); rp14 ^= (rp14 >> 8); rp14 &= 0xff; | ||
341 | rp15 ^= (rp15 >> 16); rp15 ^= (rp15 >> 8); rp15 &= 0xff; | ||
342 | rp3 = (par >> 16); rp3 ^= (rp3 >> 8); rp3 &= 0xff; | ||
343 | rp2 = par & 0xffff; rp2 ^= (rp2 >> 8); rp2 &= 0xff; | ||
344 | par ^= (par >> 16); | ||
345 | rp1 = (par >> 8); rp1 &= 0xff; | ||
346 | rp0 = (par & 0xff); | ||
347 | par ^= (par >> 8); par &= 0xff; | ||
348 | |||
349 | code[0] = | ||
350 | (parity[rp7] << 7) | | ||
351 | (parity[rp6] << 6) | | ||
352 | (parity[rp5] << 5) | | ||
353 | (parity[rp4] << 4) | | ||
354 | (parity[rp3] << 3) | | ||
355 | (parity[rp2] << 2) | | ||
356 | (parity[rp1] << 1) | | ||
357 | (parity[rp0]); | ||
358 | code[1] = | ||
359 | (parity[rp15] << 7) | | ||
360 | (parity[rp14] << 6) | | ||
361 | (parity[rp13] << 5) | | ||
362 | (parity[rp12] << 4) | | ||
363 | (parity[rp11] << 3) | | ||
364 | (parity[rp10] << 2) | | ||
365 | (parity[rp9] << 1) | | ||
366 | (parity[rp8]); | ||
367 | code[2] = | ||
368 | (parity[par & 0xf0] << 7) | | ||
369 | (parity[par & 0x0f] << 6) | | ||
370 | (parity[par & 0xcc] << 5) | | ||
371 | (parity[par & 0x33] << 4) | | ||
372 | (parity[par & 0xaa] << 3) | | ||
373 | (parity[par & 0x55] << 2); | ||
374 | code[0] = ~code[0]; | ||
375 | code[1] = ~code[1]; | ||
376 | code[2] = ~code[2]; | ||
377 | } | ||
378 | |||
379 | The parity array is not shown any more. Note also that for these | ||
380 | examples I kinda deviated from my regular programming style by allowing | ||
381 | multiple statements on a line, not using { } in then and else blocks | ||
382 | with only a single statement and by using operators like ^= | ||
383 | |||
384 | |||
385 | Analysis 2 | ||
386 | ========== | ||
387 | |||
388 | The code (of course) works, and hurray: we are a little bit faster than | ||
389 | the linux driver code (about 15%). But wait, don't cheer too quickly. | ||
390 | THere is more to be gained. | ||
391 | If we look at e.g. rp14 and rp15 we see that we either xor our data with | ||
392 | rp14 or with rp15. However we also have par which goes over all data. | ||
393 | This means there is no need to calculate rp14 as it can be calculated from | ||
394 | rp15 through rp14 = par ^ rp15; | ||
395 | (or if desired we can avoid calculating rp15 and calculate it from | ||
396 | rp14). That is why some places refer to inverse parity. | ||
397 | Of course the same thing holds for rp4/5, rp6/7, rp8/9, rp10/11 and rp12/13. | ||
398 | Effectively this means we can eliminate the else clause from the if | ||
399 | statements. Also we can optimise the calculation in the end a little bit | ||
400 | by going from long to byte first. Actually we can even avoid the table | ||
401 | lookups | ||
402 | |||
403 | Attempt 3 | ||
404 | ========= | ||
405 | |||
406 | Odd replaced: | ||
407 | if (i & 0x01) rp5 ^= cur; else rp4 ^= cur; | ||
408 | if (i & 0x02) rp7 ^= cur; else rp6 ^= cur; | ||
409 | if (i & 0x04) rp9 ^= cur; else rp8 ^= cur; | ||
410 | if (i & 0x08) rp11 ^= cur; else rp10 ^= cur; | ||
411 | if (i & 0x10) rp13 ^= cur; else rp12 ^= cur; | ||
412 | if (i & 0x20) rp15 ^= cur; else rp14 ^= cur; | ||
413 | with | ||
414 | if (i & 0x01) rp5 ^= cur; | ||
415 | if (i & 0x02) rp7 ^= cur; | ||
416 | if (i & 0x04) rp9 ^= cur; | ||
417 | if (i & 0x08) rp11 ^= cur; | ||
418 | if (i & 0x10) rp13 ^= cur; | ||
419 | if (i & 0x20) rp15 ^= cur; | ||
420 | |||
421 | and outside the loop added: | ||
422 | rp4 = par ^ rp5; | ||
423 | rp6 = par ^ rp7; | ||
424 | rp8 = par ^ rp9; | ||
425 | rp10 = par ^ rp11; | ||
426 | rp12 = par ^ rp13; | ||
427 | rp14 = par ^ rp15; | ||
428 | |||
429 | And after that the code takes about 30% more time, although the number of | ||
430 | statements is reduced. This is also reflected in the assembly code. | ||
431 | |||
432 | |||
433 | Analysis 3 | ||
434 | ========== | ||
435 | |||
436 | Very weird. Guess it has to do with caching or instruction parallellism | ||
437 | or so. I also tried on an eeePC (Celeron, clocked at 900 Mhz). Interesting | ||
438 | observation was that this one is only 30% slower (according to time) | ||
439 | executing the code as my 3Ghz D920 processor. | ||
440 | |||
441 | Well, it was expected not to be easy so maybe instead move to a | ||
442 | different track: let's move back to the code from attempt2 and do some | ||
443 | loop unrolling. This will eliminate a few if statements. I'll try | ||
444 | different amounts of unrolling to see what works best. | ||
445 | |||
446 | |||
447 | Attempt 4 | ||
448 | ========= | ||
449 | |||
450 | Unrolled the loop 1, 2, 3 and 4 times. | ||
451 | For 4 the code starts with: | ||
452 | |||
453 | for (i = 0; i < 4; i++) | ||
454 | { | ||
455 | cur = *bp++; | ||
456 | par ^= cur; | ||
457 | rp4 ^= cur; | ||
458 | rp6 ^= cur; | ||
459 | rp8 ^= cur; | ||
460 | rp10 ^= cur; | ||
461 | if (i & 0x1) rp13 ^= cur; else rp12 ^= cur; | ||
462 | if (i & 0x2) rp15 ^= cur; else rp14 ^= cur; | ||
463 | cur = *bp++; | ||
464 | par ^= cur; | ||
465 | rp5 ^= cur; | ||
466 | rp6 ^= cur; | ||
467 | ... | ||
468 | |||
469 | |||
470 | Analysis 4 | ||
471 | ========== | ||
472 | |||
473 | Unrolling once gains about 15% | ||
474 | Unrolling twice keeps the gain at about 15% | ||
475 | Unrolling three times gives a gain of 30% compared to attempt 2. | ||
476 | Unrolling four times gives a marginal improvement compared to unrolling | ||
477 | three times. | ||
478 | |||
479 | I decided to proceed with a four time unrolled loop anyway. It was my gut | ||
480 | feeling that in the next steps I would obtain additional gain from it. | ||
481 | |||
482 | The next step was triggered by the fact that par contains the xor of all | ||
483 | bytes and rp4 and rp5 each contain the xor of half of the bytes. | ||
484 | So in effect par = rp4 ^ rp5. But as xor is commutative we can also say | ||
485 | that rp5 = par ^ rp4. So no need to keep both rp4 and rp5 around. We can | ||
486 | eliminate rp5 (or rp4, but I already foresaw another optimisation). | ||
487 | The same holds for rp6/7, rp8/9, rp10/11 rp12/13 and rp14/15. | ||
488 | |||
489 | |||
490 | Attempt 5 | ||
491 | ========= | ||
492 | |||
493 | Effectively so all odd digit rp assignments in the loop were removed. | ||
494 | This included the else clause of the if statements. | ||
495 | Of course after the loop we need to correct things by adding code like: | ||
496 | rp5 = par ^ rp4; | ||
497 | Also the initial assignments (rp5 = 0; etc) could be removed. | ||
498 | Along the line I also removed the initialisation of rp0/1/2/3. | ||
499 | |||
500 | |||
501 | Analysis 5 | ||
502 | ========== | ||
503 | |||
504 | Measurements showed this was a good move. The run-time roughly halved | ||
505 | compared with attempt 4 with 4 times unrolled, and we only require 1/3rd | ||
506 | of the processor time compared to the current code in the linux kernel. | ||
507 | |||
508 | However, still I thought there was more. I didn't like all the if | ||
509 | statements. Why not keep a running parity and only keep the last if | ||
510 | statement. Time for yet another version! | ||
511 | |||
512 | |||
513 | Attempt 6 | ||
514 | ========= | ||
515 | |||
516 | THe code within the for loop was changed to: | ||
517 | |||
518 | for (i = 0; i < 4; i++) | ||
519 | { | ||
520 | cur = *bp++; tmppar = cur; rp4 ^= cur; | ||
521 | cur = *bp++; tmppar ^= cur; rp6 ^= tmppar; | ||
522 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
523 | cur = *bp++; tmppar ^= cur; rp8 ^= tmppar; | ||
524 | |||
525 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; | ||
526 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; | ||
527 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
528 | cur = *bp++; tmppar ^= cur; rp10 ^= tmppar; | ||
529 | |||
530 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; rp8 ^= cur; | ||
531 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; rp8 ^= cur; | ||
532 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp8 ^= cur; | ||
533 | cur = *bp++; tmppar ^= cur; rp8 ^= cur; | ||
534 | |||
535 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; rp6 ^= cur; | ||
536 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; | ||
537 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
538 | cur = *bp++; tmppar ^= cur; | ||
539 | |||
540 | par ^= tmppar; | ||
541 | if ((i & 0x1) == 0) rp12 ^= tmppar; | ||
542 | if ((i & 0x2) == 0) rp14 ^= tmppar; | ||
543 | } | ||
544 | |||
545 | As you can see tmppar is used to accumulate the parity within a for | ||
546 | iteration. In the last 3 statements is is added to par and, if needed, | ||
547 | to rp12 and rp14. | ||
548 | |||
549 | While making the changes I also found that I could exploit that tmppar | ||
550 | contains the running parity for this iteration. So instead of having: | ||
551 | rp4 ^= cur; rp6 = cur; | ||
552 | I removed the rp6 = cur; statement and did rp6 ^= tmppar; on next | ||
553 | statement. A similar change was done for rp8 and rp10 | ||
554 | |||
555 | |||
556 | Analysis 6 | ||
557 | ========== | ||
558 | |||
559 | Measuring this code again showed big gain. When executing the original | ||
560 | linux code 1 million times, this took about 1 second on my system. | ||
561 | (using time to measure the performance). After this iteration I was back | ||
562 | to 0.075 sec. Actually I had to decide to start measuring over 10 | ||
563 | million interations in order not to loose too much accuracy. This one | ||
564 | definitely seemed to be the jackpot! | ||
565 | |||
566 | There is a little bit more room for improvement though. There are three | ||
567 | places with statements: | ||
568 | rp4 ^= cur; rp6 ^= cur; | ||
569 | It seems more efficient to also maintain a variable rp4_6 in the while | ||
570 | loop; This eliminates 3 statements per loop. Of course after the loop we | ||
571 | need to correct by adding: | ||
572 | rp4 ^= rp4_6; | ||
573 | rp6 ^= rp4_6 | ||
574 | Furthermore there are 4 sequential assingments to rp8. This can be | ||
575 | encoded slightly more efficient by saving tmppar before those 4 lines | ||
576 | and later do rp8 = rp8 ^ tmppar ^ notrp8; | ||
577 | (where notrp8 is the value of rp8 before those 4 lines). | ||
578 | Again a use of the commutative property of xor. | ||
579 | Time for a new test! | ||
580 | |||
581 | |||
582 | Attempt 7 | ||
583 | ========= | ||
584 | |||
585 | The new code now looks like: | ||
586 | |||
587 | for (i = 0; i < 4; i++) | ||
588 | { | ||
589 | cur = *bp++; tmppar = cur; rp4 ^= cur; | ||
590 | cur = *bp++; tmppar ^= cur; rp6 ^= tmppar; | ||
591 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
592 | cur = *bp++; tmppar ^= cur; rp8 ^= tmppar; | ||
593 | |||
594 | cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; | ||
595 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; | ||
596 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
597 | cur = *bp++; tmppar ^= cur; rp10 ^= tmppar; | ||
598 | |||
599 | notrp8 = tmppar; | ||
600 | cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; | ||
601 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; | ||
602 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
603 | cur = *bp++; tmppar ^= cur; | ||
604 | rp8 = rp8 ^ tmppar ^ notrp8; | ||
605 | |||
606 | cur = *bp++; tmppar ^= cur; rp4_6 ^= cur; | ||
607 | cur = *bp++; tmppar ^= cur; rp6 ^= cur; | ||
608 | cur = *bp++; tmppar ^= cur; rp4 ^= cur; | ||
609 | cur = *bp++; tmppar ^= cur; | ||
610 | |||
611 | par ^= tmppar; | ||
612 | if ((i & 0x1) == 0) rp12 ^= tmppar; | ||
613 | if ((i & 0x2) == 0) rp14 ^= tmppar; | ||
614 | } | ||
615 | rp4 ^= rp4_6; | ||
616 | rp6 ^= rp4_6; | ||
617 | |||
618 | |||
619 | Not a big change, but every penny counts :-) | ||
620 | |||
621 | |||
622 | Analysis 7 | ||
623 | ========== | ||
624 | |||
625 | Acutally this made things worse. Not very much, but I don't want to move | ||
626 | into the wrong direction. Maybe something to investigate later. Could | ||
627 | have to do with caching again. | ||
628 | |||
629 | Guess that is what there is to win within the loop. Maybe unrolling one | ||
630 | more time will help. I'll keep the optimisations from 7 for now. | ||
631 | |||
632 | |||
633 | Attempt 8 | ||
634 | ========= | ||
635 | |||
636 | Unrolled the loop one more time. | ||
637 | |||
638 | |||
639 | Analysis 8 | ||
640 | ========== | ||
641 | |||
642 | This makes things worse. Let's stick with attempt 6 and continue from there. | ||
643 | Although it seems that the code within the loop cannot be optimised | ||
644 | further there is still room to optimize the generation of the ecc codes. | ||
645 | We can simply calcualate the total parity. If this is 0 then rp4 = rp5 | ||
646 | etc. If the parity is 1, then rp4 = !rp5; | ||
647 | But if rp4 = rp5 we do not need rp5 etc. We can just write the even bits | ||
648 | in the result byte and then do something like | ||
649 | code[0] |= (code[0] << 1); | ||
650 | Lets test this. | ||
651 | |||
652 | |||
653 | Attempt 9 | ||
654 | ========= | ||
655 | |||
656 | Changed the code but again this slightly degrades performance. Tried all | ||
657 | kind of other things, like having dedicated parity arrays to avoid the | ||
658 | shift after parity[rp7] << 7; No gain. | ||
659 | Change the lookup using the parity array by using shift operators (e.g. | ||
660 | replace parity[rp7] << 7 with: | ||
661 | rp7 ^= (rp7 << 4); | ||
662 | rp7 ^= (rp7 << 2); | ||
663 | rp7 ^= (rp7 << 1); | ||
664 | rp7 &= 0x80; | ||
665 | No gain. | ||
666 | |||
667 | The only marginal change was inverting the parity bits, so we can remove | ||
668 | the last three invert statements. | ||
669 | |||
670 | Ah well, pity this does not deliver more. Then again 10 million | ||
671 | iterations using the linux driver code takes between 13 and 13.5 | ||
672 | seconds, whereas my code now takes about 0.73 seconds for those 10 | ||
673 | million iterations. So basically I've improved the performance by a | ||
674 | factor 18 on my system. Not that bad. Of course on different hardware | ||
675 | you will get different results. No warranties! | ||
676 | |||
677 | But of course there is no such thing as a free lunch. The codesize almost | ||
678 | tripled (from 562 bytes to 1434 bytes). Then again, it is not that much. | ||
679 | |||
680 | |||
681 | Correcting errors | ||
682 | ================= | ||
683 | |||
684 | For correcting errors I again used the ST application note as a starter, | ||
685 | but I also peeked at the existing code. | ||
686 | The algorithm itself is pretty straightforward. Just xor the given and | ||
687 | the calculated ecc. If all bytes are 0 there is no problem. If 11 bits | ||
688 | are 1 we have one correctable bit error. If there is 1 bit 1, we have an | ||
689 | error in the given ecc code. | ||
690 | It proved to be fastest to do some table lookups. Performance gain | ||
691 | introduced by this is about a factor 2 on my system when a repair had to | ||
692 | be done, and 1% or so if no repair had to be done. | ||
693 | Code size increased from 330 bytes to 686 bytes for this function. | ||
694 | (gcc 4.2, -O3) | ||
695 | |||
696 | |||
697 | Conclusion | ||
698 | ========== | ||
699 | |||
700 | The gain when calculating the ecc is tremendous. Om my development hardware | ||
701 | a speedup of a factor of 18 for ecc calculation was achieved. On a test on an | ||
702 | embedded system with a MIPS core a factor 7 was obtained. | ||
703 | On a test with a Linksys NSLU2 (ARMv5TE processor) the speedup was a factor | ||
704 | 5 (big endian mode, gcc 4.1.2, -O3) | ||
705 | For correction not much gain could be obtained (as bitflips are rare). Then | ||
706 | again there are also much less cycles spent there. | ||
707 | |||
708 | It seems there is not much more gain possible in this, at least when | ||
709 | programmed in C. Of course it might be possible to squeeze something more | ||
710 | out of it with an assembler program, but due to pipeline behaviour etc | ||
711 | this is very tricky (at least for intel hw). | ||
712 | |||
713 | Author: Frans Meulenbroeks | ||
714 | Copyright (C) 2008 Koninklijke Philips Electronics NV. | ||
diff --git a/arch/arm/plat-omap/include/mach/onenand.h b/arch/arm/plat-omap/include/mach/onenand.h index d57f20226b28..4649d302c263 100644 --- a/arch/arm/plat-omap/include/mach/onenand.h +++ b/arch/arm/plat-omap/include/mach/onenand.h | |||
@@ -16,6 +16,10 @@ struct omap_onenand_platform_data { | |||
16 | int gpio_irq; | 16 | int gpio_irq; |
17 | struct mtd_partition *parts; | 17 | struct mtd_partition *parts; |
18 | int nr_parts; | 18 | int nr_parts; |
19 | int (*onenand_setup)(void __iomem *); | 19 | int (*onenand_setup)(void __iomem *, int freq); |
20 | int dma_channel; | 20 | int dma_channel; |
21 | }; | 21 | }; |
22 | |||
23 | int omap2_onenand_rephase(void); | ||
24 | |||
25 | #define ONENAND_MAX_PARTITIONS 8 | ||
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 14f11f8b9e5f..a90d50c2c3e5 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -172,6 +172,11 @@ config MTD_CHAR | |||
172 | memory chips, and also use ioctl() to obtain information about | 172 | memory chips, and also use ioctl() to obtain information about |
173 | the device, or to erase parts of it. | 173 | the device, or to erase parts of it. |
174 | 174 | ||
175 | config HAVE_MTD_OTP | ||
176 | bool | ||
177 | help | ||
178 | Enable access to OTP regions using MTD_CHAR. | ||
179 | |||
175 | config MTD_BLKDEVS | 180 | config MTD_BLKDEVS |
176 | tristate "Common interface to block layer for MTD 'translation layers'" | 181 | tristate "Common interface to block layer for MTD 'translation layers'" |
177 | depends on BLOCK | 182 | depends on BLOCK |
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 479d32b57a1e..9401bfec4623 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig | |||
@@ -154,6 +154,7 @@ config MTD_CFI_I8 | |||
154 | config MTD_OTP | 154 | config MTD_OTP |
155 | bool "Protection Registers aka one-time programmable (OTP) bits" | 155 | bool "Protection Registers aka one-time programmable (OTP) bits" |
156 | depends on MTD_CFI_ADV_OPTIONS | 156 | depends on MTD_CFI_ADV_OPTIONS |
157 | select HAVE_MTD_OTP | ||
157 | default n | 158 | default n |
158 | help | 159 | help |
159 | This enables support for reading, writing and locking so called | 160 | This enables support for reading, writing and locking so called |
@@ -187,7 +188,7 @@ config MTD_CFI_INTELEXT | |||
187 | StrataFlash and other parts. | 188 | StrataFlash and other parts. |
188 | 189 | ||
189 | config MTD_CFI_AMDSTD | 190 | config MTD_CFI_AMDSTD |
190 | tristate "Support for AMD/Fujitsu flash chips" | 191 | tristate "Support for AMD/Fujitsu/Spansion flash chips" |
191 | depends on MTD_GEN_PROBE | 192 | depends on MTD_GEN_PROBE |
192 | select MTD_CFI_UTIL | 193 | select MTD_CFI_UTIL |
193 | help | 194 | help |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5f1b472137a0..5157e3cb4b9e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -478,6 +478,28 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) | |||
478 | else | 478 | else |
479 | cfi->chips[i].erase_time = 2000000; | 479 | cfi->chips[i].erase_time = 2000000; |
480 | 480 | ||
481 | if (cfi->cfiq->WordWriteTimeoutTyp && | ||
482 | cfi->cfiq->WordWriteTimeoutMax) | ||
483 | cfi->chips[i].word_write_time_max = | ||
484 | 1<<(cfi->cfiq->WordWriteTimeoutTyp + | ||
485 | cfi->cfiq->WordWriteTimeoutMax); | ||
486 | else | ||
487 | cfi->chips[i].word_write_time_max = 50000 * 8; | ||
488 | |||
489 | if (cfi->cfiq->BufWriteTimeoutTyp && | ||
490 | cfi->cfiq->BufWriteTimeoutMax) | ||
491 | cfi->chips[i].buffer_write_time_max = | ||
492 | 1<<(cfi->cfiq->BufWriteTimeoutTyp + | ||
493 | cfi->cfiq->BufWriteTimeoutMax); | ||
494 | |||
495 | if (cfi->cfiq->BlockEraseTimeoutTyp && | ||
496 | cfi->cfiq->BlockEraseTimeoutMax) | ||
497 | cfi->chips[i].erase_time_max = | ||
498 | 1000<<(cfi->cfiq->BlockEraseTimeoutTyp + | ||
499 | cfi->cfiq->BlockEraseTimeoutMax); | ||
500 | else | ||
501 | cfi->chips[i].erase_time_max = 2000000 * 8; | ||
502 | |||
481 | cfi->chips[i].ref_point_counter = 0; | 503 | cfi->chips[i].ref_point_counter = 0; |
482 | init_waitqueue_head(&(cfi->chips[i].wq)); | 504 | init_waitqueue_head(&(cfi->chips[i].wq)); |
483 | } | 505 | } |
@@ -1012,7 +1034,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, | |||
1012 | 1034 | ||
1013 | static int __xipram xip_wait_for_operation( | 1035 | static int __xipram xip_wait_for_operation( |
1014 | struct map_info *map, struct flchip *chip, | 1036 | struct map_info *map, struct flchip *chip, |
1015 | unsigned long adr, unsigned int chip_op_time ) | 1037 | unsigned long adr, unsigned int chip_op_time_max) |
1016 | { | 1038 | { |
1017 | struct cfi_private *cfi = map->fldrv_priv; | 1039 | struct cfi_private *cfi = map->fldrv_priv; |
1018 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; | 1040 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; |
@@ -1021,7 +1043,7 @@ static int __xipram xip_wait_for_operation( | |||
1021 | flstate_t oldstate, newstate; | 1043 | flstate_t oldstate, newstate; |
1022 | 1044 | ||
1023 | start = xip_currtime(); | 1045 | start = xip_currtime(); |
1024 | usec = chip_op_time * 8; | 1046 | usec = chip_op_time_max; |
1025 | if (usec == 0) | 1047 | if (usec == 0) |
1026 | usec = 500000; | 1048 | usec = 500000; |
1027 | done = 0; | 1049 | done = 0; |
@@ -1131,8 +1153,8 @@ static int __xipram xip_wait_for_operation( | |||
1131 | #define XIP_INVAL_CACHED_RANGE(map, from, size) \ | 1153 | #define XIP_INVAL_CACHED_RANGE(map, from, size) \ |
1132 | INVALIDATE_CACHED_RANGE(map, from, size) | 1154 | INVALIDATE_CACHED_RANGE(map, from, size) |
1133 | 1155 | ||
1134 | #define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \ | 1156 | #define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec, usec_max) \ |
1135 | xip_wait_for_operation(map, chip, cmd_adr, usec) | 1157 | xip_wait_for_operation(map, chip, cmd_adr, usec_max) |
1136 | 1158 | ||
1137 | #else | 1159 | #else |
1138 | 1160 | ||
@@ -1144,7 +1166,7 @@ static int __xipram xip_wait_for_operation( | |||
1144 | static int inval_cache_and_wait_for_operation( | 1166 | static int inval_cache_and_wait_for_operation( |
1145 | struct map_info *map, struct flchip *chip, | 1167 | struct map_info *map, struct flchip *chip, |
1146 | unsigned long cmd_adr, unsigned long inval_adr, int inval_len, | 1168 | unsigned long cmd_adr, unsigned long inval_adr, int inval_len, |
1147 | unsigned int chip_op_time) | 1169 | unsigned int chip_op_time, unsigned int chip_op_time_max) |
1148 | { | 1170 | { |
1149 | struct cfi_private *cfi = map->fldrv_priv; | 1171 | struct cfi_private *cfi = map->fldrv_priv; |
1150 | map_word status, status_OK = CMD(0x80); | 1172 | map_word status, status_OK = CMD(0x80); |
@@ -1156,8 +1178,7 @@ static int inval_cache_and_wait_for_operation( | |||
1156 | INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len); | 1178 | INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len); |
1157 | spin_lock(chip->mutex); | 1179 | spin_lock(chip->mutex); |
1158 | 1180 | ||
1159 | /* set our timeout to 8 times the expected delay */ | 1181 | timeo = chip_op_time_max; |
1160 | timeo = chip_op_time * 8; | ||
1161 | if (!timeo) | 1182 | if (!timeo) |
1162 | timeo = 500000; | 1183 | timeo = 500000; |
1163 | reset_timeo = timeo; | 1184 | reset_timeo = timeo; |
@@ -1217,8 +1238,8 @@ static int inval_cache_and_wait_for_operation( | |||
1217 | 1238 | ||
1218 | #endif | 1239 | #endif |
1219 | 1240 | ||
1220 | #define WAIT_TIMEOUT(map, chip, adr, udelay) \ | 1241 | #define WAIT_TIMEOUT(map, chip, adr, udelay, udelay_max) \ |
1221 | INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay); | 1242 | INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay, udelay_max); |
1222 | 1243 | ||
1223 | 1244 | ||
1224 | static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) | 1245 | static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) |
@@ -1452,7 +1473,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1452 | 1473 | ||
1453 | ret = INVAL_CACHE_AND_WAIT(map, chip, adr, | 1474 | ret = INVAL_CACHE_AND_WAIT(map, chip, adr, |
1454 | adr, map_bankwidth(map), | 1475 | adr, map_bankwidth(map), |
1455 | chip->word_write_time); | 1476 | chip->word_write_time, |
1477 | chip->word_write_time_max); | ||
1456 | if (ret) { | 1478 | if (ret) { |
1457 | xip_enable(map, chip, adr); | 1479 | xip_enable(map, chip, adr); |
1458 | printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); | 1480 | printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); |
@@ -1623,7 +1645,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1623 | 1645 | ||
1624 | chip->state = FL_WRITING_TO_BUFFER; | 1646 | chip->state = FL_WRITING_TO_BUFFER; |
1625 | map_write(map, write_cmd, cmd_adr); | 1647 | map_write(map, write_cmd, cmd_adr); |
1626 | ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0); | 1648 | ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0, 0); |
1627 | if (ret) { | 1649 | if (ret) { |
1628 | /* Argh. Not ready for write to buffer */ | 1650 | /* Argh. Not ready for write to buffer */ |
1629 | map_word Xstatus = map_read(map, cmd_adr); | 1651 | map_word Xstatus = map_read(map, cmd_adr); |
@@ -1640,7 +1662,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1640 | 1662 | ||
1641 | /* Figure out the number of words to write */ | 1663 | /* Figure out the number of words to write */ |
1642 | word_gap = (-adr & (map_bankwidth(map)-1)); | 1664 | word_gap = (-adr & (map_bankwidth(map)-1)); |
1643 | words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); | 1665 | words = DIV_ROUND_UP(len - word_gap, map_bankwidth(map)); |
1644 | if (!word_gap) { | 1666 | if (!word_gap) { |
1645 | words--; | 1667 | words--; |
1646 | } else { | 1668 | } else { |
@@ -1692,7 +1714,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | |||
1692 | 1714 | ||
1693 | ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, | 1715 | ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, |
1694 | initial_adr, initial_len, | 1716 | initial_adr, initial_len, |
1695 | chip->buffer_write_time); | 1717 | chip->buffer_write_time, |
1718 | chip->buffer_write_time_max); | ||
1696 | if (ret) { | 1719 | if (ret) { |
1697 | map_write(map, CMD(0x70), cmd_adr); | 1720 | map_write(map, CMD(0x70), cmd_adr); |
1698 | chip->state = FL_STATUS; | 1721 | chip->state = FL_STATUS; |
@@ -1827,7 +1850,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | |||
1827 | 1850 | ||
1828 | ret = INVAL_CACHE_AND_WAIT(map, chip, adr, | 1851 | ret = INVAL_CACHE_AND_WAIT(map, chip, adr, |
1829 | adr, len, | 1852 | adr, len, |
1830 | chip->erase_time); | 1853 | chip->erase_time, |
1854 | chip->erase_time_max); | ||
1831 | if (ret) { | 1855 | if (ret) { |
1832 | map_write(map, CMD(0x70), adr); | 1856 | map_write(map, CMD(0x70), adr); |
1833 | chip->state = FL_STATUS; | 1857 | chip->state = FL_STATUS; |
@@ -2006,7 +2030,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip | |||
2006 | */ | 2030 | */ |
2007 | udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; | 2031 | udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0; |
2008 | 2032 | ||
2009 | ret = WAIT_TIMEOUT(map, chip, adr, udelay); | 2033 | ret = WAIT_TIMEOUT(map, chip, adr, udelay, udelay * 100); |
2010 | if (ret) { | 2034 | if (ret) { |
2011 | map_write(map, CMD(0x70), adr); | 2035 | map_write(map, CMD(0x70), adr); |
2012 | chip->state = FL_STATUS; | 2036 | chip->state = FL_STATUS; |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index c418e92e1d92..e63e6749429a 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
@@ -44,17 +44,14 @@ do { \ | |||
44 | 44 | ||
45 | #define xip_enable(base, map, cfi) \ | 45 | #define xip_enable(base, map, cfi) \ |
46 | do { \ | 46 | do { \ |
47 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ | 47 | cfi_qry_mode_off(base, map, cfi); \ |
48 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ | ||
49 | xip_allowed(base, map); \ | 48 | xip_allowed(base, map); \ |
50 | } while (0) | 49 | } while (0) |
51 | 50 | ||
52 | #define xip_disable_qry(base, map, cfi) \ | 51 | #define xip_disable_qry(base, map, cfi) \ |
53 | do { \ | 52 | do { \ |
54 | xip_disable(); \ | 53 | xip_disable(); \ |
55 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ | 54 | cfi_qry_mode_on(base, map, cfi); \ |
56 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ | ||
57 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \ | ||
58 | } while (0) | 55 | } while (0) |
59 | 56 | ||
60 | #else | 57 | #else |
@@ -70,32 +67,6 @@ do { \ | |||
70 | in: interleave,type,mode | 67 | in: interleave,type,mode |
71 | ret: table index, <0 for error | 68 | ret: table index, <0 for error |
72 | */ | 69 | */ |
73 | static int __xipram qry_present(struct map_info *map, __u32 base, | ||
74 | struct cfi_private *cfi) | ||
75 | { | ||
76 | int osf = cfi->interleave * cfi->device_type; // scale factor | ||
77 | map_word val[3]; | ||
78 | map_word qry[3]; | ||
79 | |||
80 | qry[0] = cfi_build_cmd('Q', map, cfi); | ||
81 | qry[1] = cfi_build_cmd('R', map, cfi); | ||
82 | qry[2] = cfi_build_cmd('Y', map, cfi); | ||
83 | |||
84 | val[0] = map_read(map, base + osf*0x10); | ||
85 | val[1] = map_read(map, base + osf*0x11); | ||
86 | val[2] = map_read(map, base + osf*0x12); | ||
87 | |||
88 | if (!map_word_equal(map, qry[0], val[0])) | ||
89 | return 0; | ||
90 | |||
91 | if (!map_word_equal(map, qry[1], val[1])) | ||
92 | return 0; | ||
93 | |||
94 | if (!map_word_equal(map, qry[2], val[2])) | ||
95 | return 0; | ||
96 | |||
97 | return 1; // "QRY" found | ||
98 | } | ||
99 | 70 | ||
100 | static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | 71 | static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, |
101 | unsigned long *chip_map, struct cfi_private *cfi) | 72 | unsigned long *chip_map, struct cfi_private *cfi) |
@@ -116,11 +87,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
116 | } | 87 | } |
117 | 88 | ||
118 | xip_disable(); | 89 | xip_disable(); |
119 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 90 | if (!cfi_qry_mode_on(base, map, cfi)) { |
120 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
121 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
122 | |||
123 | if (!qry_present(map,base,cfi)) { | ||
124 | xip_enable(base, map, cfi); | 91 | xip_enable(base, map, cfi); |
125 | return 0; | 92 | return 0; |
126 | } | 93 | } |
@@ -141,14 +108,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
141 | start = i << cfi->chipshift; | 108 | start = i << cfi->chipshift; |
142 | /* This chip should be in read mode if it's one | 109 | /* This chip should be in read mode if it's one |
143 | we've already touched. */ | 110 | we've already touched. */ |
144 | if (qry_present(map, start, cfi)) { | 111 | if (cfi_qry_present(map, start, cfi)) { |
145 | /* Eep. This chip also had the QRY marker. | 112 | /* Eep. This chip also had the QRY marker. |
146 | * Is it an alias for the new one? */ | 113 | * Is it an alias for the new one? */ |
147 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); | 114 | cfi_qry_mode_off(start, map, cfi); |
148 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | ||
149 | 115 | ||
150 | /* If the QRY marker goes away, it's an alias */ | 116 | /* If the QRY marker goes away, it's an alias */ |
151 | if (!qry_present(map, start, cfi)) { | 117 | if (!cfi_qry_present(map, start, cfi)) { |
152 | xip_allowed(base, map); | 118 | xip_allowed(base, map); |
153 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", | 119 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", |
154 | map->name, base, start); | 120 | map->name, base, start); |
@@ -158,10 +124,9 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
158 | * unfortunate. Stick the new chip in read mode | 124 | * unfortunate. Stick the new chip in read mode |
159 | * too and if it's the same, assume it's an alias. */ | 125 | * too and if it's the same, assume it's an alias. */ |
160 | /* FIXME: Use other modes to do a proper check */ | 126 | /* FIXME: Use other modes to do a proper check */ |
161 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 127 | cfi_qry_mode_off(base, map, cfi); |
162 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | ||
163 | 128 | ||
164 | if (qry_present(map, base, cfi)) { | 129 | if (cfi_qry_present(map, base, cfi)) { |
165 | xip_allowed(base, map); | 130 | xip_allowed(base, map); |
166 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", | 131 | printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", |
167 | map->name, base, start); | 132 | map->name, base, start); |
@@ -176,8 +141,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
176 | cfi->numchips++; | 141 | cfi->numchips++; |
177 | 142 | ||
178 | /* Put it back into Read Mode */ | 143 | /* Put it back into Read Mode */ |
179 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 144 | cfi_qry_mode_off(base, map, cfi); |
180 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
181 | xip_allowed(base, map); | 145 | xip_allowed(base, map); |
182 | 146 | ||
183 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 147 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
@@ -237,9 +201,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
237 | cfi_read_query(map, base + 0xf * ofs_factor); | 201 | cfi_read_query(map, base + 0xf * ofs_factor); |
238 | 202 | ||
239 | /* Put it back into Read Mode */ | 203 | /* Put it back into Read Mode */ |
240 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 204 | cfi_qry_mode_off(base, map, cfi); |
241 | /* ... even if it's an Intel chip */ | ||
242 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
243 | xip_allowed(base, map); | 205 | xip_allowed(base, map); |
244 | 206 | ||
245 | /* Do any necessary byteswapping */ | 207 | /* Do any necessary byteswapping */ |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 0ee457018016..34d40e25d312 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -24,6 +24,66 @@ | |||
24 | #include <linux/mtd/cfi.h> | 24 | #include <linux/mtd/cfi.h> |
25 | #include <linux/mtd/compatmac.h> | 25 | #include <linux/mtd/compatmac.h> |
26 | 26 | ||
27 | int __xipram cfi_qry_present(struct map_info *map, __u32 base, | ||
28 | struct cfi_private *cfi) | ||
29 | { | ||
30 | int osf = cfi->interleave * cfi->device_type; /* scale factor */ | ||
31 | map_word val[3]; | ||
32 | map_word qry[3]; | ||
33 | |||
34 | qry[0] = cfi_build_cmd('Q', map, cfi); | ||
35 | qry[1] = cfi_build_cmd('R', map, cfi); | ||
36 | qry[2] = cfi_build_cmd('Y', map, cfi); | ||
37 | |||
38 | val[0] = map_read(map, base + osf*0x10); | ||
39 | val[1] = map_read(map, base + osf*0x11); | ||
40 | val[2] = map_read(map, base + osf*0x12); | ||
41 | |||
42 | if (!map_word_equal(map, qry[0], val[0])) | ||
43 | return 0; | ||
44 | |||
45 | if (!map_word_equal(map, qry[1], val[1])) | ||
46 | return 0; | ||
47 | |||
48 | if (!map_word_equal(map, qry[2], val[2])) | ||
49 | return 0; | ||
50 | |||
51 | return 1; /* "QRY" found */ | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(cfi_qry_present); | ||
54 | |||
55 | int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, | ||
56 | struct cfi_private *cfi) | ||
57 | { | ||
58 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
59 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
60 | if (cfi_qry_present(map, base, cfi)) | ||
61 | return 1; | ||
62 | /* QRY not found probably we deal with some odd CFI chips */ | ||
63 | /* Some revisions of some old Intel chips? */ | ||
64 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
65 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
66 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
67 | if (cfi_qry_present(map, base, cfi)) | ||
68 | return 1; | ||
69 | /* ST M29DW chips */ | ||
70 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
71 | cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); | ||
72 | if (cfi_qry_present(map, base, cfi)) | ||
73 | return 1; | ||
74 | /* QRY not found */ | ||
75 | return 0; | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(cfi_qry_mode_on); | ||
78 | |||
79 | void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, | ||
80 | struct cfi_private *cfi) | ||
81 | { | ||
82 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
83 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
84 | } | ||
85 | EXPORT_SYMBOL_GPL(cfi_qry_mode_off); | ||
86 | |||
27 | struct cfi_extquery * | 87 | struct cfi_extquery * |
28 | __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) | 88 | __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) |
29 | { | 89 | { |
@@ -48,8 +108,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
48 | #endif | 108 | #endif |
49 | 109 | ||
50 | /* Switch it into Query Mode */ | 110 | /* Switch it into Query Mode */ |
51 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | 111 | cfi_qry_mode_on(base, map, cfi); |
52 | |||
53 | /* Read in the Extended Query Table */ | 112 | /* Read in the Extended Query Table */ |
54 | for (i=0; i<size; i++) { | 113 | for (i=0; i<size; i++) { |
55 | ((unsigned char *)extp)[i] = | 114 | ((unsigned char *)extp)[i] = |
@@ -57,8 +116,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
57 | } | 116 | } |
58 | 117 | ||
59 | /* Make sure it returns to read mode */ | 118 | /* Make sure it returns to read mode */ |
60 | cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); | 119 | cfi_qry_mode_off(base, map, cfi); |
61 | cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL); | ||
62 | 120 | ||
63 | #ifdef CONFIG_MTD_XIP | 121 | #ifdef CONFIG_MTD_XIP |
64 | (void) map_read(map, base); | 122 | (void) map_read(map, base); |
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index f061885b2812..e2dc96441e05 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
@@ -111,7 +111,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
111 | max_chips = 1; | 111 | max_chips = 1; |
112 | } | 112 | } |
113 | 113 | ||
114 | mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG ); | 114 | mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); |
115 | chip_map = kzalloc(mapsize, GFP_KERNEL); | 115 | chip_map = kzalloc(mapsize, GFP_KERNEL); |
116 | if (!chip_map) { | 116 | if (!chip_map) { |
117 | printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); | 117 | printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 9c613f06623c..6fde0a2e3567 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -59,6 +59,27 @@ config MTD_DATAFLASH | |||
59 | Sometimes DataFlash chips are packaged inside MMC-format | 59 | Sometimes DataFlash chips are packaged inside MMC-format |
60 | cards; at this writing, the MMC stack won't handle those. | 60 | cards; at this writing, the MMC stack won't handle those. |
61 | 61 | ||
62 | config MTD_DATAFLASH_WRITE_VERIFY | ||
63 | bool "Verify DataFlash page writes" | ||
64 | depends on MTD_DATAFLASH | ||
65 | help | ||
66 | This adds an extra check when data is written to the flash. | ||
67 | It may help if you are verifying chip setup (timings etc) on | ||
68 | your board. There is a rare possibility that even though the | ||
69 | device thinks the write was successful, a bit could have been | ||
70 | flipped accidentally due to device wear or something else. | ||
71 | |||
72 | config MTD_DATAFLASH_OTP | ||
73 | bool "DataFlash OTP support (Security Register)" | ||
74 | depends on MTD_DATAFLASH | ||
75 | select HAVE_MTD_OTP | ||
76 | help | ||
77 | Newer DataFlash chips (revisions C and D) support 128 bytes of | ||
78 | one-time-programmable (OTP) data. The first half may be written | ||
79 | (once) with up to 64 bytes of data, such as a serial number or | ||
80 | other key product data. The second half is programmed with a | ||
81 | unique-to-each-chip bit pattern at the factory. | ||
82 | |||
62 | config MTD_M25P80 | 83 | config MTD_M25P80 |
63 | tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" | 84 | tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" |
64 | depends on SPI_MASTER && EXPERIMENTAL | 85 | depends on SPI_MASTER && EXPERIMENTAL |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index b35c3333e210..4d3ae085b1d2 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ | 39 | #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ |
40 | #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ | 40 | #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ |
41 | #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ | 41 | #define OPCODE_BE_32K 0x52 /* Erase 32KiB block */ |
42 | #define OPCODE_BE 0xc7 /* Erase whole flash block */ | ||
42 | #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ | 43 | #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ |
43 | #define OPCODE_RDID 0x9f /* Read JEDEC ID */ | 44 | #define OPCODE_RDID 0x9f /* Read JEDEC ID */ |
44 | 45 | ||
@@ -133,7 +134,7 @@ static inline int write_enable(struct m25p *flash) | |||
133 | { | 134 | { |
134 | u8 code = OPCODE_WREN; | 135 | u8 code = OPCODE_WREN; |
135 | 136 | ||
136 | return spi_write_then_read(flash->spi, &code, 1, NULL, 0); | 137 | return spi_write(flash->spi, &code, 1); |
137 | } | 138 | } |
138 | 139 | ||
139 | 140 | ||
@@ -161,6 +162,31 @@ static int wait_till_ready(struct m25p *flash) | |||
161 | return 1; | 162 | return 1; |
162 | } | 163 | } |
163 | 164 | ||
165 | /* | ||
166 | * Erase the whole flash memory | ||
167 | * | ||
168 | * Returns 0 if successful, non-zero otherwise. | ||
169 | */ | ||
170 | static int erase_block(struct m25p *flash) | ||
171 | { | ||
172 | DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n", | ||
173 | flash->spi->dev.bus_id, __func__, | ||
174 | flash->mtd.size / 1024); | ||
175 | |||
176 | /* Wait until finished previous write command. */ | ||
177 | if (wait_till_ready(flash)) | ||
178 | return 1; | ||
179 | |||
180 | /* Send write enable, then erase commands. */ | ||
181 | write_enable(flash); | ||
182 | |||
183 | /* Set up command buffer. */ | ||
184 | flash->command[0] = OPCODE_BE; | ||
185 | |||
186 | spi_write(flash->spi, flash->command, 1); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
164 | 190 | ||
165 | /* | 191 | /* |
166 | * Erase one sector of flash memory at offset ``offset'' which is any | 192 | * Erase one sector of flash memory at offset ``offset'' which is any |
@@ -229,15 +255,21 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
229 | */ | 255 | */ |
230 | 256 | ||
231 | /* now erase those sectors */ | 257 | /* now erase those sectors */ |
232 | while (len) { | 258 | if (len == flash->mtd.size && erase_block(flash)) { |
233 | if (erase_sector(flash, addr)) { | 259 | instr->state = MTD_ERASE_FAILED; |
234 | instr->state = MTD_ERASE_FAILED; | 260 | mutex_unlock(&flash->lock); |
235 | mutex_unlock(&flash->lock); | 261 | return -EIO; |
236 | return -EIO; | 262 | } else { |
237 | } | 263 | while (len) { |
264 | if (erase_sector(flash, addr)) { | ||
265 | instr->state = MTD_ERASE_FAILED; | ||
266 | mutex_unlock(&flash->lock); | ||
267 | return -EIO; | ||
268 | } | ||
238 | 269 | ||
239 | addr += mtd->erasesize; | 270 | addr += mtd->erasesize; |
240 | len -= mtd->erasesize; | 271 | len -= mtd->erasesize; |
272 | } | ||
241 | } | 273 | } |
242 | 274 | ||
243 | mutex_unlock(&flash->lock); | 275 | mutex_unlock(&flash->lock); |
@@ -437,6 +469,7 @@ struct flash_info { | |||
437 | * then a two byte device id. | 469 | * then a two byte device id. |
438 | */ | 470 | */ |
439 | u32 jedec_id; | 471 | u32 jedec_id; |
472 | u16 ext_id; | ||
440 | 473 | ||
441 | /* The size listed here is what works with OPCODE_SE, which isn't | 474 | /* The size listed here is what works with OPCODE_SE, which isn't |
442 | * necessarily called a "sector" by the vendor. | 475 | * necessarily called a "sector" by the vendor. |
@@ -456,57 +489,59 @@ struct flash_info { | |||
456 | static struct flash_info __devinitdata m25p_data [] = { | 489 | static struct flash_info __devinitdata m25p_data [] = { |
457 | 490 | ||
458 | /* Atmel -- some are (confusingly) marketed as "DataFlash" */ | 491 | /* Atmel -- some are (confusingly) marketed as "DataFlash" */ |
459 | { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, }, | 492 | { "at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K, }, |
460 | { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, }, | 493 | { "at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K, }, |
461 | 494 | ||
462 | { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, }, | 495 | { "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K, }, |
463 | { "at25df641", 0x1f4800, 64 * 1024, 128, SECT_4K, }, | 496 | { "at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K, }, |
464 | 497 | ||
465 | { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, }, | 498 | { "at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K, }, |
466 | { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, }, | 499 | { "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K, }, |
467 | { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, }, | 500 | { "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, }, |
468 | { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, }, | 501 | { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, }, |
469 | 502 | ||
470 | /* Spansion -- single (large) sector size only, at least | 503 | /* Spansion -- single (large) sector size only, at least |
471 | * for the chips listed here (without boot sectors). | 504 | * for the chips listed here (without boot sectors). |
472 | */ | 505 | */ |
473 | { "s25sl004a", 0x010212, 64 * 1024, 8, }, | 506 | { "s25sl004a", 0x010212, 0, 64 * 1024, 8, }, |
474 | { "s25sl008a", 0x010213, 64 * 1024, 16, }, | 507 | { "s25sl008a", 0x010213, 0, 64 * 1024, 16, }, |
475 | { "s25sl016a", 0x010214, 64 * 1024, 32, }, | 508 | { "s25sl016a", 0x010214, 0, 64 * 1024, 32, }, |
476 | { "s25sl032a", 0x010215, 64 * 1024, 64, }, | 509 | { "s25sl032a", 0x010215, 0, 64 * 1024, 64, }, |
477 | { "s25sl064a", 0x010216, 64 * 1024, 128, }, | 510 | { "s25sl064a", 0x010216, 0, 64 * 1024, 128, }, |
511 | { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, }, | ||
512 | { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, }, | ||
478 | 513 | ||
479 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ | 514 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ |
480 | { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, }, | 515 | { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, }, |
481 | { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, }, | 516 | { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, }, |
482 | { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, }, | 517 | { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, }, |
483 | { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, }, | 518 | { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, }, |
484 | 519 | ||
485 | /* ST Microelectronics -- newer production may have feature updates */ | 520 | /* ST Microelectronics -- newer production may have feature updates */ |
486 | { "m25p05", 0x202010, 32 * 1024, 2, }, | 521 | { "m25p05", 0x202010, 0, 32 * 1024, 2, }, |
487 | { "m25p10", 0x202011, 32 * 1024, 4, }, | 522 | { "m25p10", 0x202011, 0, 32 * 1024, 4, }, |
488 | { "m25p20", 0x202012, 64 * 1024, 4, }, | 523 | { "m25p20", 0x202012, 0, 64 * 1024, 4, }, |
489 | { "m25p40", 0x202013, 64 * 1024, 8, }, | 524 | { "m25p40", 0x202013, 0, 64 * 1024, 8, }, |
490 | { "m25p80", 0, 64 * 1024, 16, }, | 525 | { "m25p80", 0, 0, 64 * 1024, 16, }, |
491 | { "m25p16", 0x202015, 64 * 1024, 32, }, | 526 | { "m25p16", 0x202015, 0, 64 * 1024, 32, }, |
492 | { "m25p32", 0x202016, 64 * 1024, 64, }, | 527 | { "m25p32", 0x202016, 0, 64 * 1024, 64, }, |
493 | { "m25p64", 0x202017, 64 * 1024, 128, }, | 528 | { "m25p64", 0x202017, 0, 64 * 1024, 128, }, |
494 | { "m25p128", 0x202018, 256 * 1024, 64, }, | 529 | { "m25p128", 0x202018, 0, 256 * 1024, 64, }, |
495 | 530 | ||
496 | { "m45pe80", 0x204014, 64 * 1024, 16, }, | 531 | { "m45pe80", 0x204014, 0, 64 * 1024, 16, }, |
497 | { "m45pe16", 0x204015, 64 * 1024, 32, }, | 532 | { "m45pe16", 0x204015, 0, 64 * 1024, 32, }, |
498 | 533 | ||
499 | { "m25pe80", 0x208014, 64 * 1024, 16, }, | 534 | { "m25pe80", 0x208014, 0, 64 * 1024, 16, }, |
500 | { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, }, | 535 | { "m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K, }, |
501 | 536 | ||
502 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ | 537 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ |
503 | { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, }, | 538 | { "w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K, }, |
504 | { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, }, | 539 | { "w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K, }, |
505 | { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, }, | 540 | { "w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K, }, |
506 | { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, }, | 541 | { "w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K, }, |
507 | { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, }, | 542 | { "w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K, }, |
508 | { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, }, | 543 | { "w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K, }, |
509 | { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, }, | 544 | { "w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K, }, |
510 | }; | 545 | }; |
511 | 546 | ||
512 | static struct flash_info *__devinit jedec_probe(struct spi_device *spi) | 547 | static struct flash_info *__devinit jedec_probe(struct spi_device *spi) |
@@ -515,6 +550,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) | |||
515 | u8 code = OPCODE_RDID; | 550 | u8 code = OPCODE_RDID; |
516 | u8 id[3]; | 551 | u8 id[3]; |
517 | u32 jedec; | 552 | u32 jedec; |
553 | u16 ext_jedec; | ||
518 | struct flash_info *info; | 554 | struct flash_info *info; |
519 | 555 | ||
520 | /* JEDEC also defines an optional "extended device information" | 556 | /* JEDEC also defines an optional "extended device information" |
@@ -533,10 +569,14 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) | |||
533 | jedec = jedec << 8; | 569 | jedec = jedec << 8; |
534 | jedec |= id[2]; | 570 | jedec |= id[2]; |
535 | 571 | ||
572 | ext_jedec = id[3] << 8 | id[4]; | ||
573 | |||
536 | for (tmp = 0, info = m25p_data; | 574 | for (tmp = 0, info = m25p_data; |
537 | tmp < ARRAY_SIZE(m25p_data); | 575 | tmp < ARRAY_SIZE(m25p_data); |
538 | tmp++, info++) { | 576 | tmp++, info++) { |
539 | if (info->jedec_id == jedec) | 577 | if (info->jedec_id == jedec) |
578 | if (ext_jedec != 0 && info->ext_id != ext_jedec) | ||
579 | continue; | ||
540 | return info; | 580 | return info; |
541 | } | 581 | } |
542 | dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); | 582 | dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 8bd0dea6885f..6dd9aff8bb2d 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
@@ -30,12 +30,10 @@ | |||
30 | * doesn't (yet) use these for any kind of i/o overlap or prefetching. | 30 | * doesn't (yet) use these for any kind of i/o overlap or prefetching. |
31 | * | 31 | * |
32 | * Sometimes DataFlash is packaged in MMC-format cards, although the | 32 | * Sometimes DataFlash is packaged in MMC-format cards, although the |
33 | * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash | 33 | * MMC stack can't (yet?) distinguish between MMC and DataFlash |
34 | * protocols during enumeration. | 34 | * protocols during enumeration. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #define CONFIG_DATAFLASH_WRITE_VERIFY | ||
38 | |||
39 | /* reads can bypass the buffers */ | 37 | /* reads can bypass the buffers */ |
40 | #define OP_READ_CONTINUOUS 0xE8 | 38 | #define OP_READ_CONTINUOUS 0xE8 |
41 | #define OP_READ_PAGE 0xD2 | 39 | #define OP_READ_PAGE 0xD2 |
@@ -80,7 +78,8 @@ | |||
80 | */ | 78 | */ |
81 | #define OP_READ_ID 0x9F | 79 | #define OP_READ_ID 0x9F |
82 | #define OP_READ_SECURITY 0x77 | 80 | #define OP_READ_SECURITY 0x77 |
83 | #define OP_WRITE_SECURITY 0x9A /* OTP bits */ | 81 | #define OP_WRITE_SECURITY_REVC 0x9A |
82 | #define OP_WRITE_SECURITY 0x9B /* revision D */ | ||
84 | 83 | ||
85 | 84 | ||
86 | struct dataflash { | 85 | struct dataflash { |
@@ -402,7 +401,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
402 | (void) dataflash_waitready(priv->spi); | 401 | (void) dataflash_waitready(priv->spi); |
403 | 402 | ||
404 | 403 | ||
405 | #ifdef CONFIG_DATAFLASH_WRITE_VERIFY | 404 | #ifdef CONFIG_MTD_DATAFLASH_VERIFY_WRITE |
406 | 405 | ||
407 | /* (3) Compare to Buffer1 */ | 406 | /* (3) Compare to Buffer1 */ |
408 | addr = pageaddr << priv->page_offset; | 407 | addr = pageaddr << priv->page_offset; |
@@ -431,7 +430,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
431 | } else | 430 | } else |
432 | status = 0; | 431 | status = 0; |
433 | 432 | ||
434 | #endif /* CONFIG_DATAFLASH_WRITE_VERIFY */ | 433 | #endif /* CONFIG_MTD_DATAFLASH_VERIFY_WRITE */ |
435 | 434 | ||
436 | remaining = remaining - writelen; | 435 | remaining = remaining - writelen; |
437 | pageaddr++; | 436 | pageaddr++; |
@@ -451,16 +450,192 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
451 | 450 | ||
452 | /* ......................................................................... */ | 451 | /* ......................................................................... */ |
453 | 452 | ||
453 | #ifdef CONFIG_MTD_DATAFLASH_OTP | ||
454 | |||
455 | static int dataflash_get_otp_info(struct mtd_info *mtd, | ||
456 | struct otp_info *info, size_t len) | ||
457 | { | ||
458 | /* Report both blocks as identical: bytes 0..64, locked. | ||
459 | * Unless the user block changed from all-ones, we can't | ||
460 | * tell whether it's still writable; so we assume it isn't. | ||
461 | */ | ||
462 | info->start = 0; | ||
463 | info->length = 64; | ||
464 | info->locked = 1; | ||
465 | return sizeof(*info); | ||
466 | } | ||
467 | |||
468 | static ssize_t otp_read(struct spi_device *spi, unsigned base, | ||
469 | uint8_t *buf, loff_t off, size_t len) | ||
470 | { | ||
471 | struct spi_message m; | ||
472 | size_t l; | ||
473 | uint8_t *scratch; | ||
474 | struct spi_transfer t; | ||
475 | int status; | ||
476 | |||
477 | if (off > 64) | ||
478 | return -EINVAL; | ||
479 | |||
480 | if ((off + len) > 64) | ||
481 | len = 64 - off; | ||
482 | if (len == 0) | ||
483 | return len; | ||
484 | |||
485 | spi_message_init(&m); | ||
486 | |||
487 | l = 4 + base + off + len; | ||
488 | scratch = kzalloc(l, GFP_KERNEL); | ||
489 | if (!scratch) | ||
490 | return -ENOMEM; | ||
491 | |||
492 | /* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes | ||
493 | * IN: ignore 4 bytes, data bytes 0..N (max 127) | ||
494 | */ | ||
495 | scratch[0] = OP_READ_SECURITY; | ||
496 | |||
497 | memset(&t, 0, sizeof t); | ||
498 | t.tx_buf = scratch; | ||
499 | t.rx_buf = scratch; | ||
500 | t.len = l; | ||
501 | spi_message_add_tail(&t, &m); | ||
502 | |||
503 | dataflash_waitready(spi); | ||
504 | |||
505 | status = spi_sync(spi, &m); | ||
506 | if (status >= 0) { | ||
507 | memcpy(buf, scratch + 4 + base + off, len); | ||
508 | status = len; | ||
509 | } | ||
510 | |||
511 | kfree(scratch); | ||
512 | return status; | ||
513 | } | ||
514 | |||
515 | static int dataflash_read_fact_otp(struct mtd_info *mtd, | ||
516 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
517 | { | ||
518 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
519 | int status; | ||
520 | |||
521 | /* 64 bytes, from 0..63 ... start at 64 on-chip */ | ||
522 | mutex_lock(&priv->lock); | ||
523 | status = otp_read(priv->spi, 64, buf, from, len); | ||
524 | mutex_unlock(&priv->lock); | ||
525 | |||
526 | if (status < 0) | ||
527 | return status; | ||
528 | *retlen = status; | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int dataflash_read_user_otp(struct mtd_info *mtd, | ||
533 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
534 | { | ||
535 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
536 | int status; | ||
537 | |||
538 | /* 64 bytes, from 0..63 ... start at 0 on-chip */ | ||
539 | mutex_lock(&priv->lock); | ||
540 | status = otp_read(priv->spi, 0, buf, from, len); | ||
541 | mutex_unlock(&priv->lock); | ||
542 | |||
543 | if (status < 0) | ||
544 | return status; | ||
545 | *retlen = status; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int dataflash_write_user_otp(struct mtd_info *mtd, | ||
550 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
551 | { | ||
552 | struct spi_message m; | ||
553 | const size_t l = 4 + 64; | ||
554 | uint8_t *scratch; | ||
555 | struct spi_transfer t; | ||
556 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
557 | int status; | ||
558 | |||
559 | if (len > 64) | ||
560 | return -EINVAL; | ||
561 | |||
562 | /* Strictly speaking, we *could* truncate the write ... but | ||
563 | * let's not do that for the only write that's ever possible. | ||
564 | */ | ||
565 | if ((from + len) > 64) | ||
566 | return -EINVAL; | ||
567 | |||
568 | /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes | ||
569 | * IN: ignore all | ||
570 | */ | ||
571 | scratch = kzalloc(l, GFP_KERNEL); | ||
572 | if (!scratch) | ||
573 | return -ENOMEM; | ||
574 | scratch[0] = OP_WRITE_SECURITY; | ||
575 | memcpy(scratch + 4 + from, buf, len); | ||
576 | |||
577 | spi_message_init(&m); | ||
578 | |||
579 | memset(&t, 0, sizeof t); | ||
580 | t.tx_buf = scratch; | ||
581 | t.len = l; | ||
582 | spi_message_add_tail(&t, &m); | ||
583 | |||
584 | /* Write the OTP bits, if they've not yet been written. | ||
585 | * This modifies SRAM buffer1. | ||
586 | */ | ||
587 | mutex_lock(&priv->lock); | ||
588 | dataflash_waitready(priv->spi); | ||
589 | status = spi_sync(priv->spi, &m); | ||
590 | mutex_unlock(&priv->lock); | ||
591 | |||
592 | kfree(scratch); | ||
593 | |||
594 | if (status >= 0) { | ||
595 | status = 0; | ||
596 | *retlen = len; | ||
597 | } | ||
598 | return status; | ||
599 | } | ||
600 | |||
601 | static char *otp_setup(struct mtd_info *device, char revision) | ||
602 | { | ||
603 | device->get_fact_prot_info = dataflash_get_otp_info; | ||
604 | device->read_fact_prot_reg = dataflash_read_fact_otp; | ||
605 | device->get_user_prot_info = dataflash_get_otp_info; | ||
606 | device->read_user_prot_reg = dataflash_read_user_otp; | ||
607 | |||
608 | /* rev c parts (at45db321c and at45db1281 only!) use a | ||
609 | * different write procedure; not (yet?) implemented. | ||
610 | */ | ||
611 | if (revision > 'c') | ||
612 | device->write_user_prot_reg = dataflash_write_user_otp; | ||
613 | |||
614 | return ", OTP"; | ||
615 | } | ||
616 | |||
617 | #else | ||
618 | |||
619 | static char *otp_setup(struct mtd_info *device, char revision) | ||
620 | { | ||
621 | return " (OTP)"; | ||
622 | } | ||
623 | |||
624 | #endif | ||
625 | |||
626 | /* ......................................................................... */ | ||
627 | |||
454 | /* | 628 | /* |
455 | * Register DataFlash device with MTD subsystem. | 629 | * Register DataFlash device with MTD subsystem. |
456 | */ | 630 | */ |
457 | static int __devinit | 631 | static int __devinit |
458 | add_dataflash(struct spi_device *spi, char *name, | 632 | add_dataflash_otp(struct spi_device *spi, char *name, |
459 | int nr_pages, int pagesize, int pageoffset) | 633 | int nr_pages, int pagesize, int pageoffset, char revision) |
460 | { | 634 | { |
461 | struct dataflash *priv; | 635 | struct dataflash *priv; |
462 | struct mtd_info *device; | 636 | struct mtd_info *device; |
463 | struct flash_platform_data *pdata = spi->dev.platform_data; | 637 | struct flash_platform_data *pdata = spi->dev.platform_data; |
638 | char *otp_tag = ""; | ||
464 | 639 | ||
465 | priv = kzalloc(sizeof *priv, GFP_KERNEL); | 640 | priv = kzalloc(sizeof *priv, GFP_KERNEL); |
466 | if (!priv) | 641 | if (!priv) |
@@ -489,8 +664,12 @@ add_dataflash(struct spi_device *spi, char *name, | |||
489 | device->write = dataflash_write; | 664 | device->write = dataflash_write; |
490 | device->priv = priv; | 665 | device->priv = priv; |
491 | 666 | ||
492 | dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", | 667 | if (revision >= 'c') |
493 | name, DIV_ROUND_UP(device->size, 1024), pagesize); | 668 | otp_tag = otp_setup(device, revision); |
669 | |||
670 | dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", | ||
671 | name, DIV_ROUND_UP(device->size, 1024), | ||
672 | pagesize, otp_tag); | ||
494 | dev_set_drvdata(&spi->dev, priv); | 673 | dev_set_drvdata(&spi->dev, priv); |
495 | 674 | ||
496 | if (mtd_has_partitions()) { | 675 | if (mtd_has_partitions()) { |
@@ -519,6 +698,14 @@ add_dataflash(struct spi_device *spi, char *name, | |||
519 | return add_mtd_device(device) == 1 ? -ENODEV : 0; | 698 | return add_mtd_device(device) == 1 ? -ENODEV : 0; |
520 | } | 699 | } |
521 | 700 | ||
701 | static inline int __devinit | ||
702 | add_dataflash(struct spi_device *spi, char *name, | ||
703 | int nr_pages, int pagesize, int pageoffset) | ||
704 | { | ||
705 | return add_dataflash_otp(spi, name, nr_pages, pagesize, | ||
706 | pageoffset, 0); | ||
707 | } | ||
708 | |||
522 | struct flash_info { | 709 | struct flash_info { |
523 | char *name; | 710 | char *name; |
524 | 711 | ||
@@ -664,13 +851,16 @@ static int __devinit dataflash_probe(struct spi_device *spi) | |||
664 | * Try to detect dataflash by JEDEC ID. | 851 | * Try to detect dataflash by JEDEC ID. |
665 | * If it succeeds we know we have either a C or D part. | 852 | * If it succeeds we know we have either a C or D part. |
666 | * D will support power of 2 pagesize option. | 853 | * D will support power of 2 pagesize option. |
854 | * Both support the security register, though with different | ||
855 | * write procedures. | ||
667 | */ | 856 | */ |
668 | info = jedec_probe(spi); | 857 | info = jedec_probe(spi); |
669 | if (IS_ERR(info)) | 858 | if (IS_ERR(info)) |
670 | return PTR_ERR(info); | 859 | return PTR_ERR(info); |
671 | if (info != NULL) | 860 | if (info != NULL) |
672 | return add_dataflash(spi, info->name, info->nr_pages, | 861 | return add_dataflash_otp(spi, info->name, info->nr_pages, |
673 | info->pagesize, info->pageoffset); | 862 | info->pagesize, info->pageoffset, |
863 | (info->flags & SUP_POW2PS) ? 'd' : 'c'); | ||
674 | 864 | ||
675 | /* | 865 | /* |
676 | * Older chips support only legacy commands, identifing | 866 | * Older chips support only legacy commands, identifing |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index df8e00bba07b..3ae76ecc07d7 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -332,30 +332,6 @@ config MTD_CFI_FLAGADM | |||
332 | Mapping for the Flaga digital module. If you don't have one, ignore | 332 | Mapping for the Flaga digital module. If you don't have one, ignore |
333 | this setting. | 333 | this setting. |
334 | 334 | ||
335 | config MTD_WALNUT | ||
336 | tristate "Flash device mapped on IBM 405GP Walnut" | ||
337 | depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE | ||
338 | help | ||
339 | This enables access routines for the flash chips on the IBM 405GP | ||
340 | Walnut board. If you have one of these boards and would like to | ||
341 | use the flash chips on it, say 'Y'. | ||
342 | |||
343 | config MTD_EBONY | ||
344 | tristate "Flash devices mapped on IBM 440GP Ebony" | ||
345 | depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE | ||
346 | help | ||
347 | This enables access routines for the flash chips on the IBM 440GP | ||
348 | Ebony board. If you have one of these boards and would like to | ||
349 | use the flash chips on it, say 'Y'. | ||
350 | |||
351 | config MTD_OCOTEA | ||
352 | tristate "Flash devices mapped on IBM 440GX Ocotea" | ||
353 | depends on MTD_CFI && OCOTEA && !PPC_MERGE | ||
354 | help | ||
355 | This enables access routines for the flash chips on the IBM 440GX | ||
356 | Ocotea board. If you have one of these boards and would like to | ||
357 | use the flash chips on it, say 'Y'. | ||
358 | |||
359 | config MTD_REDWOOD | 335 | config MTD_REDWOOD |
360 | tristate "CFI Flash devices mapped on IBM Redwood" | 336 | tristate "CFI Flash devices mapped on IBM Redwood" |
361 | depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) | 337 | depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) |
@@ -458,13 +434,6 @@ config MTD_CEIVA | |||
458 | PhotoMax Digital Picture Frame. | 434 | PhotoMax Digital Picture Frame. |
459 | If you have such a device, say 'Y'. | 435 | If you have such a device, say 'Y'. |
460 | 436 | ||
461 | config MTD_NOR_TOTO | ||
462 | tristate "NOR Flash device on TOTO board" | ||
463 | depends on ARCH_OMAP && OMAP_TOTO | ||
464 | help | ||
465 | This enables access to the NOR flash on the Texas Instruments | ||
466 | TOTO board. | ||
467 | |||
468 | config MTD_H720X | 437 | config MTD_H720X |
469 | tristate "Hynix evaluation board mappings" | 438 | tristate "Hynix evaluation board mappings" |
470 | depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) | 439 | depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 6cda6df973e5..6d9ba35caf11 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -50,12 +50,8 @@ obj-$(CONFIG_MTD_REDWOOD) += redwood.o | |||
50 | obj-$(CONFIG_MTD_UCLINUX) += uclinux.o | 50 | obj-$(CONFIG_MTD_UCLINUX) += uclinux.o |
51 | obj-$(CONFIG_MTD_NETtel) += nettel.o | 51 | obj-$(CONFIG_MTD_NETtel) += nettel.o |
52 | obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o | 52 | obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o |
53 | obj-$(CONFIG_MTD_EBONY) += ebony.o | ||
54 | obj-$(CONFIG_MTD_OCOTEA) += ocotea.o | ||
55 | obj-$(CONFIG_MTD_WALNUT) += walnut.o | ||
56 | obj-$(CONFIG_MTD_H720X) += h720x-flash.o | 53 | obj-$(CONFIG_MTD_H720X) += h720x-flash.o |
57 | obj-$(CONFIG_MTD_SBC8240) += sbc8240.o | 54 | obj-$(CONFIG_MTD_SBC8240) += sbc8240.o |
58 | obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o | ||
59 | obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o | 55 | obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o |
60 | obj-$(CONFIG_MTD_IXP2000) += ixp2000.o | 56 | obj-$(CONFIG_MTD_IXP2000) += ixp2000.o |
61 | obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o | 57 | obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o |
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c deleted file mode 100644 index d92b7c70d3ed..000000000000 --- a/drivers/mtd/maps/ebony.c +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | /* | ||
2 | * Mapping for Ebony user flash | ||
3 | * | ||
4 | * Matt Porter <mporter@kernel.crashing.org> | ||
5 | * | ||
6 | * Copyright 2002-2004 MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/map.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/ibm44x.h> | ||
23 | #include <platforms/4xx/ebony.h> | ||
24 | |||
25 | static struct mtd_info *flash; | ||
26 | |||
27 | static struct map_info ebony_small_map = { | ||
28 | .name = "Ebony small flash", | ||
29 | .size = EBONY_SMALL_FLASH_SIZE, | ||
30 | .bankwidth = 1, | ||
31 | }; | ||
32 | |||
33 | static struct map_info ebony_large_map = { | ||
34 | .name = "Ebony large flash", | ||
35 | .size = EBONY_LARGE_FLASH_SIZE, | ||
36 | .bankwidth = 1, | ||
37 | }; | ||
38 | |||
39 | static struct mtd_partition ebony_small_partitions[] = { | ||
40 | { | ||
41 | .name = "OpenBIOS", | ||
42 | .offset = 0x0, | ||
43 | .size = 0x80000, | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | static struct mtd_partition ebony_large_partitions[] = { | ||
48 | { | ||
49 | .name = "fs", | ||
50 | .offset = 0, | ||
51 | .size = 0x380000, | ||
52 | }, | ||
53 | { | ||
54 | .name = "firmware", | ||
55 | .offset = 0x380000, | ||
56 | .size = 0x80000, | ||
57 | } | ||
58 | }; | ||
59 | |||
60 | int __init init_ebony(void) | ||
61 | { | ||
62 | u8 fpga0_reg; | ||
63 | u8 __iomem *fpga0_adr; | ||
64 | unsigned long long small_flash_base, large_flash_base; | ||
65 | |||
66 | fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16); | ||
67 | if (!fpga0_adr) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | fpga0_reg = readb(fpga0_adr); | ||
71 | iounmap(fpga0_adr); | ||
72 | |||
73 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | ||
74 | !EBONY_FLASH_SEL(fpga0_reg)) | ||
75 | small_flash_base = EBONY_SMALL_FLASH_HIGH2; | ||
76 | else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | ||
77 | EBONY_FLASH_SEL(fpga0_reg)) | ||
78 | small_flash_base = EBONY_SMALL_FLASH_HIGH1; | ||
79 | else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | ||
80 | !EBONY_FLASH_SEL(fpga0_reg)) | ||
81 | small_flash_base = EBONY_SMALL_FLASH_LOW2; | ||
82 | else | ||
83 | small_flash_base = EBONY_SMALL_FLASH_LOW1; | ||
84 | |||
85 | if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && | ||
86 | !EBONY_ONBRD_FLASH_EN(fpga0_reg)) | ||
87 | large_flash_base = EBONY_LARGE_FLASH_LOW; | ||
88 | else | ||
89 | large_flash_base = EBONY_LARGE_FLASH_HIGH; | ||
90 | |||
91 | ebony_small_map.phys = small_flash_base; | ||
92 | ebony_small_map.virt = ioremap64(small_flash_base, | ||
93 | ebony_small_map.size); | ||
94 | |||
95 | if (!ebony_small_map.virt) { | ||
96 | printk("Failed to ioremap flash\n"); | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | simple_map_init(&ebony_small_map); | ||
101 | |||
102 | flash = do_map_probe("jedec_probe", &ebony_small_map); | ||
103 | if (flash) { | ||
104 | flash->owner = THIS_MODULE; | ||
105 | add_mtd_partitions(flash, ebony_small_partitions, | ||
106 | ARRAY_SIZE(ebony_small_partitions)); | ||
107 | } else { | ||
108 | printk("map probe failed for flash\n"); | ||
109 | iounmap(ebony_small_map.virt); | ||
110 | return -ENXIO; | ||
111 | } | ||
112 | |||
113 | ebony_large_map.phys = large_flash_base; | ||
114 | ebony_large_map.virt = ioremap64(large_flash_base, | ||
115 | ebony_large_map.size); | ||
116 | |||
117 | if (!ebony_large_map.virt) { | ||
118 | printk("Failed to ioremap flash\n"); | ||
119 | iounmap(ebony_small_map.virt); | ||
120 | return -EIO; | ||
121 | } | ||
122 | |||
123 | simple_map_init(&ebony_large_map); | ||
124 | |||
125 | flash = do_map_probe("jedec_probe", &ebony_large_map); | ||
126 | if (flash) { | ||
127 | flash->owner = THIS_MODULE; | ||
128 | add_mtd_partitions(flash, ebony_large_partitions, | ||
129 | ARRAY_SIZE(ebony_large_partitions)); | ||
130 | } else { | ||
131 | printk("map probe failed for flash\n"); | ||
132 | iounmap(ebony_small_map.virt); | ||
133 | iounmap(ebony_large_map.virt); | ||
134 | return -ENXIO; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static void __exit cleanup_ebony(void) | ||
141 | { | ||
142 | if (flash) { | ||
143 | del_mtd_partitions(flash); | ||
144 | map_destroy(flash); | ||
145 | } | ||
146 | |||
147 | if (ebony_small_map.virt) { | ||
148 | iounmap(ebony_small_map.virt); | ||
149 | ebony_small_map.virt = NULL; | ||
150 | } | ||
151 | |||
152 | if (ebony_large_map.virt) { | ||
153 | iounmap(ebony_large_map.virt); | ||
154 | ebony_large_map.virt = NULL; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | module_init(init_ebony); | ||
159 | module_exit(cleanup_ebony); | ||
160 | |||
161 | MODULE_LICENSE("GPL"); | ||
162 | MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); | ||
163 | MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards"); | ||
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c deleted file mode 100644 index 5522eac8c980..000000000000 --- a/drivers/mtd/maps/ocotea.c +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | /* | ||
2 | * Mapping for Ocotea user flash | ||
3 | * | ||
4 | * Matt Porter <mporter@kernel.crashing.org> | ||
5 | * | ||
6 | * Copyright 2002-2004 MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/map.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/ibm44x.h> | ||
23 | #include <platforms/4xx/ocotea.h> | ||
24 | |||
25 | static struct mtd_info *flash; | ||
26 | |||
27 | static struct map_info ocotea_small_map = { | ||
28 | .name = "Ocotea small flash", | ||
29 | .size = OCOTEA_SMALL_FLASH_SIZE, | ||
30 | .buswidth = 1, | ||
31 | }; | ||
32 | |||
33 | static struct map_info ocotea_large_map = { | ||
34 | .name = "Ocotea large flash", | ||
35 | .size = OCOTEA_LARGE_FLASH_SIZE, | ||
36 | .buswidth = 1, | ||
37 | }; | ||
38 | |||
39 | static struct mtd_partition ocotea_small_partitions[] = { | ||
40 | { | ||
41 | .name = "pibs", | ||
42 | .offset = 0x0, | ||
43 | .size = 0x100000, | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | static struct mtd_partition ocotea_large_partitions[] = { | ||
48 | { | ||
49 | .name = "fs", | ||
50 | .offset = 0, | ||
51 | .size = 0x300000, | ||
52 | }, | ||
53 | { | ||
54 | .name = "firmware", | ||
55 | .offset = 0x300000, | ||
56 | .size = 0x100000, | ||
57 | } | ||
58 | }; | ||
59 | |||
60 | int __init init_ocotea(void) | ||
61 | { | ||
62 | u8 fpga0_reg; | ||
63 | u8 *fpga0_adr; | ||
64 | unsigned long long small_flash_base, large_flash_base; | ||
65 | |||
66 | fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16); | ||
67 | if (!fpga0_adr) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | fpga0_reg = readb((unsigned long)fpga0_adr); | ||
71 | iounmap(fpga0_adr); | ||
72 | |||
73 | if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) { | ||
74 | small_flash_base = OCOTEA_SMALL_FLASH_HIGH; | ||
75 | large_flash_base = OCOTEA_LARGE_FLASH_LOW; | ||
76 | } | ||
77 | else { | ||
78 | small_flash_base = OCOTEA_SMALL_FLASH_LOW; | ||
79 | large_flash_base = OCOTEA_LARGE_FLASH_HIGH; | ||
80 | } | ||
81 | |||
82 | ocotea_small_map.phys = small_flash_base; | ||
83 | ocotea_small_map.virt = ioremap64(small_flash_base, | ||
84 | ocotea_small_map.size); | ||
85 | |||
86 | if (!ocotea_small_map.virt) { | ||
87 | printk("Failed to ioremap flash\n"); | ||
88 | return -EIO; | ||
89 | } | ||
90 | |||
91 | simple_map_init(&ocotea_small_map); | ||
92 | |||
93 | flash = do_map_probe("map_rom", &ocotea_small_map); | ||
94 | if (flash) { | ||
95 | flash->owner = THIS_MODULE; | ||
96 | add_mtd_partitions(flash, ocotea_small_partitions, | ||
97 | ARRAY_SIZE(ocotea_small_partitions)); | ||
98 | } else { | ||
99 | printk("map probe failed for flash\n"); | ||
100 | iounmap(ocotea_small_map.virt); | ||
101 | return -ENXIO; | ||
102 | } | ||
103 | |||
104 | ocotea_large_map.phys = large_flash_base; | ||
105 | ocotea_large_map.virt = ioremap64(large_flash_base, | ||
106 | ocotea_large_map.size); | ||
107 | |||
108 | if (!ocotea_large_map.virt) { | ||
109 | printk("Failed to ioremap flash\n"); | ||
110 | iounmap(ocotea_small_map.virt); | ||
111 | return -EIO; | ||
112 | } | ||
113 | |||
114 | simple_map_init(&ocotea_large_map); | ||
115 | |||
116 | flash = do_map_probe("cfi_probe", &ocotea_large_map); | ||
117 | if (flash) { | ||
118 | flash->owner = THIS_MODULE; | ||
119 | add_mtd_partitions(flash, ocotea_large_partitions, | ||
120 | ARRAY_SIZE(ocotea_large_partitions)); | ||
121 | } else { | ||
122 | printk("map probe failed for flash\n"); | ||
123 | iounmap(ocotea_small_map.virt); | ||
124 | iounmap(ocotea_large_map.virt); | ||
125 | return -ENXIO; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static void __exit cleanup_ocotea(void) | ||
132 | { | ||
133 | if (flash) { | ||
134 | del_mtd_partitions(flash); | ||
135 | map_destroy(flash); | ||
136 | } | ||
137 | |||
138 | if (ocotea_small_map.virt) { | ||
139 | iounmap((void *)ocotea_small_map.virt); | ||
140 | ocotea_small_map.virt = 0; | ||
141 | } | ||
142 | |||
143 | if (ocotea_large_map.virt) { | ||
144 | iounmap((void *)ocotea_large_map.virt); | ||
145 | ocotea_large_map.virt = 0; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | module_init(init_ocotea); | ||
150 | module_exit(cleanup_ocotea); | ||
151 | |||
152 | MODULE_LICENSE("GPL"); | ||
153 | MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); | ||
154 | MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards"); | ||
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c deleted file mode 100644 index 0a60ebbc2175..000000000000 --- a/drivers/mtd/maps/omap-toto-flash.c +++ /dev/null | |||
@@ -1,133 +0,0 @@ | |||
1 | /* | ||
2 | * NOR Flash memory access on TI Toto board | ||
3 | * | ||
4 | * jzhang@ti.com (C) 2003 Texas Instruments. | ||
5 | * | ||
6 | * (C) 2002 MontVista Software, Inc. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/slab.h> | ||
15 | |||
16 | #include <linux/mtd/mtd.h> | ||
17 | #include <linux/mtd/map.h> | ||
18 | #include <linux/mtd/partitions.h> | ||
19 | |||
20 | #include <asm/hardware.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | |||
24 | #ifndef CONFIG_ARCH_OMAP | ||
25 | #error This is for OMAP architecture only | ||
26 | #endif | ||
27 | |||
28 | //these lines need be moved to a hardware header file | ||
29 | #define OMAP_TOTO_FLASH_BASE 0xd8000000 | ||
30 | #define OMAP_TOTO_FLASH_SIZE 0x80000 | ||
31 | |||
32 | static struct map_info omap_toto_map_flash = { | ||
33 | .name = "OMAP Toto flash", | ||
34 | .bankwidth = 2, | ||
35 | .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, | ||
36 | }; | ||
37 | |||
38 | |||
39 | static struct mtd_partition toto_flash_partitions[] = { | ||
40 | { | ||
41 | .name = "BootLoader", | ||
42 | .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/ | ||
43 | .offset = 0, | ||
44 | .mask_flags = MTD_WRITEABLE, /* force read-only */ | ||
45 | }, { | ||
46 | .name = "ReservedSpace", | ||
47 | .size = 0x00030000, | ||
48 | .offset = MTDPART_OFS_APPEND, | ||
49 | //mask_flags: MTD_WRITEABLE, /* force read-only */ | ||
50 | }, { | ||
51 | .name = "EnvArea", /* bottom 64KiB for env vars */ | ||
52 | .size = MTDPART_SIZ_FULL, | ||
53 | .offset = MTDPART_OFS_APPEND, | ||
54 | } | ||
55 | }; | ||
56 | |||
57 | static struct mtd_partition *parsed_parts; | ||
58 | |||
59 | static struct mtd_info *flash_mtd; | ||
60 | |||
61 | static int __init init_flash (void) | ||
62 | { | ||
63 | |||
64 | struct mtd_partition *parts; | ||
65 | int nb_parts = 0; | ||
66 | int parsed_nr_parts = 0; | ||
67 | const char *part_type; | ||
68 | |||
69 | /* | ||
70 | * Static partition definition selection | ||
71 | */ | ||
72 | part_type = "static"; | ||
73 | |||
74 | parts = toto_flash_partitions; | ||
75 | nb_parts = ARRAY_SIZE(toto_flash_partitions); | ||
76 | omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE; | ||
77 | omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE); | ||
78 | |||
79 | simple_map_init(&omap_toto_map_flash); | ||
80 | /* | ||
81 | * Now let's probe for the actual flash. Do it here since | ||
82 | * specific machine settings might have been set above. | ||
83 | */ | ||
84 | printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n", | ||
85 | omap_toto_map_flash.bankwidth*8); | ||
86 | flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); | ||
87 | if (!flash_mtd) | ||
88 | return -ENXIO; | ||
89 | |||
90 | if (parsed_nr_parts > 0) { | ||
91 | parts = parsed_parts; | ||
92 | nb_parts = parsed_nr_parts; | ||
93 | } | ||
94 | |||
95 | if (nb_parts == 0) { | ||
96 | printk(KERN_NOTICE "OMAP toto flash: no partition info available," | ||
97 | "registering whole flash at once\n"); | ||
98 | if (add_mtd_device(flash_mtd)){ | ||
99 | return -ENXIO; | ||
100 | } | ||
101 | } else { | ||
102 | printk(KERN_NOTICE "Using %s partition definition\n", | ||
103 | part_type); | ||
104 | return add_mtd_partitions(flash_mtd, parts, nb_parts); | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | int __init omap_toto_mtd_init(void) | ||
110 | { | ||
111 | int status; | ||
112 | |||
113 | if (status = init_flash()) { | ||
114 | printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n"); | ||
115 | } | ||
116 | return status; | ||
117 | } | ||
118 | |||
119 | static void __exit omap_toto_mtd_cleanup(void) | ||
120 | { | ||
121 | if (flash_mtd) { | ||
122 | del_mtd_partitions(flash_mtd); | ||
123 | map_destroy(flash_mtd); | ||
124 | kfree(parsed_parts); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | module_init(omap_toto_mtd_init); | ||
129 | module_exit(omap_toto_mtd_cleanup); | ||
130 | |||
131 | MODULE_AUTHOR("Jian Zhang"); | ||
132 | MODULE_DESCRIPTION("OMAP Toto board map driver"); | ||
133 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c deleted file mode 100644 index e243476c8171..000000000000 --- a/drivers/mtd/maps/walnut.c +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | /* | ||
2 | * Mapping for Walnut flash | ||
3 | * (used ebony.c as a "framework") | ||
4 | * | ||
5 | * Heikki Lindholm <holindho@infradead.org> | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/map.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/ibm4xx.h> | ||
23 | #include <platforms/4xx/walnut.h> | ||
24 | |||
25 | /* these should be in platforms/4xx/walnut.h ? */ | ||
26 | #define WALNUT_FLASH_ONBD_N(x) (x & 0x02) | ||
27 | #define WALNUT_FLASH_SRAM_SEL(x) (x & 0x01) | ||
28 | #define WALNUT_FLASH_LOW 0xFFF00000 | ||
29 | #define WALNUT_FLASH_HIGH 0xFFF80000 | ||
30 | #define WALNUT_FLASH_SIZE 0x80000 | ||
31 | |||
32 | static struct mtd_info *flash; | ||
33 | |||
34 | static struct map_info walnut_map = { | ||
35 | .name = "Walnut flash", | ||
36 | .size = WALNUT_FLASH_SIZE, | ||
37 | .bankwidth = 1, | ||
38 | }; | ||
39 | |||
40 | /* Actually, OpenBIOS is the last 128 KiB of the flash - better | ||
41 | * partitioning could be made */ | ||
42 | static struct mtd_partition walnut_partitions[] = { | ||
43 | { | ||
44 | .name = "OpenBIOS", | ||
45 | .offset = 0x0, | ||
46 | .size = WALNUT_FLASH_SIZE, | ||
47 | /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ | ||
48 | } | ||
49 | }; | ||
50 | |||
51 | int __init init_walnut(void) | ||
52 | { | ||
53 | u8 fpga_brds1; | ||
54 | void *fpga_brds1_adr; | ||
55 | void *fpga_status_adr; | ||
56 | unsigned long flash_base; | ||
57 | |||
58 | /* this should already be mapped (platform/4xx/walnut.c) */ | ||
59 | fpga_status_adr = ioremap(WALNUT_FPGA_BASE, 8); | ||
60 | if (!fpga_status_adr) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | fpga_brds1_adr = fpga_status_adr+5; | ||
64 | fpga_brds1 = readb(fpga_brds1_adr); | ||
65 | /* iounmap(fpga_status_adr); */ | ||
66 | |||
67 | if (WALNUT_FLASH_ONBD_N(fpga_brds1)) { | ||
68 | printk("The on-board flash is disabled (U79 sw 5)!"); | ||
69 | iounmap(fpga_status_adr); | ||
70 | return -EIO; | ||
71 | } | ||
72 | if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) | ||
73 | flash_base = WALNUT_FLASH_LOW; | ||
74 | else | ||
75 | flash_base = WALNUT_FLASH_HIGH; | ||
76 | |||
77 | walnut_map.phys = flash_base; | ||
78 | walnut_map.virt = | ||
79 | (void __iomem *)ioremap(flash_base, walnut_map.size); | ||
80 | |||
81 | if (!walnut_map.virt) { | ||
82 | printk("Failed to ioremap flash.\n"); | ||
83 | iounmap(fpga_status_adr); | ||
84 | return -EIO; | ||
85 | } | ||
86 | |||
87 | simple_map_init(&walnut_map); | ||
88 | |||
89 | flash = do_map_probe("jedec_probe", &walnut_map); | ||
90 | if (flash) { | ||
91 | flash->owner = THIS_MODULE; | ||
92 | add_mtd_partitions(flash, walnut_partitions, | ||
93 | ARRAY_SIZE(walnut_partitions)); | ||
94 | } else { | ||
95 | printk("map probe failed for flash\n"); | ||
96 | iounmap(fpga_status_adr); | ||
97 | return -ENXIO; | ||
98 | } | ||
99 | |||
100 | iounmap(fpga_status_adr); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void __exit cleanup_walnut(void) | ||
105 | { | ||
106 | if (flash) { | ||
107 | del_mtd_partitions(flash); | ||
108 | map_destroy(flash); | ||
109 | } | ||
110 | |||
111 | if (walnut_map.virt) { | ||
112 | iounmap((void *)walnut_map.virt); | ||
113 | walnut_map.virt = 0; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | module_init(init_walnut); | ||
118 | module_exit(cleanup_walnut); | ||
119 | |||
120 | MODULE_LICENSE("GPL"); | ||
121 | MODULE_AUTHOR("Heikki Lindholm <holindho@infradead.org>"); | ||
122 | MODULE_DESCRIPTION("MTD map and partitions for IBM 405GP Walnut boards"); | ||
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d2f331876e4c..13cc67ad272a 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -350,7 +350,7 @@ static void mtdchar_erase_callback (struct erase_info *instr) | |||
350 | wake_up((wait_queue_head_t *)instr->priv); | 350 | wake_up((wait_queue_head_t *)instr->priv); |
351 | } | 351 | } |
352 | 352 | ||
353 | #if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) | 353 | #ifdef CONFIG_HAVE_MTD_OTP |
354 | static int otp_select_filemode(struct mtd_file_info *mfi, int mode) | 354 | static int otp_select_filemode(struct mtd_file_info *mfi, int mode) |
355 | { | 355 | { |
356 | struct mtd_info *mtd = mfi->mtd; | 356 | struct mtd_info *mtd = mfi->mtd; |
@@ -663,7 +663,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
663 | break; | 663 | break; |
664 | } | 664 | } |
665 | 665 | ||
666 | #if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) | 666 | #ifdef CONFIG_HAVE_MTD_OTP |
667 | case OTPSELECT: | 667 | case OTPSELECT: |
668 | { | 668 | { |
669 | int mode; | 669 | int mode; |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 2972a5edb73d..789842d0e6f2 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -444,7 +444,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
444 | return -EINVAL; | 444 | return -EINVAL; |
445 | } | 445 | } |
446 | 446 | ||
447 | instr->fail_addr = 0xffffffff; | 447 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
448 | 448 | ||
449 | /* make a local copy of instr to avoid modifying the caller's struct */ | 449 | /* make a local copy of instr to avoid modifying the caller's struct */ |
450 | erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); | 450 | erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); |
@@ -493,7 +493,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
493 | /* sanity check: should never happen since | 493 | /* sanity check: should never happen since |
494 | * block alignment has been checked above */ | 494 | * block alignment has been checked above */ |
495 | BUG_ON(err == -EINVAL); | 495 | BUG_ON(err == -EINVAL); |
496 | if (erase->fail_addr != 0xffffffff) | 496 | if (erase->fail_addr != MTD_FAIL_ADDR_UNKNOWN) |
497 | instr->fail_addr = erase->fail_addr + offset; | 497 | instr->fail_addr = erase->fail_addr + offset; |
498 | break; | 498 | break; |
499 | } | 499 | } |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index edb90b58a9b1..8e77e36e75ee 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -214,7 +214,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
214 | instr->addr += part->offset; | 214 | instr->addr += part->offset; |
215 | ret = part->master->erase(part->master, instr); | 215 | ret = part->master->erase(part->master, instr); |
216 | if (ret) { | 216 | if (ret) { |
217 | if (instr->fail_addr != 0xffffffff) | 217 | if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) |
218 | instr->fail_addr -= part->offset; | 218 | instr->fail_addr -= part->offset; |
219 | instr->addr -= part->offset; | 219 | instr->addr -= part->offset; |
220 | } | 220 | } |
@@ -226,7 +226,7 @@ void mtd_erase_callback(struct erase_info *instr) | |||
226 | if (instr->mtd->erase == part_erase) { | 226 | if (instr->mtd->erase == part_erase) { |
227 | struct mtd_part *part = PART(instr->mtd); | 227 | struct mtd_part *part = PART(instr->mtd); |
228 | 228 | ||
229 | if (instr->fail_addr != 0xffffffff) | 229 | if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) |
230 | instr->fail_addr -= part->offset; | 230 | instr->fail_addr -= part->offset; |
231 | instr->addr -= part->offset; | 231 | instr->addr -= part->offset; |
232 | } | 232 | } |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 41f361c49b32..8eb2b06cf0d9 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -68,12 +68,6 @@ config MTD_NAND_AMS_DELTA | |||
68 | help | 68 | help |
69 | Support for NAND flash on Amstrad E3 (Delta). | 69 | Support for NAND flash on Amstrad E3 (Delta). |
70 | 70 | ||
71 | config MTD_NAND_TOTO | ||
72 | tristate "NAND Flash device on TOTO board" | ||
73 | depends on ARCH_OMAP && BROKEN | ||
74 | help | ||
75 | Support for NAND flash on Texas Instruments Toto platform. | ||
76 | |||
77 | config MTD_NAND_TS7250 | 71 | config MTD_NAND_TS7250 |
78 | tristate "NAND Flash device on TS-7250 board" | 72 | tristate "NAND Flash device on TS-7250 board" |
79 | depends on MACH_TS72XX | 73 | depends on MACH_TS72XX |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b786c5da82da..8540c46ffba9 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -8,7 +8,6 @@ obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o | |||
8 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o | 8 | obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o |
9 | obj-$(CONFIG_MTD_NAND_SPIA) += spia.o | 9 | obj-$(CONFIG_MTD_NAND_SPIA) += spia.o |
10 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o | 10 | obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o |
11 | obj-$(CONFIG_MTD_NAND_TOTO) += toto.o | ||
12 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o | 11 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o |
13 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o | 12 | obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o |
14 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o | 13 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d1129bae6c27..d303db39c48d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -801,9 +801,9 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function | 801 | * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function |
802 | * @mtd: mtd info structure | 802 | * @mtd: mtd info structure |
803 | * @chip: nand chip info structure | 803 | * @chip: nand chip info structure |
804 | * @dataofs offset of requested data within the page | 804 | * @data_offs: offset of requested data within the page |
805 | * @readlen data length | 805 | * @readlen: data length |
806 | * @buf: buffer to store read data | 806 | * @bufpoi: buffer to store read data |
807 | */ | 807 | */ |
808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) | 808 | static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) |
809 | { | 809 | { |
@@ -2042,7 +2042,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
2042 | return -EINVAL; | 2042 | return -EINVAL; |
2043 | } | 2043 | } |
2044 | 2044 | ||
2045 | instr->fail_addr = 0xffffffff; | 2045 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
2046 | 2046 | ||
2047 | /* Grab the lock and see if the device is available */ | 2047 | /* Grab the lock and see if the device is available */ |
2048 | nand_get_device(chip, mtd, FL_ERASING); | 2048 | nand_get_device(chip, mtd, FL_ERASING); |
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 918a806a8471..868147acce2c 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -1,13 +1,18 @@ | |||
1 | /* | 1 | /* |
2 | * This file contains an ECC algorithm from Toshiba that detects and | 2 | * This file contains an ECC algorithm that detects and corrects 1 bit |
3 | * corrects 1 bit errors in a 256 byte block of data. | 3 | * errors in a 256 byte block of data. |
4 | * | 4 | * |
5 | * drivers/mtd/nand/nand_ecc.c | 5 | * drivers/mtd/nand/nand_ecc.c |
6 | * | 6 | * |
7 | * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright © 2008 Koninklijke Philips Electronics NV. |
8 | * Toshiba America Electronics Components, Inc. | 8 | * Author: Frans Meulenbroeks |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> | 10 | * Completely replaces the previous ECC implementation which was written by: |
11 | * Steven J. Hill (sjhill@realitydiluted.com) | ||
12 | * Thomas Gleixner (tglx@linutronix.de) | ||
13 | * | ||
14 | * Information on how this algorithm works and how it was developed | ||
15 | * can be found in Documentation/mtd/nand_ecc.txt | ||
11 | * | 16 | * |
12 | * This file is free software; you can redistribute it and/or modify it | 17 | * This file is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 18 | * under the terms of the GNU General Public License as published by the |
@@ -23,174 +28,475 @@ | |||
23 | * with this file; if not, write to the Free Software Foundation, Inc., | 28 | * with this file; if not, write to the Free Software Foundation, Inc., |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 29 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
25 | * | 30 | * |
26 | * As a special exception, if other files instantiate templates or use | ||
27 | * macros or inline functions from these files, or you compile these | ||
28 | * files and link them with other works to produce a work based on these | ||
29 | * files, these files do not by themselves cause the resulting work to be | ||
30 | * covered by the GNU General Public License. However the source code for | ||
31 | * these files must still be made available in accordance with section (3) | ||
32 | * of the GNU General Public License. | ||
33 | * | ||
34 | * This exception does not invalidate any other reasons why a work based on | ||
35 | * this file might be covered by the GNU General Public License. | ||
36 | */ | 31 | */ |
37 | 32 | ||
33 | /* | ||
34 | * The STANDALONE macro is useful when running the code outside the kernel | ||
35 | * e.g. when running the code in a testbed or a benchmark program. | ||
36 | * When STANDALONE is used, the module related macros are commented out | ||
37 | * as well as the linux include files. | ||
38 | * Instead a private definition of mtd_info is given to satisfy the compiler | ||
39 | * (the code does not use mtd_info, so the code does not care) | ||
40 | */ | ||
41 | #ifndef STANDALONE | ||
38 | #include <linux/types.h> | 42 | #include <linux/types.h> |
39 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
40 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/mtd/mtd.h> | ||
46 | #include <linux/mtd/nand.h> | ||
41 | #include <linux/mtd/nand_ecc.h> | 47 | #include <linux/mtd/nand_ecc.h> |
48 | #include <asm/byteorder.h> | ||
49 | #else | ||
50 | #include <stdint.h> | ||
51 | struct mtd_info; | ||
52 | #define EXPORT_SYMBOL(x) /* x */ | ||
53 | |||
54 | #define MODULE_LICENSE(x) /* x */ | ||
55 | #define MODULE_AUTHOR(x) /* x */ | ||
56 | #define MODULE_DESCRIPTION(x) /* x */ | ||
57 | |||
58 | #define printk printf | ||
59 | #define KERN_ERR "" | ||
60 | #endif | ||
61 | |||
62 | /* | ||
63 | * invparity is a 256 byte table that contains the odd parity | ||
64 | * for each byte. So if the number of bits in a byte is even, | ||
65 | * the array element is 1, and when the number of bits is odd | ||
66 | * the array eleemnt is 0. | ||
67 | */ | ||
68 | static const char invparity[256] = { | ||
69 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
70 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
71 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
72 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
73 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
74 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
75 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
76 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
77 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
78 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
79 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
80 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
81 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, | ||
82 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
83 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, | ||
84 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 | ||
85 | }; | ||
86 | |||
87 | /* | ||
88 | * bitsperbyte contains the number of bits per byte | ||
89 | * this is only used for testing and repairing parity | ||
90 | * (a precalculated value slightly improves performance) | ||
91 | */ | ||
92 | static const char bitsperbyte[256] = { | ||
93 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, | ||
94 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
95 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
96 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
97 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
98 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
99 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
100 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
101 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, | ||
102 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
103 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
104 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
105 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, | ||
106 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
107 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, | ||
108 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, | ||
109 | }; | ||
42 | 110 | ||
43 | /* | 111 | /* |
44 | * Pre-calculated 256-way 1 byte column parity | 112 | * addressbits is a lookup table to filter out the bits from the xor-ed |
113 | * ecc data that identify the faulty location. | ||
114 | * this is only used for repairing parity | ||
115 | * see the comments in nand_correct_data for more details | ||
45 | */ | 116 | */ |
46 | static const u_char nand_ecc_precalc_table[] = { | 117 | static const char addressbits[256] = { |
47 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, | 118 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
48 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 119 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
49 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 120 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
50 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 121 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
51 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 122 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
52 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 123 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
53 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 124 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
54 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 125 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
55 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, | 126 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
56 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, | 127 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
57 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, | 128 | 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, |
58 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, | 129 | 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, |
59 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, | 130 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
60 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, | 131 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
61 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, | 132 | 0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05, |
62 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 | 133 | 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, |
134 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
135 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
136 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
137 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
138 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
139 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
140 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
141 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
142 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
143 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
144 | 0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09, | ||
145 | 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, | ||
146 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
147 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, | ||
148 | 0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d, | ||
149 | 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f | ||
63 | }; | 150 | }; |
64 | 151 | ||
65 | /** | 152 | /** |
66 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block | 153 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte |
154 | * block | ||
67 | * @mtd: MTD block structure | 155 | * @mtd: MTD block structure |
68 | * @dat: raw data | 156 | * @buf: input buffer with raw data |
69 | * @ecc_code: buffer for ECC | 157 | * @code: output buffer with ECC |
70 | */ | 158 | */ |
71 | int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, | 159 | int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, |
72 | u_char *ecc_code) | 160 | unsigned char *code) |
73 | { | 161 | { |
74 | uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; | ||
75 | int i; | 162 | int i; |
163 | const uint32_t *bp = (uint32_t *)buf; | ||
164 | /* 256 or 512 bytes/ecc */ | ||
165 | const uint32_t eccsize_mult = | ||
166 | (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; | ||
167 | uint32_t cur; /* current value in buffer */ | ||
168 | /* rp0..rp15..rp17 are the various accumulated parities (per byte) */ | ||
169 | uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7; | ||
170 | uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16; | ||
171 | uint32_t uninitialized_var(rp17); /* to make compiler happy */ | ||
172 | uint32_t par; /* the cumulative parity for all data */ | ||
173 | uint32_t tmppar; /* the cumulative parity for this iteration; | ||
174 | for rp12, rp14 and rp16 at the end of the | ||
175 | loop */ | ||
176 | |||
177 | par = 0; | ||
178 | rp4 = 0; | ||
179 | rp6 = 0; | ||
180 | rp8 = 0; | ||
181 | rp10 = 0; | ||
182 | rp12 = 0; | ||
183 | rp14 = 0; | ||
184 | rp16 = 0; | ||
185 | |||
186 | /* | ||
187 | * The loop is unrolled a number of times; | ||
188 | * This avoids if statements to decide on which rp value to update | ||
189 | * Also we process the data by longwords. | ||
190 | * Note: passing unaligned data might give a performance penalty. | ||
191 | * It is assumed that the buffers are aligned. | ||
192 | * tmppar is the cumulative sum of this iteration. | ||
193 | * needed for calculating rp12, rp14, rp16 and par | ||
194 | * also used as a performance improvement for rp6, rp8 and rp10 | ||
195 | */ | ||
196 | for (i = 0; i < eccsize_mult << 2; i++) { | ||
197 | cur = *bp++; | ||
198 | tmppar = cur; | ||
199 | rp4 ^= cur; | ||
200 | cur = *bp++; | ||
201 | tmppar ^= cur; | ||
202 | rp6 ^= tmppar; | ||
203 | cur = *bp++; | ||
204 | tmppar ^= cur; | ||
205 | rp4 ^= cur; | ||
206 | cur = *bp++; | ||
207 | tmppar ^= cur; | ||
208 | rp8 ^= tmppar; | ||
76 | 209 | ||
77 | /* Initialize variables */ | 210 | cur = *bp++; |
78 | reg1 = reg2 = reg3 = 0; | 211 | tmppar ^= cur; |
212 | rp4 ^= cur; | ||
213 | rp6 ^= cur; | ||
214 | cur = *bp++; | ||
215 | tmppar ^= cur; | ||
216 | rp6 ^= cur; | ||
217 | cur = *bp++; | ||
218 | tmppar ^= cur; | ||
219 | rp4 ^= cur; | ||
220 | cur = *bp++; | ||
221 | tmppar ^= cur; | ||
222 | rp10 ^= tmppar; | ||
79 | 223 | ||
80 | /* Build up column parity */ | 224 | cur = *bp++; |
81 | for(i = 0; i < 256; i++) { | 225 | tmppar ^= cur; |
82 | /* Get CP0 - CP5 from table */ | 226 | rp4 ^= cur; |
83 | idx = nand_ecc_precalc_table[*dat++]; | 227 | rp6 ^= cur; |
84 | reg1 ^= (idx & 0x3f); | 228 | rp8 ^= cur; |
229 | cur = *bp++; | ||
230 | tmppar ^= cur; | ||
231 | rp6 ^= cur; | ||
232 | rp8 ^= cur; | ||
233 | cur = *bp++; | ||
234 | tmppar ^= cur; | ||
235 | rp4 ^= cur; | ||
236 | rp8 ^= cur; | ||
237 | cur = *bp++; | ||
238 | tmppar ^= cur; | ||
239 | rp8 ^= cur; | ||
85 | 240 | ||
86 | /* All bit XOR = 1 ? */ | 241 | cur = *bp++; |
87 | if (idx & 0x40) { | 242 | tmppar ^= cur; |
88 | reg3 ^= (uint8_t) i; | 243 | rp4 ^= cur; |
89 | reg2 ^= ~((uint8_t) i); | 244 | rp6 ^= cur; |
90 | } | 245 | cur = *bp++; |
246 | tmppar ^= cur; | ||
247 | rp6 ^= cur; | ||
248 | cur = *bp++; | ||
249 | tmppar ^= cur; | ||
250 | rp4 ^= cur; | ||
251 | cur = *bp++; | ||
252 | tmppar ^= cur; | ||
253 | |||
254 | par ^= tmppar; | ||
255 | if ((i & 0x1) == 0) | ||
256 | rp12 ^= tmppar; | ||
257 | if ((i & 0x2) == 0) | ||
258 | rp14 ^= tmppar; | ||
259 | if (eccsize_mult == 2 && (i & 0x4) == 0) | ||
260 | rp16 ^= tmppar; | ||
91 | } | 261 | } |
92 | 262 | ||
93 | /* Create non-inverted ECC code from line parity */ | 263 | /* |
94 | tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ | 264 | * handle the fact that we use longword operations |
95 | tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ | 265 | * we'll bring rp4..rp14..rp16 back to single byte entities by |
96 | tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ | 266 | * shifting and xoring first fold the upper and lower 16 bits, |
97 | tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ | 267 | * then the upper and lower 8 bits. |
98 | tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ | 268 | */ |
99 | tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ | 269 | rp4 ^= (rp4 >> 16); |
100 | tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ | 270 | rp4 ^= (rp4 >> 8); |
101 | tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ | 271 | rp4 &= 0xff; |
102 | 272 | rp6 ^= (rp6 >> 16); | |
103 | tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ | 273 | rp6 ^= (rp6 >> 8); |
104 | tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ | 274 | rp6 &= 0xff; |
105 | tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ | 275 | rp8 ^= (rp8 >> 16); |
106 | tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ | 276 | rp8 ^= (rp8 >> 8); |
107 | tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ | 277 | rp8 &= 0xff; |
108 | tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ | 278 | rp10 ^= (rp10 >> 16); |
109 | tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ | 279 | rp10 ^= (rp10 >> 8); |
110 | tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ | 280 | rp10 &= 0xff; |
111 | 281 | rp12 ^= (rp12 >> 16); | |
112 | /* Calculate final ECC code */ | 282 | rp12 ^= (rp12 >> 8); |
113 | #ifdef CONFIG_MTD_NAND_ECC_SMC | 283 | rp12 &= 0xff; |
114 | ecc_code[0] = ~tmp2; | 284 | rp14 ^= (rp14 >> 16); |
115 | ecc_code[1] = ~tmp1; | 285 | rp14 ^= (rp14 >> 8); |
286 | rp14 &= 0xff; | ||
287 | if (eccsize_mult == 2) { | ||
288 | rp16 ^= (rp16 >> 16); | ||
289 | rp16 ^= (rp16 >> 8); | ||
290 | rp16 &= 0xff; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * we also need to calculate the row parity for rp0..rp3 | ||
295 | * This is present in par, because par is now | ||
296 | * rp3 rp3 rp2 rp2 in little endian and | ||
297 | * rp2 rp2 rp3 rp3 in big endian | ||
298 | * as well as | ||
299 | * rp1 rp0 rp1 rp0 in little endian and | ||
300 | * rp0 rp1 rp0 rp1 in big endian | ||
301 | * First calculate rp2 and rp3 | ||
302 | */ | ||
303 | #ifdef __BIG_ENDIAN | ||
304 | rp2 = (par >> 16); | ||
305 | rp2 ^= (rp2 >> 8); | ||
306 | rp2 &= 0xff; | ||
307 | rp3 = par & 0xffff; | ||
308 | rp3 ^= (rp3 >> 8); | ||
309 | rp3 &= 0xff; | ||
116 | #else | 310 | #else |
117 | ecc_code[0] = ~tmp1; | 311 | rp3 = (par >> 16); |
118 | ecc_code[1] = ~tmp2; | 312 | rp3 ^= (rp3 >> 8); |
313 | rp3 &= 0xff; | ||
314 | rp2 = par & 0xffff; | ||
315 | rp2 ^= (rp2 >> 8); | ||
316 | rp2 &= 0xff; | ||
119 | #endif | 317 | #endif |
120 | ecc_code[2] = ((~reg1) << 2) | 0x03; | ||
121 | 318 | ||
122 | return 0; | 319 | /* reduce par to 16 bits then calculate rp1 and rp0 */ |
123 | } | 320 | par ^= (par >> 16); |
124 | EXPORT_SYMBOL(nand_calculate_ecc); | 321 | #ifdef __BIG_ENDIAN |
322 | rp0 = (par >> 8) & 0xff; | ||
323 | rp1 = (par & 0xff); | ||
324 | #else | ||
325 | rp1 = (par >> 8) & 0xff; | ||
326 | rp0 = (par & 0xff); | ||
327 | #endif | ||
125 | 328 | ||
126 | static inline int countbits(uint32_t byte) | 329 | /* finally reduce par to 8 bits */ |
127 | { | 330 | par ^= (par >> 8); |
128 | int res = 0; | 331 | par &= 0xff; |
129 | 332 | ||
130 | for (;byte; byte >>= 1) | 333 | /* |
131 | res += byte & 0x01; | 334 | * and calculate rp5..rp15..rp17 |
132 | return res; | 335 | * note that par = rp4 ^ rp5 and due to the commutative property |
336 | * of the ^ operator we can say: | ||
337 | * rp5 = (par ^ rp4); | ||
338 | * The & 0xff seems superfluous, but benchmarking learned that | ||
339 | * leaving it out gives slightly worse results. No idea why, probably | ||
340 | * it has to do with the way the pipeline in pentium is organized. | ||
341 | */ | ||
342 | rp5 = (par ^ rp4) & 0xff; | ||
343 | rp7 = (par ^ rp6) & 0xff; | ||
344 | rp9 = (par ^ rp8) & 0xff; | ||
345 | rp11 = (par ^ rp10) & 0xff; | ||
346 | rp13 = (par ^ rp12) & 0xff; | ||
347 | rp15 = (par ^ rp14) & 0xff; | ||
348 | if (eccsize_mult == 2) | ||
349 | rp17 = (par ^ rp16) & 0xff; | ||
350 | |||
351 | /* | ||
352 | * Finally calculate the ecc bits. | ||
353 | * Again here it might seem that there are performance optimisations | ||
354 | * possible, but benchmarks showed that on the system this is developed | ||
355 | * the code below is the fastest | ||
356 | */ | ||
357 | #ifdef CONFIG_MTD_NAND_ECC_SMC | ||
358 | code[0] = | ||
359 | (invparity[rp7] << 7) | | ||
360 | (invparity[rp6] << 6) | | ||
361 | (invparity[rp5] << 5) | | ||
362 | (invparity[rp4] << 4) | | ||
363 | (invparity[rp3] << 3) | | ||
364 | (invparity[rp2] << 2) | | ||
365 | (invparity[rp1] << 1) | | ||
366 | (invparity[rp0]); | ||
367 | code[1] = | ||
368 | (invparity[rp15] << 7) | | ||
369 | (invparity[rp14] << 6) | | ||
370 | (invparity[rp13] << 5) | | ||
371 | (invparity[rp12] << 4) | | ||
372 | (invparity[rp11] << 3) | | ||
373 | (invparity[rp10] << 2) | | ||
374 | (invparity[rp9] << 1) | | ||
375 | (invparity[rp8]); | ||
376 | #else | ||
377 | code[1] = | ||
378 | (invparity[rp7] << 7) | | ||
379 | (invparity[rp6] << 6) | | ||
380 | (invparity[rp5] << 5) | | ||
381 | (invparity[rp4] << 4) | | ||
382 | (invparity[rp3] << 3) | | ||
383 | (invparity[rp2] << 2) | | ||
384 | (invparity[rp1] << 1) | | ||
385 | (invparity[rp0]); | ||
386 | code[0] = | ||
387 | (invparity[rp15] << 7) | | ||
388 | (invparity[rp14] << 6) | | ||
389 | (invparity[rp13] << 5) | | ||
390 | (invparity[rp12] << 4) | | ||
391 | (invparity[rp11] << 3) | | ||
392 | (invparity[rp10] << 2) | | ||
393 | (invparity[rp9] << 1) | | ||
394 | (invparity[rp8]); | ||
395 | #endif | ||
396 | if (eccsize_mult == 1) | ||
397 | code[2] = | ||
398 | (invparity[par & 0xf0] << 7) | | ||
399 | (invparity[par & 0x0f] << 6) | | ||
400 | (invparity[par & 0xcc] << 5) | | ||
401 | (invparity[par & 0x33] << 4) | | ||
402 | (invparity[par & 0xaa] << 3) | | ||
403 | (invparity[par & 0x55] << 2) | | ||
404 | 3; | ||
405 | else | ||
406 | code[2] = | ||
407 | (invparity[par & 0xf0] << 7) | | ||
408 | (invparity[par & 0x0f] << 6) | | ||
409 | (invparity[par & 0xcc] << 5) | | ||
410 | (invparity[par & 0x33] << 4) | | ||
411 | (invparity[par & 0xaa] << 3) | | ||
412 | (invparity[par & 0x55] << 2) | | ||
413 | (invparity[rp17] << 1) | | ||
414 | (invparity[rp16] << 0); | ||
415 | return 0; | ||
133 | } | 416 | } |
417 | EXPORT_SYMBOL(nand_calculate_ecc); | ||
134 | 418 | ||
135 | /** | 419 | /** |
136 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) | 420 | * nand_correct_data - [NAND Interface] Detect and correct bit error(s) |
137 | * @mtd: MTD block structure | 421 | * @mtd: MTD block structure |
138 | * @dat: raw data read from the chip | 422 | * @buf: raw data read from the chip |
139 | * @read_ecc: ECC from the chip | 423 | * @read_ecc: ECC from the chip |
140 | * @calc_ecc: the ECC calculated from raw data | 424 | * @calc_ecc: the ECC calculated from raw data |
141 | * | 425 | * |
142 | * Detect and correct a 1 bit error for 256 byte block | 426 | * Detect and correct a 1 bit error for 256/512 byte block |
143 | */ | 427 | */ |
144 | int nand_correct_data(struct mtd_info *mtd, u_char *dat, | 428 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, |
145 | u_char *read_ecc, u_char *calc_ecc) | 429 | unsigned char *read_ecc, unsigned char *calc_ecc) |
146 | { | 430 | { |
147 | uint8_t s0, s1, s2; | 431 | unsigned char b0, b1, b2; |
432 | unsigned char byte_addr, bit_addr; | ||
433 | /* 256 or 512 bytes/ecc */ | ||
434 | const uint32_t eccsize_mult = | ||
435 | (((struct nand_chip *)mtd->priv)->ecc.size) >> 8; | ||
148 | 436 | ||
437 | /* | ||
438 | * b0 to b2 indicate which bit is faulty (if any) | ||
439 | * we might need the xor result more than once, | ||
440 | * so keep them in a local var | ||
441 | */ | ||
149 | #ifdef CONFIG_MTD_NAND_ECC_SMC | 442 | #ifdef CONFIG_MTD_NAND_ECC_SMC |
150 | s0 = calc_ecc[0] ^ read_ecc[0]; | 443 | b0 = read_ecc[0] ^ calc_ecc[0]; |
151 | s1 = calc_ecc[1] ^ read_ecc[1]; | 444 | b1 = read_ecc[1] ^ calc_ecc[1]; |
152 | s2 = calc_ecc[2] ^ read_ecc[2]; | ||
153 | #else | 445 | #else |
154 | s1 = calc_ecc[0] ^ read_ecc[0]; | 446 | b0 = read_ecc[1] ^ calc_ecc[1]; |
155 | s0 = calc_ecc[1] ^ read_ecc[1]; | 447 | b1 = read_ecc[0] ^ calc_ecc[0]; |
156 | s2 = calc_ecc[2] ^ read_ecc[2]; | ||
157 | #endif | 448 | #endif |
158 | if ((s0 | s1 | s2) == 0) | 449 | b2 = read_ecc[2] ^ calc_ecc[2]; |
159 | return 0; | ||
160 | |||
161 | /* Check for a single bit error */ | ||
162 | if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && | ||
163 | ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && | ||
164 | ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { | ||
165 | 450 | ||
166 | uint32_t byteoffs, bitnum; | 451 | /* check if there are any bitfaults */ |
167 | 452 | ||
168 | byteoffs = (s1 << 0) & 0x80; | 453 | /* repeated if statements are slightly more efficient than switch ... */ |
169 | byteoffs |= (s1 << 1) & 0x40; | 454 | /* ordered in order of likelihood */ |
170 | byteoffs |= (s1 << 2) & 0x20; | ||
171 | byteoffs |= (s1 << 3) & 0x10; | ||
172 | 455 | ||
173 | byteoffs |= (s0 >> 4) & 0x08; | 456 | if ((b0 | b1 | b2) == 0) |
174 | byteoffs |= (s0 >> 3) & 0x04; | 457 | return 0; /* no error */ |
175 | byteoffs |= (s0 >> 2) & 0x02; | ||
176 | byteoffs |= (s0 >> 1) & 0x01; | ||
177 | |||
178 | bitnum = (s2 >> 5) & 0x04; | ||
179 | bitnum |= (s2 >> 4) & 0x02; | ||
180 | bitnum |= (s2 >> 3) & 0x01; | ||
181 | |||
182 | dat[byteoffs] ^= (1 << bitnum); | ||
183 | 458 | ||
459 | if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && | ||
460 | (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && | ||
461 | ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) || | ||
462 | (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) { | ||
463 | /* single bit error */ | ||
464 | /* | ||
465 | * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty | ||
466 | * byte, cp 5/3/1 indicate the faulty bit. | ||
467 | * A lookup table (called addressbits) is used to filter | ||
468 | * the bits from the byte they are in. | ||
469 | * A marginal optimisation is possible by having three | ||
470 | * different lookup tables. | ||
471 | * One as we have now (for b0), one for b2 | ||
472 | * (that would avoid the >> 1), and one for b1 (with all values | ||
473 | * << 4). However it was felt that introducing two more tables | ||
474 | * hardly justify the gain. | ||
475 | * | ||
476 | * The b2 shift is there to get rid of the lowest two bits. | ||
477 | * We could also do addressbits[b2] >> 1 but for the | ||
478 | * performace it does not make any difference | ||
479 | */ | ||
480 | if (eccsize_mult == 1) | ||
481 | byte_addr = (addressbits[b1] << 4) + addressbits[b0]; | ||
482 | else | ||
483 | byte_addr = (addressbits[b2 & 0x3] << 8) + | ||
484 | (addressbits[b1] << 4) + addressbits[b0]; | ||
485 | bit_addr = addressbits[b2 >> 2]; | ||
486 | /* flip the bit */ | ||
487 | buf[byte_addr] ^= (1 << bit_addr); | ||
184 | return 1; | 488 | return 1; |
185 | } | ||
186 | 489 | ||
187 | if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) | 490 | } |
188 | return 1; | 491 | /* count nr of bits; use table lookup, faster than calculating it */ |
492 | if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) | ||
493 | return 1; /* error in ecc data; no action needed */ | ||
189 | 494 | ||
190 | return -EBADMSG; | 495 | printk(KERN_ERR "uncorrectable error : "); |
496 | return -1; | ||
191 | } | 497 | } |
192 | EXPORT_SYMBOL(nand_correct_data); | 498 | EXPORT_SYMBOL(nand_correct_data); |
193 | 499 | ||
194 | MODULE_LICENSE("GPL"); | 500 | MODULE_LICENSE("GPL"); |
195 | MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); | 501 | MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>"); |
196 | MODULE_DESCRIPTION("Generic NAND ECC support"); | 502 | MODULE_DESCRIPTION("Generic NAND ECC support"); |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 556e8131ecdc..ae7c57781a68 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/list.h> | 39 | #include <linux/list.h> |
40 | #include <linux/random.h> | 40 | #include <linux/random.h> |
41 | #include <asm/div64.h> | ||
42 | 41 | ||
43 | /* Default simulator parameters values */ | 42 | /* Default simulator parameters values */ |
44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 43 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c deleted file mode 100644 index bbf492e6830d..000000000000 --- a/drivers/mtd/nand/toto.c +++ /dev/null | |||
@@ -1,206 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/mtd/nand/toto.c | ||
3 | * | ||
4 | * Copyright (c) 2003 Texas Instruments | ||
5 | * | ||
6 | * Derived from drivers/mtd/autcpu12.c | ||
7 | * | ||
8 | * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * Overview: | ||
15 | * This is a device driver for the NAND flash device found on the | ||
16 | * TI fido board. It supports 32MiB and 64MiB cards | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/mtd/mtd.h> | ||
24 | #include <linux/mtd/nand.h> | ||
25 | #include <linux/mtd/partitions.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <asm/arch/hardware.h> | ||
28 | #include <asm/sizes.h> | ||
29 | #include <asm/arch/toto.h> | ||
30 | #include <asm/arch-omap1510/hardware.h> | ||
31 | #include <asm/arch/gpio.h> | ||
32 | |||
33 | #define CONFIG_NAND_WORKAROUND 1 | ||
34 | |||
35 | /* | ||
36 | * MTD structure for TOTO board | ||
37 | */ | ||
38 | static struct mtd_info *toto_mtd = NULL; | ||
39 | |||
40 | static unsigned long toto_io_base = OMAP_FLASH_1_BASE; | ||
41 | |||
42 | /* | ||
43 | * Define partitions for flash devices | ||
44 | */ | ||
45 | |||
46 | static struct mtd_partition partition_info64M[] = { | ||
47 | { .name = "toto kernel partition 1", | ||
48 | .offset = 0, | ||
49 | .size = 2 * SZ_1M }, | ||
50 | { .name = "toto file sys partition 2", | ||
51 | .offset = 2 * SZ_1M, | ||
52 | .size = 14 * SZ_1M }, | ||
53 | { .name = "toto user partition 3", | ||
54 | .offset = 16 * SZ_1M, | ||
55 | .size = 16 * SZ_1M }, | ||
56 | { .name = "toto devboard extra partition 4", | ||
57 | .offset = 32 * SZ_1M, | ||
58 | .size = 32 * SZ_1M }, | ||
59 | }; | ||
60 | |||
61 | static struct mtd_partition partition_info32M[] = { | ||
62 | { .name = "toto kernel partition 1", | ||
63 | .offset = 0, | ||
64 | .size = 2 * SZ_1M }, | ||
65 | { .name = "toto file sys partition 2", | ||
66 | .offset = 2 * SZ_1M, | ||
67 | .size = 14 * SZ_1M }, | ||
68 | { .name = "toto user partition 3", | ||
69 | .offset = 16 * SZ_1M, | ||
70 | .size = 16 * SZ_1M }, | ||
71 | }; | ||
72 | |||
73 | #define NUM_PARTITIONS32M 3 | ||
74 | #define NUM_PARTITIONS64M 4 | ||
75 | |||
76 | /* | ||
77 | * hardware specific access to control-lines | ||
78 | * | ||
79 | * ctrl: | ||
80 | * NAND_NCE: bit 0 -> bit 14 (0x4000) | ||
81 | * NAND_CLE: bit 1 -> bit 12 (0x1000) | ||
82 | * NAND_ALE: bit 2 -> bit 1 (0x0002) | ||
83 | */ | ||
84 | static void toto_hwcontrol(struct mtd_info *mtd, int cmd, | ||
85 | unsigned int ctrl) | ||
86 | { | ||
87 | struct nand_chip *chip = mtd->priv; | ||
88 | |||
89 | if (ctrl & NAND_CTRL_CHANGE) { | ||
90 | unsigned long bits; | ||
91 | |||
92 | /* hopefully enough time for tc make proceding write to clear */ | ||
93 | udelay(1); | ||
94 | |||
95 | bits = (~ctrl & NAND_NCE) << 14; | ||
96 | bits |= (ctrl & NAND_CLE) << 12; | ||
97 | bits |= (ctrl & NAND_ALE) >> 1; | ||
98 | |||
99 | #warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx | ||
100 | gpiosetout(0x5002, bits); | ||
101 | |||
102 | #ifdef CONFIG_NAND_WORKAROUND | ||
103 | /* "some" dev boards busted, blue wired to rts2 :( */ | ||
104 | rts2setout(2, (ctrl & NAND_CLE) << 1); | ||
105 | #endif | ||
106 | /* allow time to ensure gpio state to over take memory write */ | ||
107 | udelay(1); | ||
108 | } | ||
109 | |||
110 | if (cmd != NAND_CMD_NONE) | ||
111 | writeb(cmd, chip->IO_ADDR_W); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Main initialization routine | ||
116 | */ | ||
117 | static int __init toto_init(void) | ||
118 | { | ||
119 | struct nand_chip *this; | ||
120 | int err = 0; | ||
121 | |||
122 | /* Allocate memory for MTD device structure and private data */ | ||
123 | toto_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | ||
124 | if (!toto_mtd) { | ||
125 | printk(KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); | ||
126 | err = -ENOMEM; | ||
127 | goto out; | ||
128 | } | ||
129 | |||
130 | /* Get pointer to private data */ | ||
131 | this = (struct nand_chip *)(&toto_mtd[1]); | ||
132 | |||
133 | /* Initialize structures */ | ||
134 | memset(toto_mtd, 0, sizeof(struct mtd_info)); | ||
135 | memset(this, 0, sizeof(struct nand_chip)); | ||
136 | |||
137 | /* Link the private data with the MTD structure */ | ||
138 | toto_mtd->priv = this; | ||
139 | toto_mtd->owner = THIS_MODULE; | ||
140 | |||
141 | /* Set address of NAND IO lines */ | ||
142 | this->IO_ADDR_R = toto_io_base; | ||
143 | this->IO_ADDR_W = toto_io_base; | ||
144 | this->cmd_ctrl = toto_hwcontrol; | ||
145 | this->dev_ready = NULL; | ||
146 | /* 25 us command delay time */ | ||
147 | this->chip_delay = 30; | ||
148 | this->ecc.mode = NAND_ECC_SOFT; | ||
149 | |||
150 | /* Scan to find existance of the device */ | ||
151 | if (nand_scan(toto_mtd, 1)) { | ||
152 | err = -ENXIO; | ||
153 | goto out_mtd; | ||
154 | } | ||
155 | |||
156 | /* Register the partitions */ | ||
157 | switch (toto_mtd->size) { | ||
158 | case SZ_64M: | ||
159 | add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); | ||
160 | break; | ||
161 | case SZ_32M: | ||
162 | add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); | ||
163 | break; | ||
164 | default:{ | ||
165 | printk(KERN_WARNING "Unsupported Nand device\n"); | ||
166 | err = -ENXIO; | ||
167 | goto out_buf; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | gpioreserve(NAND_MASK); /* claim our gpios */ | ||
172 | archflashwp(0, 0); /* open up flash for writing */ | ||
173 | |||
174 | goto out; | ||
175 | |||
176 | out_mtd: | ||
177 | kfree(toto_mtd); | ||
178 | out: | ||
179 | return err; | ||
180 | } | ||
181 | |||
182 | module_init(toto_init); | ||
183 | |||
184 | /* | ||
185 | * Clean up routine | ||
186 | */ | ||
187 | static void __exit toto_cleanup(void) | ||
188 | { | ||
189 | /* Release resources, unregister device */ | ||
190 | nand_release(toto_mtd); | ||
191 | |||
192 | /* Free the MTD device structure */ | ||
193 | kfree(toto_mtd); | ||
194 | |||
195 | /* stop flash writes */ | ||
196 | archflashwp(0, 1); | ||
197 | |||
198 | /* release gpios to system */ | ||
199 | gpiorelease(NAND_MASK); | ||
200 | } | ||
201 | |||
202 | module_exit(toto_cleanup); | ||
203 | |||
204 | MODULE_LICENSE("GPL"); | ||
205 | MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>"); | ||
206 | MODULE_DESCRIPTION("Glue layer for NAND flash on toto board"); | ||
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index cb41cbca64f7..79fa79e8f8de 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -27,8 +27,16 @@ config MTD_ONENAND_GENERIC | |||
27 | help | 27 | help |
28 | Support for OneNAND flash via platform device driver. | 28 | Support for OneNAND flash via platform device driver. |
29 | 29 | ||
30 | config MTD_ONENAND_OMAP2 | ||
31 | tristate "OneNAND on OMAP2/OMAP3 support" | ||
32 | depends on MTD_ONENAND && (ARCH_OMAP2 || ARCH_OMAP3) | ||
33 | help | ||
34 | Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU | ||
35 | via the GPMC memory controller. | ||
36 | |||
30 | config MTD_ONENAND_OTP | 37 | config MTD_ONENAND_OTP |
31 | bool "OneNAND OTP Support" | 38 | bool "OneNAND OTP Support" |
39 | select HAVE_MTD_OTP | ||
32 | help | 40 | help |
33 | One Block of the NAND Flash Array memory is reserved as | 41 | One Block of the NAND Flash Array memory is reserved as |
34 | a One-Time Programmable Block memory area. | 42 | a One-Time Programmable Block memory area. |
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index 4d2eacfd7e11..64b6cc61a520 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile | |||
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o | |||
7 | 7 | ||
8 | # Board specific. | 8 | # Board specific. |
9 | obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o | 9 | obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o |
10 | obj-$(CONFIG_MTD_ONENAND_OMAP2) += omap2.o | ||
10 | 11 | ||
11 | # Simulator | 12 | # Simulator |
12 | obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o | 13 | obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o |
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c new file mode 100644 index 000000000000..34b42533f4bb --- /dev/null +++ b/drivers/mtd/onenand/omap2.c | |||
@@ -0,0 +1,782 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/onenand/omap2.c | ||
3 | * | ||
4 | * OneNAND driver for OMAP2 / OMAP3 | ||
5 | * | ||
6 | * Copyright © 2005-2006 Nokia Corporation | ||
7 | * | ||
8 | * Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and Juha Yrjölä | ||
9 | * IRQ and DMA support written by Timo Teras | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License version 2 as published by | ||
13 | * the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along with | ||
21 | * this program; see the file COPYING. If not, write to the Free Software | ||
22 | * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/device.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/mtd/mtd.h> | ||
30 | #include <linux/mtd/onenand.h> | ||
31 | #include <linux/mtd/partitions.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/delay.h> | ||
35 | |||
36 | #include <asm/io.h> | ||
37 | #include <asm/mach/flash.h> | ||
38 | #include <asm/arch/gpmc.h> | ||
39 | #include <asm/arch/onenand.h> | ||
40 | #include <asm/arch/gpio.h> | ||
41 | #include <asm/arch/gpmc.h> | ||
42 | #include <asm/arch/pm.h> | ||
43 | |||
44 | #include <linux/dma-mapping.h> | ||
45 | #include <asm/dma-mapping.h> | ||
46 | #include <asm/arch/dma.h> | ||
47 | |||
48 | #include <asm/arch/board.h> | ||
49 | |||
50 | #define DRIVER_NAME "omap2-onenand" | ||
51 | |||
52 | #define ONENAND_IO_SIZE SZ_128K | ||
53 | #define ONENAND_BUFRAM_SIZE (1024 * 5) | ||
54 | |||
55 | struct omap2_onenand { | ||
56 | struct platform_device *pdev; | ||
57 | int gpmc_cs; | ||
58 | unsigned long phys_base; | ||
59 | int gpio_irq; | ||
60 | struct mtd_info mtd; | ||
61 | struct mtd_partition *parts; | ||
62 | struct onenand_chip onenand; | ||
63 | struct completion irq_done; | ||
64 | struct completion dma_done; | ||
65 | int dma_channel; | ||
66 | int freq; | ||
67 | int (*setup)(void __iomem *base, int freq); | ||
68 | }; | ||
69 | |||
70 | static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) | ||
71 | { | ||
72 | struct omap2_onenand *c = data; | ||
73 | |||
74 | complete(&c->dma_done); | ||
75 | } | ||
76 | |||
77 | static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id) | ||
78 | { | ||
79 | struct omap2_onenand *c = dev_id; | ||
80 | |||
81 | complete(&c->irq_done); | ||
82 | |||
83 | return IRQ_HANDLED; | ||
84 | } | ||
85 | |||
86 | static inline unsigned short read_reg(struct omap2_onenand *c, int reg) | ||
87 | { | ||
88 | return readw(c->onenand.base + reg); | ||
89 | } | ||
90 | |||
91 | static inline void write_reg(struct omap2_onenand *c, unsigned short value, | ||
92 | int reg) | ||
93 | { | ||
94 | writew(value, c->onenand.base + reg); | ||
95 | } | ||
96 | |||
97 | static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr) | ||
98 | { | ||
99 | printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n", | ||
100 | msg, state, ctrl, intr); | ||
101 | } | ||
102 | |||
103 | static void wait_warn(char *msg, int state, unsigned int ctrl, | ||
104 | unsigned int intr) | ||
105 | { | ||
106 | printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x " | ||
107 | "intr 0x%04x\n", msg, state, ctrl, intr); | ||
108 | } | ||
109 | |||
110 | static int omap2_onenand_wait(struct mtd_info *mtd, int state) | ||
111 | { | ||
112 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
113 | unsigned int intr = 0; | ||
114 | unsigned int ctrl; | ||
115 | unsigned long timeout; | ||
116 | u32 syscfg; | ||
117 | |||
118 | if (state == FL_RESETING) { | ||
119 | int i; | ||
120 | |||
121 | for (i = 0; i < 20; i++) { | ||
122 | udelay(1); | ||
123 | intr = read_reg(c, ONENAND_REG_INTERRUPT); | ||
124 | if (intr & ONENAND_INT_MASTER) | ||
125 | break; | ||
126 | } | ||
127 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | ||
128 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
129 | wait_err("controller error", state, ctrl, intr); | ||
130 | return -EIO; | ||
131 | } | ||
132 | if (!(intr & ONENAND_INT_RESET)) { | ||
133 | wait_err("timeout", state, ctrl, intr); | ||
134 | return -EIO; | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | if (state != FL_READING) { | ||
140 | int result; | ||
141 | |||
142 | /* Turn interrupts on */ | ||
143 | syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); | ||
144 | if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) { | ||
145 | syscfg |= ONENAND_SYS_CFG1_IOBE; | ||
146 | write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); | ||
147 | if (cpu_is_omap34xx()) | ||
148 | /* Add a delay to let GPIO settle */ | ||
149 | syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); | ||
150 | } | ||
151 | |||
152 | INIT_COMPLETION(c->irq_done); | ||
153 | if (c->gpio_irq) { | ||
154 | result = omap_get_gpio_datain(c->gpio_irq); | ||
155 | if (result == -1) { | ||
156 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | ||
157 | intr = read_reg(c, ONENAND_REG_INTERRUPT); | ||
158 | wait_err("gpio error", state, ctrl, intr); | ||
159 | return -EIO; | ||
160 | } | ||
161 | } else | ||
162 | result = 0; | ||
163 | if (result == 0) { | ||
164 | int retry_cnt = 0; | ||
165 | retry: | ||
166 | result = wait_for_completion_timeout(&c->irq_done, | ||
167 | msecs_to_jiffies(20)); | ||
168 | if (result == 0) { | ||
169 | /* Timeout after 20ms */ | ||
170 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | ||
171 | if (ctrl & ONENAND_CTRL_ONGO) { | ||
172 | /* | ||
173 | * The operation seems to be still going | ||
174 | * so give it some more time. | ||
175 | */ | ||
176 | retry_cnt += 1; | ||
177 | if (retry_cnt < 3) | ||
178 | goto retry; | ||
179 | intr = read_reg(c, | ||
180 | ONENAND_REG_INTERRUPT); | ||
181 | wait_err("timeout", state, ctrl, intr); | ||
182 | return -EIO; | ||
183 | } | ||
184 | intr = read_reg(c, ONENAND_REG_INTERRUPT); | ||
185 | if ((intr & ONENAND_INT_MASTER) == 0) | ||
186 | wait_warn("timeout", state, ctrl, intr); | ||
187 | } | ||
188 | } | ||
189 | } else { | ||
190 | /* Turn interrupts off */ | ||
191 | syscfg = read_reg(c, ONENAND_REG_SYS_CFG1); | ||
192 | syscfg &= ~ONENAND_SYS_CFG1_IOBE; | ||
193 | write_reg(c, syscfg, ONENAND_REG_SYS_CFG1); | ||
194 | |||
195 | timeout = jiffies + msecs_to_jiffies(20); | ||
196 | while (time_before(jiffies, timeout)) { | ||
197 | intr = read_reg(c, ONENAND_REG_INTERRUPT); | ||
198 | if (intr & ONENAND_INT_MASTER) | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | intr = read_reg(c, ONENAND_REG_INTERRUPT); | ||
204 | ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); | ||
205 | |||
206 | if (intr & ONENAND_INT_READ) { | ||
207 | int ecc = read_reg(c, ONENAND_REG_ECC_STATUS); | ||
208 | |||
209 | if (ecc) { | ||
210 | unsigned int addr1, addr8; | ||
211 | |||
212 | addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1); | ||
213 | addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8); | ||
214 | if (ecc & ONENAND_ECC_2BIT_ALL) { | ||
215 | printk(KERN_ERR "onenand_wait: ECC error = " | ||
216 | "0x%04x, addr1 %#x, addr8 %#x\n", | ||
217 | ecc, addr1, addr8); | ||
218 | mtd->ecc_stats.failed++; | ||
219 | return -EBADMSG; | ||
220 | } else if (ecc & ONENAND_ECC_1BIT_ALL) { | ||
221 | printk(KERN_NOTICE "onenand_wait: correctable " | ||
222 | "ECC error = 0x%04x, addr1 %#x, " | ||
223 | "addr8 %#x\n", ecc, addr1, addr8); | ||
224 | mtd->ecc_stats.corrected++; | ||
225 | } | ||
226 | } | ||
227 | } else if (state == FL_READING) { | ||
228 | wait_err("timeout", state, ctrl, intr); | ||
229 | return -EIO; | ||
230 | } | ||
231 | |||
232 | if (ctrl & ONENAND_CTRL_ERROR) { | ||
233 | wait_err("controller error", state, ctrl, intr); | ||
234 | if (ctrl & ONENAND_CTRL_LOCK) | ||
235 | printk(KERN_ERR "onenand_wait: " | ||
236 | "Device is write protected!!!\n"); | ||
237 | return -EIO; | ||
238 | } | ||
239 | |||
240 | if (ctrl & 0xFE9F) | ||
241 | wait_warn("unexpected controller status", state, ctrl, intr); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area) | ||
247 | { | ||
248 | struct onenand_chip *this = mtd->priv; | ||
249 | |||
250 | if (ONENAND_CURRENT_BUFFERRAM(this)) { | ||
251 | if (area == ONENAND_DATARAM) | ||
252 | return mtd->writesize; | ||
253 | if (area == ONENAND_SPARERAM) | ||
254 | return mtd->oobsize; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | #if defined(CONFIG_ARCH_OMAP3) || defined(MULTI_OMAP2) | ||
261 | |||
262 | static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
263 | unsigned char *buffer, int offset, | ||
264 | size_t count) | ||
265 | { | ||
266 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
267 | struct onenand_chip *this = mtd->priv; | ||
268 | dma_addr_t dma_src, dma_dst; | ||
269 | int bram_offset; | ||
270 | unsigned long timeout; | ||
271 | void *buf = (void *)buffer; | ||
272 | size_t xtra; | ||
273 | volatile unsigned *done; | ||
274 | |||
275 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | ||
276 | if (bram_offset & 3 || (size_t)buf & 3 || count < 384) | ||
277 | goto out_copy; | ||
278 | |||
279 | if (buf >= high_memory) { | ||
280 | struct page *p1; | ||
281 | |||
282 | if (((size_t)buf & PAGE_MASK) != | ||
283 | ((size_t)(buf + count - 1) & PAGE_MASK)) | ||
284 | goto out_copy; | ||
285 | p1 = vmalloc_to_page(buf); | ||
286 | if (!p1) | ||
287 | goto out_copy; | ||
288 | buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); | ||
289 | } | ||
290 | |||
291 | xtra = count & 3; | ||
292 | if (xtra) { | ||
293 | count -= xtra; | ||
294 | memcpy(buf + count, this->base + bram_offset + count, xtra); | ||
295 | } | ||
296 | |||
297 | dma_src = c->phys_base + bram_offset; | ||
298 | dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE); | ||
299 | if (dma_mapping_error(&c->pdev->dev, dma_dst)) { | ||
300 | dev_err(&c->pdev->dev, | ||
301 | "Couldn't DMA map a %d byte buffer\n", | ||
302 | count); | ||
303 | goto out_copy; | ||
304 | } | ||
305 | |||
306 | omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, | ||
307 | count >> 2, 1, 0, 0, 0); | ||
308 | omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
309 | dma_src, 0, 0); | ||
310 | omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
311 | dma_dst, 0, 0); | ||
312 | |||
313 | INIT_COMPLETION(c->dma_done); | ||
314 | omap_start_dma(c->dma_channel); | ||
315 | |||
316 | timeout = jiffies + msecs_to_jiffies(20); | ||
317 | done = &c->dma_done.done; | ||
318 | while (time_before(jiffies, timeout)) | ||
319 | if (*done) | ||
320 | break; | ||
321 | |||
322 | dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); | ||
323 | |||
324 | if (!*done) { | ||
325 | dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); | ||
326 | goto out_copy; | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | |||
331 | out_copy: | ||
332 | memcpy(buf, this->base + bram_offset, count); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
337 | const unsigned char *buffer, | ||
338 | int offset, size_t count) | ||
339 | { | ||
340 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
341 | struct onenand_chip *this = mtd->priv; | ||
342 | dma_addr_t dma_src, dma_dst; | ||
343 | int bram_offset; | ||
344 | unsigned long timeout; | ||
345 | void *buf = (void *)buffer; | ||
346 | volatile unsigned *done; | ||
347 | |||
348 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | ||
349 | if (bram_offset & 3 || (size_t)buf & 3 || count < 384) | ||
350 | goto out_copy; | ||
351 | |||
352 | /* panic_write() may be in an interrupt context */ | ||
353 | if (in_interrupt()) | ||
354 | goto out_copy; | ||
355 | |||
356 | if (buf >= high_memory) { | ||
357 | struct page *p1; | ||
358 | |||
359 | if (((size_t)buf & PAGE_MASK) != | ||
360 | ((size_t)(buf + count - 1) & PAGE_MASK)) | ||
361 | goto out_copy; | ||
362 | p1 = vmalloc_to_page(buf); | ||
363 | if (!p1) | ||
364 | goto out_copy; | ||
365 | buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK); | ||
366 | } | ||
367 | |||
368 | dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE); | ||
369 | dma_dst = c->phys_base + bram_offset; | ||
370 | if (dma_mapping_error(&c->pdev->dev, dma_dst)) { | ||
371 | dev_err(&c->pdev->dev, | ||
372 | "Couldn't DMA map a %d byte buffer\n", | ||
373 | count); | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, | ||
378 | count >> 2, 1, 0, 0, 0); | ||
379 | omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
380 | dma_src, 0, 0); | ||
381 | omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
382 | dma_dst, 0, 0); | ||
383 | |||
384 | INIT_COMPLETION(c->dma_done); | ||
385 | omap_start_dma(c->dma_channel); | ||
386 | |||
387 | timeout = jiffies + msecs_to_jiffies(20); | ||
388 | done = &c->dma_done.done; | ||
389 | while (time_before(jiffies, timeout)) | ||
390 | if (*done) | ||
391 | break; | ||
392 | |||
393 | dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); | ||
394 | |||
395 | if (!*done) { | ||
396 | dev_err(&c->pdev->dev, "timeout waiting for DMA\n"); | ||
397 | goto out_copy; | ||
398 | } | ||
399 | |||
400 | return 0; | ||
401 | |||
402 | out_copy: | ||
403 | memcpy(this->base + bram_offset, buf, count); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | #else | ||
408 | |||
409 | int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
410 | unsigned char *buffer, int offset, | ||
411 | size_t count); | ||
412 | |||
413 | int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
414 | const unsigned char *buffer, | ||
415 | int offset, size_t count); | ||
416 | |||
417 | #endif | ||
418 | |||
419 | #if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2) | ||
420 | |||
421 | static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
422 | unsigned char *buffer, int offset, | ||
423 | size_t count) | ||
424 | { | ||
425 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
426 | struct onenand_chip *this = mtd->priv; | ||
427 | dma_addr_t dma_src, dma_dst; | ||
428 | int bram_offset; | ||
429 | |||
430 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | ||
431 | /* DMA is not used. Revisit PM requirements before enabling it. */ | ||
432 | if (1 || (c->dma_channel < 0) || | ||
433 | ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || | ||
434 | (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { | ||
435 | memcpy(buffer, (__force void *)(this->base + bram_offset), | ||
436 | count); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | dma_src = c->phys_base + bram_offset; | ||
441 | dma_dst = dma_map_single(&c->pdev->dev, buffer, count, | ||
442 | DMA_FROM_DEVICE); | ||
443 | if (dma_mapping_error(&c->pdev->dev, dma_dst)) { | ||
444 | dev_err(&c->pdev->dev, | ||
445 | "Couldn't DMA map a %d byte buffer\n", | ||
446 | count); | ||
447 | return -1; | ||
448 | } | ||
449 | |||
450 | omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32, | ||
451 | count / 4, 1, 0, 0, 0); | ||
452 | omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
453 | dma_src, 0, 0); | ||
454 | omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
455 | dma_dst, 0, 0); | ||
456 | |||
457 | INIT_COMPLETION(c->dma_done); | ||
458 | omap_start_dma(c->dma_channel); | ||
459 | wait_for_completion(&c->dma_done); | ||
460 | |||
461 | dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
467 | const unsigned char *buffer, | ||
468 | int offset, size_t count) | ||
469 | { | ||
470 | struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); | ||
471 | struct onenand_chip *this = mtd->priv; | ||
472 | dma_addr_t dma_src, dma_dst; | ||
473 | int bram_offset; | ||
474 | |||
475 | bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset; | ||
476 | /* DMA is not used. Revisit PM requirements before enabling it. */ | ||
477 | if (1 || (c->dma_channel < 0) || | ||
478 | ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) || | ||
479 | (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) { | ||
480 | memcpy((__force void *)(this->base + bram_offset), buffer, | ||
481 | count); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count, | ||
486 | DMA_TO_DEVICE); | ||
487 | dma_dst = c->phys_base + bram_offset; | ||
488 | if (dma_mapping_error(&c->pdev->dev, dma_dst)) { | ||
489 | dev_err(&c->pdev->dev, | ||
490 | "Couldn't DMA map a %d byte buffer\n", | ||
491 | count); | ||
492 | return -1; | ||
493 | } | ||
494 | |||
495 | omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16, | ||
496 | count / 2, 1, 0, 0, 0); | ||
497 | omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
498 | dma_src, 0, 0); | ||
499 | omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC, | ||
500 | dma_dst, 0, 0); | ||
501 | |||
502 | INIT_COMPLETION(c->dma_done); | ||
503 | omap_start_dma(c->dma_channel); | ||
504 | wait_for_completion(&c->dma_done); | ||
505 | |||
506 | dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE); | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | #else | ||
512 | |||
513 | int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area, | ||
514 | unsigned char *buffer, int offset, | ||
515 | size_t count); | ||
516 | |||
517 | int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area, | ||
518 | const unsigned char *buffer, | ||
519 | int offset, size_t count); | ||
520 | |||
521 | #endif | ||
522 | |||
523 | static struct platform_driver omap2_onenand_driver; | ||
524 | |||
525 | static int __adjust_timing(struct device *dev, void *data) | ||
526 | { | ||
527 | int ret = 0; | ||
528 | struct omap2_onenand *c; | ||
529 | |||
530 | c = dev_get_drvdata(dev); | ||
531 | |||
532 | BUG_ON(c->setup == NULL); | ||
533 | |||
534 | /* DMA is not in use so this is all that is needed */ | ||
535 | /* Revisit for OMAP3! */ | ||
536 | ret = c->setup(c->onenand.base, c->freq); | ||
537 | |||
538 | return ret; | ||
539 | } | ||
540 | |||
541 | int omap2_onenand_rephase(void) | ||
542 | { | ||
543 | return driver_for_each_device(&omap2_onenand_driver.driver, NULL, | ||
544 | NULL, __adjust_timing); | ||
545 | } | ||
546 | |||
547 | static void __devexit omap2_onenand_shutdown(struct platform_device *pdev) | ||
548 | { | ||
549 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); | ||
550 | |||
551 | /* With certain content in the buffer RAM, the OMAP boot ROM code | ||
552 | * can recognize the flash chip incorrectly. Zero it out before | ||
553 | * soft reset. | ||
554 | */ | ||
555 | memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); | ||
556 | } | ||
557 | |||
558 | static int __devinit omap2_onenand_probe(struct platform_device *pdev) | ||
559 | { | ||
560 | struct omap_onenand_platform_data *pdata; | ||
561 | struct omap2_onenand *c; | ||
562 | int r; | ||
563 | |||
564 | pdata = pdev->dev.platform_data; | ||
565 | if (pdata == NULL) { | ||
566 | dev_err(&pdev->dev, "platform data missing\n"); | ||
567 | return -ENODEV; | ||
568 | } | ||
569 | |||
570 | c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL); | ||
571 | if (!c) | ||
572 | return -ENOMEM; | ||
573 | |||
574 | init_completion(&c->irq_done); | ||
575 | init_completion(&c->dma_done); | ||
576 | c->gpmc_cs = pdata->cs; | ||
577 | c->gpio_irq = pdata->gpio_irq; | ||
578 | c->dma_channel = pdata->dma_channel; | ||
579 | if (c->dma_channel < 0) { | ||
580 | /* if -1, don't use DMA */ | ||
581 | c->gpio_irq = 0; | ||
582 | } | ||
583 | |||
584 | r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base); | ||
585 | if (r < 0) { | ||
586 | dev_err(&pdev->dev, "Cannot request GPMC CS\n"); | ||
587 | goto err_kfree; | ||
588 | } | ||
589 | |||
590 | if (request_mem_region(c->phys_base, ONENAND_IO_SIZE, | ||
591 | pdev->dev.driver->name) == NULL) { | ||
592 | dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, " | ||
593 | "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE); | ||
594 | r = -EBUSY; | ||
595 | goto err_free_cs; | ||
596 | } | ||
597 | c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE); | ||
598 | if (c->onenand.base == NULL) { | ||
599 | r = -ENOMEM; | ||
600 | goto err_release_mem_region; | ||
601 | } | ||
602 | |||
603 | if (pdata->onenand_setup != NULL) { | ||
604 | r = pdata->onenand_setup(c->onenand.base, c->freq); | ||
605 | if (r < 0) { | ||
606 | dev_err(&pdev->dev, "Onenand platform setup failed: " | ||
607 | "%d\n", r); | ||
608 | goto err_iounmap; | ||
609 | } | ||
610 | c->setup = pdata->onenand_setup; | ||
611 | } | ||
612 | |||
613 | if (c->gpio_irq) { | ||
614 | if ((r = omap_request_gpio(c->gpio_irq)) < 0) { | ||
615 | dev_err(&pdev->dev, "Failed to request GPIO%d for " | ||
616 | "OneNAND\n", c->gpio_irq); | ||
617 | goto err_iounmap; | ||
618 | } | ||
619 | omap_set_gpio_direction(c->gpio_irq, 1); | ||
620 | |||
621 | if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq), | ||
622 | omap2_onenand_interrupt, IRQF_TRIGGER_RISING, | ||
623 | pdev->dev.driver->name, c)) < 0) | ||
624 | goto err_release_gpio; | ||
625 | } | ||
626 | |||
627 | if (c->dma_channel >= 0) { | ||
628 | r = omap_request_dma(0, pdev->dev.driver->name, | ||
629 | omap2_onenand_dma_cb, (void *) c, | ||
630 | &c->dma_channel); | ||
631 | if (r == 0) { | ||
632 | omap_set_dma_write_mode(c->dma_channel, | ||
633 | OMAP_DMA_WRITE_NON_POSTED); | ||
634 | omap_set_dma_src_data_pack(c->dma_channel, 1); | ||
635 | omap_set_dma_src_burst_mode(c->dma_channel, | ||
636 | OMAP_DMA_DATA_BURST_8); | ||
637 | omap_set_dma_dest_data_pack(c->dma_channel, 1); | ||
638 | omap_set_dma_dest_burst_mode(c->dma_channel, | ||
639 | OMAP_DMA_DATA_BURST_8); | ||
640 | } else { | ||
641 | dev_info(&pdev->dev, | ||
642 | "failed to allocate DMA for OneNAND, " | ||
643 | "using PIO instead\n"); | ||
644 | c->dma_channel = -1; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual " | ||
649 | "base %p\n", c->gpmc_cs, c->phys_base, | ||
650 | c->onenand.base); | ||
651 | |||
652 | c->pdev = pdev; | ||
653 | c->mtd.name = pdev->dev.bus_id; | ||
654 | c->mtd.priv = &c->onenand; | ||
655 | c->mtd.owner = THIS_MODULE; | ||
656 | |||
657 | if (c->dma_channel >= 0) { | ||
658 | struct onenand_chip *this = &c->onenand; | ||
659 | |||
660 | this->wait = omap2_onenand_wait; | ||
661 | if (cpu_is_omap34xx()) { | ||
662 | this->read_bufferram = omap3_onenand_read_bufferram; | ||
663 | this->write_bufferram = omap3_onenand_write_bufferram; | ||
664 | } else { | ||
665 | this->read_bufferram = omap2_onenand_read_bufferram; | ||
666 | this->write_bufferram = omap2_onenand_write_bufferram; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | if ((r = onenand_scan(&c->mtd, 1)) < 0) | ||
671 | goto err_release_dma; | ||
672 | |||
673 | switch ((c->onenand.version_id >> 4) & 0xf) { | ||
674 | case 0: | ||
675 | c->freq = 40; | ||
676 | break; | ||
677 | case 1: | ||
678 | c->freq = 54; | ||
679 | break; | ||
680 | case 2: | ||
681 | c->freq = 66; | ||
682 | break; | ||
683 | case 3: | ||
684 | c->freq = 83; | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | #ifdef CONFIG_MTD_PARTITIONS | ||
689 | if (pdata->parts != NULL) | ||
690 | r = add_mtd_partitions(&c->mtd, pdata->parts, | ||
691 | pdata->nr_parts); | ||
692 | else | ||
693 | #endif | ||
694 | r = add_mtd_device(&c->mtd); | ||
695 | if (r < 0) | ||
696 | goto err_release_onenand; | ||
697 | |||
698 | platform_set_drvdata(pdev, c); | ||
699 | |||
700 | return 0; | ||
701 | |||
702 | err_release_onenand: | ||
703 | onenand_release(&c->mtd); | ||
704 | err_release_dma: | ||
705 | if (c->dma_channel != -1) | ||
706 | omap_free_dma(c->dma_channel); | ||
707 | if (c->gpio_irq) | ||
708 | free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c); | ||
709 | err_release_gpio: | ||
710 | if (c->gpio_irq) | ||
711 | omap_free_gpio(c->gpio_irq); | ||
712 | err_iounmap: | ||
713 | iounmap(c->onenand.base); | ||
714 | err_release_mem_region: | ||
715 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); | ||
716 | err_free_cs: | ||
717 | gpmc_cs_free(c->gpmc_cs); | ||
718 | err_kfree: | ||
719 | kfree(c); | ||
720 | |||
721 | return r; | ||
722 | } | ||
723 | |||
724 | static int __devexit omap2_onenand_remove(struct platform_device *pdev) | ||
725 | { | ||
726 | struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); | ||
727 | |||
728 | BUG_ON(c == NULL); | ||
729 | |||
730 | #ifdef CONFIG_MTD_PARTITIONS | ||
731 | if (c->parts) | ||
732 | del_mtd_partitions(&c->mtd); | ||
733 | else | ||
734 | del_mtd_device(&c->mtd); | ||
735 | #else | ||
736 | del_mtd_device(&c->mtd); | ||
737 | #endif | ||
738 | |||
739 | onenand_release(&c->mtd); | ||
740 | if (c->dma_channel != -1) | ||
741 | omap_free_dma(c->dma_channel); | ||
742 | omap2_onenand_shutdown(pdev); | ||
743 | platform_set_drvdata(pdev, NULL); | ||
744 | if (c->gpio_irq) { | ||
745 | free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c); | ||
746 | omap_free_gpio(c->gpio_irq); | ||
747 | } | ||
748 | iounmap(c->onenand.base); | ||
749 | release_mem_region(c->phys_base, ONENAND_IO_SIZE); | ||
750 | kfree(c); | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static struct platform_driver omap2_onenand_driver = { | ||
756 | .probe = omap2_onenand_probe, | ||
757 | .remove = omap2_onenand_remove, | ||
758 | .shutdown = omap2_onenand_shutdown, | ||
759 | .driver = { | ||
760 | .name = DRIVER_NAME, | ||
761 | .owner = THIS_MODULE, | ||
762 | }, | ||
763 | }; | ||
764 | |||
765 | static int __init omap2_onenand_init(void) | ||
766 | { | ||
767 | printk(KERN_INFO "OneNAND driver initializing\n"); | ||
768 | return platform_driver_register(&omap2_onenand_driver); | ||
769 | } | ||
770 | |||
771 | static void __exit omap2_onenand_exit(void) | ||
772 | { | ||
773 | platform_driver_unregister(&omap2_onenand_driver); | ||
774 | } | ||
775 | |||
776 | module_init(omap2_onenand_init); | ||
777 | module_exit(omap2_onenand_exit); | ||
778 | |||
779 | MODULE_ALIAS(DRIVER_NAME); | ||
780 | MODULE_LICENSE("GPL"); | ||
781 | MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>"); | ||
782 | MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3"); | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 926cf3a4135d..90ed319f26e6 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -1794,7 +1794,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1794 | return -EINVAL; | 1794 | return -EINVAL; |
1795 | } | 1795 | } |
1796 | 1796 | ||
1797 | instr->fail_addr = 0xffffffff; | 1797 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
1798 | 1798 | ||
1799 | /* Grab the lock and see if the device is available */ | 1799 | /* Grab the lock and see if the device is available */ |
1800 | onenand_get_device(mtd, FL_ERASING); | 1800 | onenand_get_device(mtd, FL_ERASING); |
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index a5f3d60047d4..33a5d6ed6f18 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c | |||
@@ -321,8 +321,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
321 | DEBUG(MTD_DEBUG_LEVEL1, | 321 | DEBUG(MTD_DEBUG_LEVEL1, |
322 | "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", | 322 | "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", |
323 | ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, | 323 | ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, |
324 | (ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) / | 324 | DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); |
325 | MAX_PHYS_BLK_PER_ZONE); | ||
326 | 325 | ||
327 | /* Set geometry */ | 326 | /* Set geometry */ |
328 | ssfdc->heads = 16; | 327 | ssfdc->heads = 16; |
diff --git a/fs/Kconfig b/fs/Kconfig index abccb5dab9a8..b7c88e1f0161 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1136,195 +1136,7 @@ config EFS_FS | |||
1136 | To compile the EFS file system support as a module, choose M here: the | 1136 | To compile the EFS file system support as a module, choose M here: the |
1137 | module will be called efs. | 1137 | module will be called efs. |
1138 | 1138 | ||
1139 | config JFFS2_FS | 1139 | source "fs/jffs2/Kconfig" |
1140 | tristate "Journalling Flash File System v2 (JFFS2) support" | ||
1141 | select CRC32 | ||
1142 | depends on MTD | ||
1143 | help | ||
1144 | JFFS2 is the second generation of the Journalling Flash File System | ||
1145 | for use on diskless embedded devices. It provides improved wear | ||
1146 | levelling, compression and support for hard links. You cannot use | ||
1147 | this on normal block devices, only on 'MTD' devices. | ||
1148 | |||
1149 | Further information on the design and implementation of JFFS2 is | ||
1150 | available at <http://sources.redhat.com/jffs2/>. | ||
1151 | |||
1152 | config JFFS2_FS_DEBUG | ||
1153 | int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" | ||
1154 | depends on JFFS2_FS | ||
1155 | default "0" | ||
1156 | help | ||
1157 | This controls the amount of debugging messages produced by the JFFS2 | ||
1158 | code. Set it to zero for use in production systems. For evaluation, | ||
1159 | testing and debugging, it's advisable to set it to one. This will | ||
1160 | enable a few assertions and will print debugging messages at the | ||
1161 | KERN_DEBUG loglevel, where they won't normally be visible. Level 2 | ||
1162 | is unlikely to be useful - it enables extra debugging in certain | ||
1163 | areas which at one point needed debugging, but when the bugs were | ||
1164 | located and fixed, the detailed messages were relegated to level 2. | ||
1165 | |||
1166 | If reporting bugs, please try to have available a full dump of the | ||
1167 | messages at debug level 1 while the misbehaviour was occurring. | ||
1168 | |||
1169 | config JFFS2_FS_WRITEBUFFER | ||
1170 | bool "JFFS2 write-buffering support" | ||
1171 | depends on JFFS2_FS | ||
1172 | default y | ||
1173 | help | ||
1174 | This enables the write-buffering support in JFFS2. | ||
1175 | |||
1176 | This functionality is required to support JFFS2 on the following | ||
1177 | types of flash devices: | ||
1178 | - NAND flash | ||
1179 | - NOR flash with transparent ECC | ||
1180 | - DataFlash | ||
1181 | |||
1182 | config JFFS2_FS_WBUF_VERIFY | ||
1183 | bool "Verify JFFS2 write-buffer reads" | ||
1184 | depends on JFFS2_FS_WRITEBUFFER | ||
1185 | default n | ||
1186 | help | ||
1187 | This causes JFFS2 to read back every page written through the | ||
1188 | write-buffer, and check for errors. | ||
1189 | |||
1190 | config JFFS2_SUMMARY | ||
1191 | bool "JFFS2 summary support (EXPERIMENTAL)" | ||
1192 | depends on JFFS2_FS && EXPERIMENTAL | ||
1193 | default n | ||
1194 | help | ||
1195 | This feature makes it possible to use summary information | ||
1196 | for faster filesystem mount. | ||
1197 | |||
1198 | The summary information can be inserted into a filesystem image | ||
1199 | by the utility 'sumtool'. | ||
1200 | |||
1201 | If unsure, say 'N'. | ||
1202 | |||
1203 | config JFFS2_FS_XATTR | ||
1204 | bool "JFFS2 XATTR support (EXPERIMENTAL)" | ||
1205 | depends on JFFS2_FS && EXPERIMENTAL | ||
1206 | default n | ||
1207 | help | ||
1208 | Extended attributes are name:value pairs associated with inodes by | ||
1209 | the kernel or by users (see the attr(5) manual page, or visit | ||
1210 | <http://acl.bestbits.at/> for details). | ||
1211 | |||
1212 | If unsure, say N. | ||
1213 | |||
1214 | config JFFS2_FS_POSIX_ACL | ||
1215 | bool "JFFS2 POSIX Access Control Lists" | ||
1216 | depends on JFFS2_FS_XATTR | ||
1217 | default y | ||
1218 | select FS_POSIX_ACL | ||
1219 | help | ||
1220 | Posix Access Control Lists (ACLs) support permissions for users and | ||
1221 | groups beyond the owner/group/world scheme. | ||
1222 | |||
1223 | To learn more about Access Control Lists, visit the Posix ACLs for | ||
1224 | Linux website <http://acl.bestbits.at/>. | ||
1225 | |||
1226 | If you don't know what Access Control Lists are, say N | ||
1227 | |||
1228 | config JFFS2_FS_SECURITY | ||
1229 | bool "JFFS2 Security Labels" | ||
1230 | depends on JFFS2_FS_XATTR | ||
1231 | default y | ||
1232 | help | ||
1233 | Security labels support alternative access control models | ||
1234 | implemented by security modules like SELinux. This option | ||
1235 | enables an extended attribute handler for file security | ||
1236 | labels in the jffs2 filesystem. | ||
1237 | |||
1238 | If you are not using a security module that requires using | ||
1239 | extended attributes for file security labels, say N. | ||
1240 | |||
1241 | config JFFS2_COMPRESSION_OPTIONS | ||
1242 | bool "Advanced compression options for JFFS2" | ||
1243 | depends on JFFS2_FS | ||
1244 | default n | ||
1245 | help | ||
1246 | Enabling this option allows you to explicitly choose which | ||
1247 | compression modules, if any, are enabled in JFFS2. Removing | ||
1248 | compressors can mean you cannot read existing file systems, | ||
1249 | and enabling experimental compressors can mean that you | ||
1250 | write a file system which cannot be read by a standard kernel. | ||
1251 | |||
1252 | If unsure, you should _definitely_ say 'N'. | ||
1253 | |||
1254 | config JFFS2_ZLIB | ||
1255 | bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS | ||
1256 | select ZLIB_INFLATE | ||
1257 | select ZLIB_DEFLATE | ||
1258 | depends on JFFS2_FS | ||
1259 | default y | ||
1260 | help | ||
1261 | Zlib is designed to be a free, general-purpose, legally unencumbered, | ||
1262 | lossless data-compression library for use on virtually any computer | ||
1263 | hardware and operating system. See <http://www.gzip.org/zlib/> for | ||
1264 | further information. | ||
1265 | |||
1266 | Say 'Y' if unsure. | ||
1267 | |||
1268 | config JFFS2_LZO | ||
1269 | bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS | ||
1270 | select LZO_COMPRESS | ||
1271 | select LZO_DECOMPRESS | ||
1272 | depends on JFFS2_FS | ||
1273 | default n | ||
1274 | help | ||
1275 | minilzo-based compression. Generally works better than Zlib. | ||
1276 | |||
1277 | This feature was added in July, 2007. Say 'N' if you need | ||
1278 | compatibility with older bootloaders or kernels. | ||
1279 | |||
1280 | config JFFS2_RTIME | ||
1281 | bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS | ||
1282 | depends on JFFS2_FS | ||
1283 | default y | ||
1284 | help | ||
1285 | Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. | ||
1286 | |||
1287 | config JFFS2_RUBIN | ||
1288 | bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS | ||
1289 | depends on JFFS2_FS | ||
1290 | default n | ||
1291 | help | ||
1292 | RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. | ||
1293 | |||
1294 | choice | ||
1295 | prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS | ||
1296 | default JFFS2_CMODE_PRIORITY | ||
1297 | depends on JFFS2_FS | ||
1298 | help | ||
1299 | You can set here the default compression mode of JFFS2 from | ||
1300 | the available compression modes. Don't touch if unsure. | ||
1301 | |||
1302 | config JFFS2_CMODE_NONE | ||
1303 | bool "no compression" | ||
1304 | help | ||
1305 | Uses no compression. | ||
1306 | |||
1307 | config JFFS2_CMODE_PRIORITY | ||
1308 | bool "priority" | ||
1309 | help | ||
1310 | Tries the compressors in a predefined order and chooses the first | ||
1311 | successful one. | ||
1312 | |||
1313 | config JFFS2_CMODE_SIZE | ||
1314 | bool "size (EXPERIMENTAL)" | ||
1315 | help | ||
1316 | Tries all compressors and chooses the one which has the smallest | ||
1317 | result. | ||
1318 | |||
1319 | config JFFS2_CMODE_FAVOURLZO | ||
1320 | bool "Favour LZO" | ||
1321 | help | ||
1322 | Tries all compressors and chooses the one which has the smallest | ||
1323 | result but gives some preference to LZO (which has faster | ||
1324 | decompression) at the expense of size. | ||
1325 | |||
1326 | endchoice | ||
1327 | |||
1328 | # UBIFS File system configuration | 1140 | # UBIFS File system configuration |
1329 | source "fs/ubifs/Kconfig" | 1141 | source "fs/ubifs/Kconfig" |
1330 | 1142 | ||
diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig new file mode 100644 index 000000000000..6ae169cd8faa --- /dev/null +++ b/fs/jffs2/Kconfig | |||
@@ -0,0 +1,188 @@ | |||
1 | config JFFS2_FS | ||
2 | tristate "Journalling Flash File System v2 (JFFS2) support" | ||
3 | select CRC32 | ||
4 | depends on MTD | ||
5 | help | ||
6 | JFFS2 is the second generation of the Journalling Flash File System | ||
7 | for use on diskless embedded devices. It provides improved wear | ||
8 | levelling, compression and support for hard links. You cannot use | ||
9 | this on normal block devices, only on 'MTD' devices. | ||
10 | |||
11 | Further information on the design and implementation of JFFS2 is | ||
12 | available at <http://sources.redhat.com/jffs2/>. | ||
13 | |||
14 | config JFFS2_FS_DEBUG | ||
15 | int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" | ||
16 | depends on JFFS2_FS | ||
17 | default "0" | ||
18 | help | ||
19 | This controls the amount of debugging messages produced by the JFFS2 | ||
20 | code. Set it to zero for use in production systems. For evaluation, | ||
21 | testing and debugging, it's advisable to set it to one. This will | ||
22 | enable a few assertions and will print debugging messages at the | ||
23 | KERN_DEBUG loglevel, where they won't normally be visible. Level 2 | ||
24 | is unlikely to be useful - it enables extra debugging in certain | ||
25 | areas which at one point needed debugging, but when the bugs were | ||
26 | located and fixed, the detailed messages were relegated to level 2. | ||
27 | |||
28 | If reporting bugs, please try to have available a full dump of the | ||
29 | messages at debug level 1 while the misbehaviour was occurring. | ||
30 | |||
31 | config JFFS2_FS_WRITEBUFFER | ||
32 | bool "JFFS2 write-buffering support" | ||
33 | depends on JFFS2_FS | ||
34 | default y | ||
35 | help | ||
36 | This enables the write-buffering support in JFFS2. | ||
37 | |||
38 | This functionality is required to support JFFS2 on the following | ||
39 | types of flash devices: | ||
40 | - NAND flash | ||
41 | - NOR flash with transparent ECC | ||
42 | - DataFlash | ||
43 | |||
44 | config JFFS2_FS_WBUF_VERIFY | ||
45 | bool "Verify JFFS2 write-buffer reads" | ||
46 | depends on JFFS2_FS_WRITEBUFFER | ||
47 | default n | ||
48 | help | ||
49 | This causes JFFS2 to read back every page written through the | ||
50 | write-buffer, and check for errors. | ||
51 | |||
52 | config JFFS2_SUMMARY | ||
53 | bool "JFFS2 summary support (EXPERIMENTAL)" | ||
54 | depends on JFFS2_FS && EXPERIMENTAL | ||
55 | default n | ||
56 | help | ||
57 | This feature makes it possible to use summary information | ||
58 | for faster filesystem mount. | ||
59 | |||
60 | The summary information can be inserted into a filesystem image | ||
61 | by the utility 'sumtool'. | ||
62 | |||
63 | If unsure, say 'N'. | ||
64 | |||
65 | config JFFS2_FS_XATTR | ||
66 | bool "JFFS2 XATTR support (EXPERIMENTAL)" | ||
67 | depends on JFFS2_FS && EXPERIMENTAL | ||
68 | default n | ||
69 | help | ||
70 | Extended attributes are name:value pairs associated with inodes by | ||
71 | the kernel or by users (see the attr(5) manual page, or visit | ||
72 | <http://acl.bestbits.at/> for details). | ||
73 | |||
74 | If unsure, say N. | ||
75 | |||
76 | config JFFS2_FS_POSIX_ACL | ||
77 | bool "JFFS2 POSIX Access Control Lists" | ||
78 | depends on JFFS2_FS_XATTR | ||
79 | default y | ||
80 | select FS_POSIX_ACL | ||
81 | help | ||
82 | Posix Access Control Lists (ACLs) support permissions for users and | ||
83 | groups beyond the owner/group/world scheme. | ||
84 | |||
85 | To learn more about Access Control Lists, visit the Posix ACLs for | ||
86 | Linux website <http://acl.bestbits.at/>. | ||
87 | |||
88 | If you don't know what Access Control Lists are, say N | ||
89 | |||
90 | config JFFS2_FS_SECURITY | ||
91 | bool "JFFS2 Security Labels" | ||
92 | depends on JFFS2_FS_XATTR | ||
93 | default y | ||
94 | help | ||
95 | Security labels support alternative access control models | ||
96 | implemented by security modules like SELinux. This option | ||
97 | enables an extended attribute handler for file security | ||
98 | labels in the jffs2 filesystem. | ||
99 | |||
100 | If you are not using a security module that requires using | ||
101 | extended attributes for file security labels, say N. | ||
102 | |||
103 | config JFFS2_COMPRESSION_OPTIONS | ||
104 | bool "Advanced compression options for JFFS2" | ||
105 | depends on JFFS2_FS | ||
106 | default n | ||
107 | help | ||
108 | Enabling this option allows you to explicitly choose which | ||
109 | compression modules, if any, are enabled in JFFS2. Removing | ||
110 | compressors can mean you cannot read existing file systems, | ||
111 | and enabling experimental compressors can mean that you | ||
112 | write a file system which cannot be read by a standard kernel. | ||
113 | |||
114 | If unsure, you should _definitely_ say 'N'. | ||
115 | |||
116 | config JFFS2_ZLIB | ||
117 | bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS | ||
118 | select ZLIB_INFLATE | ||
119 | select ZLIB_DEFLATE | ||
120 | depends on JFFS2_FS | ||
121 | default y | ||
122 | help | ||
123 | Zlib is designed to be a free, general-purpose, legally unencumbered, | ||
124 | lossless data-compression library for use on virtually any computer | ||
125 | hardware and operating system. See <http://www.gzip.org/zlib/> for | ||
126 | further information. | ||
127 | |||
128 | Say 'Y' if unsure. | ||
129 | |||
130 | config JFFS2_LZO | ||
131 | bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS | ||
132 | select LZO_COMPRESS | ||
133 | select LZO_DECOMPRESS | ||
134 | depends on JFFS2_FS | ||
135 | default n | ||
136 | help | ||
137 | minilzo-based compression. Generally works better than Zlib. | ||
138 | |||
139 | This feature was added in July, 2007. Say 'N' if you need | ||
140 | compatibility with older bootloaders or kernels. | ||
141 | |||
142 | config JFFS2_RTIME | ||
143 | bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS | ||
144 | depends on JFFS2_FS | ||
145 | default y | ||
146 | help | ||
147 | Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. | ||
148 | |||
149 | config JFFS2_RUBIN | ||
150 | bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS | ||
151 | depends on JFFS2_FS | ||
152 | default n | ||
153 | help | ||
154 | RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. | ||
155 | |||
156 | choice | ||
157 | prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS | ||
158 | default JFFS2_CMODE_PRIORITY | ||
159 | depends on JFFS2_FS | ||
160 | help | ||
161 | You can set here the default compression mode of JFFS2 from | ||
162 | the available compression modes. Don't touch if unsure. | ||
163 | |||
164 | config JFFS2_CMODE_NONE | ||
165 | bool "no compression" | ||
166 | help | ||
167 | Uses no compression. | ||
168 | |||
169 | config JFFS2_CMODE_PRIORITY | ||
170 | bool "priority" | ||
171 | help | ||
172 | Tries the compressors in a predefined order and chooses the first | ||
173 | successful one. | ||
174 | |||
175 | config JFFS2_CMODE_SIZE | ||
176 | bool "size (EXPERIMENTAL)" | ||
177 | help | ||
178 | Tries all compressors and chooses the one which has the smallest | ||
179 | result. | ||
180 | |||
181 | config JFFS2_CMODE_FAVOURLZO | ||
182 | bool "Favour LZO" | ||
183 | help | ||
184 | Tries all compressors and chooses the one which has the smallest | ||
185 | result but gives some preference to LZO (which has faster | ||
186 | decompression) at the expense of size. | ||
187 | |||
188 | endchoice | ||
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index cd219ef55254..b1aaae823a52 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -311,7 +311,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
311 | /* FIXME: If you care. We'd need to use frags for the target | 311 | /* FIXME: If you care. We'd need to use frags for the target |
312 | if it grows much more than this */ | 312 | if it grows much more than this */ |
313 | if (targetlen > 254) | 313 | if (targetlen > 254) |
314 | return -EINVAL; | 314 | return -ENAMETOOLONG; |
315 | 315 | ||
316 | ri = jffs2_alloc_raw_inode(); | 316 | ri = jffs2_alloc_raw_inode(); |
317 | 317 | ||
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index dddb2a6c9e2c..259461b910af 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -68,7 +68,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
68 | instr->len = c->sector_size; | 68 | instr->len = c->sector_size; |
69 | instr->callback = jffs2_erase_callback; | 69 | instr->callback = jffs2_erase_callback; |
70 | instr->priv = (unsigned long)(&instr[1]); | 70 | instr->priv = (unsigned long)(&instr[1]); |
71 | instr->fail_addr = 0xffffffff; | 71 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
72 | 72 | ||
73 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; | 73 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; |
74 | ((struct erase_priv_struct *)instr->priv)->c = c; | 74 | ((struct erase_priv_struct *)instr->priv)->c = c; |
@@ -175,7 +175,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
175 | { | 175 | { |
176 | /* For NAND, if the failure did not occur at the device level for a | 176 | /* For NAND, if the failure did not occur at the device level for a |
177 | specific physical page, don't bother updating the bad block table. */ | 177 | specific physical page, don't bother updating the bad block table. */ |
178 | if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) { | 178 | if (jffs2_cleanmarker_oob(c) && (bad_offset != MTD_FAIL_ADDR_UNKNOWN)) { |
179 | /* We had a device-level failure to erase. Let's see if we've | 179 | /* We had a device-level failure to erase. Let's see if we've |
180 | failed too many times. */ | 180 | failed too many times. */ |
181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 086c43830221..89e9b735d8df 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -207,6 +207,8 @@ int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
207 | buf->f_files = 0; | 207 | buf->f_files = 0; |
208 | buf->f_ffree = 0; | 208 | buf->f_ffree = 0; |
209 | buf->f_namelen = JFFS2_MAX_NAME_LEN; | 209 | buf->f_namelen = JFFS2_MAX_NAME_LEN; |
210 | buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; | ||
211 | buf->f_fsid.val[1] = c->mtd->index; | ||
210 | 212 | ||
211 | spin_lock(&c->erase_completion_lock); | 213 | spin_lock(&c->erase_completion_lock); |
212 | avail = c->dirty_size + c->free_size; | 214 | avail = c->dirty_size + c->free_size; |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index d6fb115f5a07..ee5124ec319e 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/mtd/flashchip.h> | 12 | #include <linux/mtd/flashchip.h> |
13 | #include <linux/mtd/map.h> | 13 | #include <linux/mtd/map.h> |
14 | #include <linux/mtd/cfi_endian.h> | 14 | #include <linux/mtd/cfi_endian.h> |
15 | #include <linux/mtd/xip.h> | ||
15 | 16 | ||
16 | #ifdef CONFIG_MTD_CFI_I1 | 17 | #ifdef CONFIG_MTD_CFI_I1 |
17 | #define cfi_interleave(cfi) 1 | 18 | #define cfi_interleave(cfi) 1 |
@@ -430,7 +431,6 @@ static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t | |||
430 | { | 431 | { |
431 | map_word val; | 432 | map_word val; |
432 | uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); | 433 | uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); |
433 | |||
434 | val = cfi_build_cmd(cmd, map, cfi); | 434 | val = cfi_build_cmd(cmd, map, cfi); |
435 | 435 | ||
436 | if (prev_val) | 436 | if (prev_val) |
@@ -483,6 +483,13 @@ static inline void cfi_udelay(int us) | |||
483 | } | 483 | } |
484 | } | 484 | } |
485 | 485 | ||
486 | int __xipram cfi_qry_present(struct map_info *map, __u32 base, | ||
487 | struct cfi_private *cfi); | ||
488 | int __xipram cfi_qry_mode_on(uint32_t base, struct map_info *map, | ||
489 | struct cfi_private *cfi); | ||
490 | void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map, | ||
491 | struct cfi_private *cfi); | ||
492 | |||
486 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, | 493 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, |
487 | const char* name); | 494 | const char* name); |
488 | struct cfi_fixup { | 495 | struct cfi_fixup { |
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index 08dd131301c1..d4f38c5fd44e 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h | |||
@@ -73,6 +73,10 @@ struct flchip { | |||
73 | int buffer_write_time; | 73 | int buffer_write_time; |
74 | int erase_time; | 74 | int erase_time; |
75 | 75 | ||
76 | int word_write_time_max; | ||
77 | int buffer_write_time_max; | ||
78 | int erase_time_max; | ||
79 | |||
76 | void *priv; | 80 | void *priv; |
77 | }; | 81 | }; |
78 | 82 | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 922636548558..eae26bb6430a 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -25,8 +25,10 @@ | |||
25 | #define MTD_ERASE_DONE 0x08 | 25 | #define MTD_ERASE_DONE 0x08 |
26 | #define MTD_ERASE_FAILED 0x10 | 26 | #define MTD_ERASE_FAILED 0x10 |
27 | 27 | ||
28 | #define MTD_FAIL_ADDR_UNKNOWN 0xffffffff | ||
29 | |||
28 | /* If the erase fails, fail_addr might indicate exactly which block failed. If | 30 | /* If the erase fails, fail_addr might indicate exactly which block failed. If |
29 | fail_addr = 0xffffffff, the failure was not at the device level or was not | 31 | fail_addr = MTD_FAIL_ADDR_UNKNOWN, the failure was not at the device level or was not |
30 | specific to any particular block. */ | 32 | specific to any particular block. */ |
31 | struct erase_info { | 33 | struct erase_info { |
32 | struct mtd_info *mtd; | 34 | struct mtd_info *mtd; |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 81774e5facf4..733d3f3b4eb8 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -248,6 +248,7 @@ struct nand_hw_control { | |||
248 | * @read_page_raw: function to read a raw page without ECC | 248 | * @read_page_raw: function to read a raw page without ECC |
249 | * @write_page_raw: function to write a raw page without ECC | 249 | * @write_page_raw: function to write a raw page without ECC |
250 | * @read_page: function to read a page according to the ecc generator requirements | 250 | * @read_page: function to read a page according to the ecc generator requirements |
251 | * @read_subpage: function to read parts of the page covered by ECC. | ||
251 | * @write_page: function to write a page according to the ecc generator requirements | 252 | * @write_page: function to write a page according to the ecc generator requirements |
252 | * @read_oob: function to read chip OOB data | 253 | * @read_oob: function to read chip OOB data |
253 | * @write_oob: function to write chip OOB data | 254 | * @write_oob: function to write chip OOB data |
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index d1b310c92eb4..0c6bbe28f38c 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h | |||
@@ -152,6 +152,8 @@ | |||
152 | #define ONENAND_SYS_CFG1_INT (1 << 6) | 152 | #define ONENAND_SYS_CFG1_INT (1 << 6) |
153 | #define ONENAND_SYS_CFG1_IOBE (1 << 5) | 153 | #define ONENAND_SYS_CFG1_IOBE (1 << 5) |
154 | #define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) | 154 | #define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) |
155 | #define ONENAND_SYS_CFG1_HF (1 << 2) | ||
156 | #define ONENAND_SYS_CFG1_SYNC_WRITE (1 << 1) | ||
155 | 157 | ||
156 | /* | 158 | /* |
157 | * Controller Status Register F240h (R) | 159 | * Controller Status Register F240h (R) |