diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/mtd/chips/jedec.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/mtd/chips/jedec.c')
-rw-r--r-- | drivers/mtd/chips/jedec.c | 934 |
1 files changed, 934 insertions, 0 deletions
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c new file mode 100644 index 000000000000..62d235a9a4e2 --- /dev/null +++ b/drivers/mtd/chips/jedec.c | |||
@@ -0,0 +1,934 @@ | |||
1 | |||
2 | /* JEDEC Flash Interface. | ||
3 | * This is an older type of interface for self programming flash. It is | ||
4 | * commonly use in older AMD chips and is obsolete compared with CFI. | ||
5 | * It is called JEDEC because the JEDEC association distributes the ID codes | ||
6 | * for the chips. | ||
7 | * | ||
8 | * See the AMD flash databook for information on how to operate the interface. | ||
9 | * | ||
10 | * This code does not support anything wider than 8 bit flash chips, I am | ||
11 | * not going to guess how to send commands to them, plus I expect they will | ||
12 | * all speak CFI.. | ||
13 | * | ||
14 | * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $ | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/mtd/jedec.h> | ||
21 | #include <linux/mtd/map.h> | ||
22 | #include <linux/mtd/mtd.h> | ||
23 | #include <linux/mtd/compatmac.h> | ||
24 | |||
25 | static struct mtd_info *jedec_probe(struct map_info *); | ||
26 | static int jedec_probe8(struct map_info *map,unsigned long base, | ||
27 | struct jedec_private *priv); | ||
28 | static int jedec_probe16(struct map_info *map,unsigned long base, | ||
29 | struct jedec_private *priv); | ||
30 | static int jedec_probe32(struct map_info *map,unsigned long base, | ||
31 | struct jedec_private *priv); | ||
32 | static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start, | ||
33 | unsigned long len); | ||
34 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr); | ||
35 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | ||
36 | size_t *retlen, const u_char *buf); | ||
37 | |||
38 | static unsigned long my_bank_size; | ||
39 | |||
40 | /* Listing of parts and sizes. We need this table to learn the sector | ||
41 | size of the chip and the total length */ | ||
42 | static const struct JEDECTable JEDEC_table[] = { | ||
43 | { | ||
44 | .jedec = 0x013D, | ||
45 | .name = "AMD Am29F017D", | ||
46 | .size = 2*1024*1024, | ||
47 | .sectorsize = 64*1024, | ||
48 | .capabilities = MTD_CAP_NORFLASH | ||
49 | }, | ||
50 | { | ||
51 | .jedec = 0x01AD, | ||
52 | .name = "AMD Am29F016", | ||
53 | .size = 2*1024*1024, | ||
54 | .sectorsize = 64*1024, | ||
55 | .capabilities = MTD_CAP_NORFLASH | ||
56 | }, | ||
57 | { | ||
58 | .jedec = 0x01D5, | ||
59 | .name = "AMD Am29F080", | ||
60 | .size = 1*1024*1024, | ||
61 | .sectorsize = 64*1024, | ||
62 | .capabilities = MTD_CAP_NORFLASH | ||
63 | }, | ||
64 | { | ||
65 | .jedec = 0x01A4, | ||
66 | .name = "AMD Am29F040", | ||
67 | .size = 512*1024, | ||
68 | .sectorsize = 64*1024, | ||
69 | .capabilities = MTD_CAP_NORFLASH | ||
70 | }, | ||
71 | { | ||
72 | .jedec = 0x20E3, | ||
73 | .name = "AMD Am29W040B", | ||
74 | .size = 512*1024, | ||
75 | .sectorsize = 64*1024, | ||
76 | .capabilities = MTD_CAP_NORFLASH | ||
77 | }, | ||
78 | { | ||
79 | .jedec = 0xC2AD, | ||
80 | .name = "Macronix MX29F016", | ||
81 | .size = 2*1024*1024, | ||
82 | .sectorsize = 64*1024, | ||
83 | .capabilities = MTD_CAP_NORFLASH | ||
84 | }, | ||
85 | { .jedec = 0x0 } | ||
86 | }; | ||
87 | |||
88 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); | ||
89 | static void jedec_sync(struct mtd_info *mtd) {}; | ||
90 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
91 | size_t *retlen, u_char *buf); | ||
92 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | ||
93 | size_t *retlen, u_char *buf); | ||
94 | |||
95 | static struct mtd_info *jedec_probe(struct map_info *map); | ||
96 | |||
97 | |||
98 | |||
99 | static struct mtd_chip_driver jedec_chipdrv = { | ||
100 | .probe = jedec_probe, | ||
101 | .name = "jedec", | ||
102 | .module = THIS_MODULE | ||
103 | }; | ||
104 | |||
105 | /* Probe entry point */ | ||
106 | |||
107 | static struct mtd_info *jedec_probe(struct map_info *map) | ||
108 | { | ||
109 | struct mtd_info *MTD; | ||
110 | struct jedec_private *priv; | ||
111 | unsigned long Base; | ||
112 | unsigned long SectorSize; | ||
113 | unsigned count; | ||
114 | unsigned I,Uniq; | ||
115 | char Part[200]; | ||
116 | memset(&priv,0,sizeof(priv)); | ||
117 | |||
118 | MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL); | ||
119 | if (!MTD) | ||
120 | return NULL; | ||
121 | |||
122 | memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); | ||
123 | priv = (struct jedec_private *)&MTD[1]; | ||
124 | |||
125 | my_bank_size = map->size; | ||
126 | |||
127 | if (map->size/my_bank_size > MAX_JEDEC_CHIPS) | ||
128 | { | ||
129 | printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n"); | ||
130 | kfree(MTD); | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | for (Base = 0; Base < map->size; Base += my_bank_size) | ||
135 | { | ||
136 | // Perhaps zero could designate all tests? | ||
137 | if (map->buswidth == 0) | ||
138 | map->buswidth = 1; | ||
139 | |||
140 | if (map->buswidth == 1){ | ||
141 | if (jedec_probe8(map,Base,priv) == 0) { | ||
142 | printk("did recognize jedec chip\n"); | ||
143 | kfree(MTD); | ||
144 | return NULL; | ||
145 | } | ||
146 | } | ||
147 | if (map->buswidth == 2) | ||
148 | jedec_probe16(map,Base,priv); | ||
149 | if (map->buswidth == 4) | ||
150 | jedec_probe32(map,Base,priv); | ||
151 | } | ||
152 | |||
153 | // Get the biggest sector size | ||
154 | SectorSize = 0; | ||
155 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
156 | { | ||
157 | // printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec); | ||
158 | // printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize); | ||
159 | if (priv->chips[I].sectorsize > SectorSize) | ||
160 | SectorSize = priv->chips[I].sectorsize; | ||
161 | } | ||
162 | |||
163 | // Quickly ensure that the other sector sizes are factors of the largest | ||
164 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
165 | { | ||
166 | if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize) | ||
167 | { | ||
168 | printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); | ||
169 | kfree(MTD); | ||
170 | return NULL; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | /* Generate a part name that includes the number of different chips and | ||
175 | other configuration information */ | ||
176 | count = 1; | ||
177 | strlcpy(Part,map->name,sizeof(Part)-10); | ||
178 | strcat(Part," "); | ||
179 | Uniq = 0; | ||
180 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
181 | { | ||
182 | const struct JEDECTable *JEDEC; | ||
183 | |||
184 | if (priv->chips[I+1].jedec == priv->chips[I].jedec) | ||
185 | { | ||
186 | count++; | ||
187 | continue; | ||
188 | } | ||
189 | |||
190 | // Locate the chip in the jedec table | ||
191 | JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); | ||
192 | if (JEDEC == 0) | ||
193 | { | ||
194 | printk("mtd: Internal Error, JEDEC not set\n"); | ||
195 | kfree(MTD); | ||
196 | return NULL; | ||
197 | } | ||
198 | |||
199 | if (Uniq != 0) | ||
200 | strcat(Part,","); | ||
201 | Uniq++; | ||
202 | |||
203 | if (count != 1) | ||
204 | sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); | ||
205 | else | ||
206 | sprintf(Part+strlen(Part),"%s",JEDEC->name); | ||
207 | if (strlen(Part) > sizeof(Part)*2/3) | ||
208 | break; | ||
209 | count = 1; | ||
210 | } | ||
211 | |||
212 | /* Determine if the chips are organized in a linear fashion, or if there | ||
213 | are empty banks. Note, the last bank does not count here, only the | ||
214 | first banks are important. Holes on non-bank boundaries can not exist | ||
215 | due to the way the detection algorithm works. */ | ||
216 | if (priv->size < my_bank_size) | ||
217 | my_bank_size = priv->size; | ||
218 | priv->is_banked = 0; | ||
219 | //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size); | ||
220 | //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]); | ||
221 | if (!priv->size) { | ||
222 | printk("priv->size is zero\n"); | ||
223 | kfree(MTD); | ||
224 | return NULL; | ||
225 | } | ||
226 | if (priv->size/my_bank_size) { | ||
227 | if (priv->size/my_bank_size == 1) { | ||
228 | priv->size = my_bank_size; | ||
229 | } | ||
230 | else { | ||
231 | for (I = 0; I != priv->size/my_bank_size - 1; I++) | ||
232 | { | ||
233 | if (priv->bank_fill[I] != my_bank_size) | ||
234 | priv->is_banked = 1; | ||
235 | |||
236 | /* This even could be eliminated, but new de-optimized read/write | ||
237 | functions have to be written */ | ||
238 | printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); | ||
239 | if (priv->bank_fill[I] != priv->bank_fill[0]) | ||
240 | { | ||
241 | printk("mtd: Failed. Cannot handle unsymmetric banking\n"); | ||
242 | kfree(MTD); | ||
243 | return NULL; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | if (priv->is_banked == 1) | ||
249 | strcat(Part,", banked"); | ||
250 | |||
251 | // printk("Part: '%s'\n",Part); | ||
252 | |||
253 | memset(MTD,0,sizeof(*MTD)); | ||
254 | // strlcpy(MTD->name,Part,sizeof(MTD->name)); | ||
255 | MTD->name = map->name; | ||
256 | MTD->type = MTD_NORFLASH; | ||
257 | MTD->flags = MTD_CAP_NORFLASH; | ||
258 | MTD->erasesize = SectorSize*(map->buswidth); | ||
259 | // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize); | ||
260 | MTD->size = priv->size; | ||
261 | // printk("MTD->size is %x\n",(unsigned int)MTD->size); | ||
262 | //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module? | ||
263 | MTD->erase = flash_erase; | ||
264 | if (priv->is_banked == 1) | ||
265 | MTD->read = jedec_read_banked; | ||
266 | else | ||
267 | MTD->read = jedec_read; | ||
268 | MTD->write = flash_write; | ||
269 | MTD->sync = jedec_sync; | ||
270 | MTD->priv = map; | ||
271 | map->fldrv_priv = priv; | ||
272 | map->fldrv = &jedec_chipdrv; | ||
273 | __module_get(THIS_MODULE); | ||
274 | return MTD; | ||
275 | } | ||
276 | |||
277 | /* Helper for the JEDEC function, JEDEC numbers all have odd parity */ | ||
278 | static int checkparity(u_char C) | ||
279 | { | ||
280 | u_char parity = 0; | ||
281 | while (C != 0) | ||
282 | { | ||
283 | parity ^= C & 1; | ||
284 | C >>= 1; | ||
285 | } | ||
286 | |||
287 | return parity == 1; | ||
288 | } | ||
289 | |||
290 | |||
291 | /* Take an array of JEDEC numbers that represent interleved flash chips | ||
292 | and process them. Check to make sure they are good JEDEC numbers, look | ||
293 | them up and then add them to the chip list */ | ||
294 | static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, | ||
295 | unsigned long base,struct jedec_private *priv) | ||
296 | { | ||
297 | unsigned I,J; | ||
298 | unsigned long Size; | ||
299 | unsigned long SectorSize; | ||
300 | const struct JEDECTable *JEDEC; | ||
301 | |||
302 | // Test #2 JEDEC numbers exhibit odd parity | ||
303 | for (I = 0; I != Count; I++) | ||
304 | { | ||
305 | if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | // Finally, just make sure all the chip sizes are the same | ||
310 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); | ||
311 | |||
312 | if (JEDEC == 0) | ||
313 | { | ||
314 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | Size = JEDEC->size; | ||
319 | SectorSize = JEDEC->sectorsize; | ||
320 | for (I = 0; I != Count; I++) | ||
321 | { | ||
322 | JEDEC = jedec_idtoinf(Mfg[0],Id[0]); | ||
323 | if (JEDEC == 0) | ||
324 | { | ||
325 | printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize) | ||
330 | { | ||
331 | printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); | ||
332 | return 0; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | // Load the Chips | ||
337 | for (I = 0; I != MAX_JEDEC_CHIPS; I++) | ||
338 | { | ||
339 | if (priv->chips[I].jedec == 0) | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | if (I + Count > MAX_JEDEC_CHIPS) | ||
344 | { | ||
345 | printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | // Add them to the table | ||
350 | for (J = 0; J != Count; J++) | ||
351 | { | ||
352 | unsigned long Bank; | ||
353 | |||
354 | JEDEC = jedec_idtoinf(Mfg[J],Id[J]); | ||
355 | priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; | ||
356 | priv->chips[I].size = JEDEC->size; | ||
357 | priv->chips[I].sectorsize = JEDEC->sectorsize; | ||
358 | priv->chips[I].base = base + J; | ||
359 | priv->chips[I].datashift = J*8; | ||
360 | priv->chips[I].capabilities = JEDEC->capabilities; | ||
361 | priv->chips[I].offset = priv->size + J; | ||
362 | |||
363 | // log2 n :| | ||
364 | priv->chips[I].addrshift = 0; | ||
365 | for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); | ||
366 | |||
367 | // Determine how filled this bank is. | ||
368 | Bank = base & (~(my_bank_size-1)); | ||
369 | if (priv->bank_fill[Bank/my_bank_size] < base + | ||
370 | (JEDEC->size << priv->chips[I].addrshift) - Bank) | ||
371 | priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; | ||
372 | I++; | ||
373 | } | ||
374 | |||
375 | priv->size += priv->chips[I-1].size*Count; | ||
376 | |||
377 | return priv->chips[I-1].size; | ||
378 | } | ||
379 | |||
380 | /* Lookup the chip information from the JEDEC ID table. */ | ||
381 | static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) | ||
382 | { | ||
383 | __u16 Id = (mfr << 8) | id; | ||
384 | unsigned long I = 0; | ||
385 | for (I = 0; JEDEC_table[I].jedec != 0; I++) | ||
386 | if (JEDEC_table[I].jedec == Id) | ||
387 | return JEDEC_table + I; | ||
388 | return NULL; | ||
389 | } | ||
390 | |||
391 | // Look for flash using an 8 bit bus interface | ||
392 | static int jedec_probe8(struct map_info *map,unsigned long base, | ||
393 | struct jedec_private *priv) | ||
394 | { | ||
395 | #define flread(x) map_read8(map,base+x) | ||
396 | #define flwrite(v,x) map_write8(map,v,base+x) | ||
397 | |||
398 | const unsigned long AutoSel1 = 0xAA; | ||
399 | const unsigned long AutoSel2 = 0x55; | ||
400 | const unsigned long AutoSel3 = 0x90; | ||
401 | const unsigned long Reset = 0xF0; | ||
402 | __u32 OldVal; | ||
403 | __u8 Mfg[1]; | ||
404 | __u8 Id[1]; | ||
405 | unsigned I; | ||
406 | unsigned long Size; | ||
407 | |||
408 | // Wait for any write/erase operation to settle | ||
409 | OldVal = flread(base); | ||
410 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | ||
411 | OldVal = flread(base); | ||
412 | |||
413 | // Reset the chip | ||
414 | flwrite(Reset,0x555); | ||
415 | |||
416 | // Send the sequence | ||
417 | flwrite(AutoSel1,0x555); | ||
418 | flwrite(AutoSel2,0x2AA); | ||
419 | flwrite(AutoSel3,0x555); | ||
420 | |||
421 | // Get the JEDEC numbers | ||
422 | Mfg[0] = flread(0); | ||
423 | Id[0] = flread(1); | ||
424 | // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); | ||
425 | |||
426 | Size = handle_jedecs(map,Mfg,Id,1,base,priv); | ||
427 | // printk("handle_jedecs Size is %x\n",(unsigned int)Size); | ||
428 | if (Size == 0) | ||
429 | { | ||
430 | flwrite(Reset,0x555); | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | |||
435 | // Reset. | ||
436 | flwrite(Reset,0x555); | ||
437 | |||
438 | return 1; | ||
439 | |||
440 | #undef flread | ||
441 | #undef flwrite | ||
442 | } | ||
443 | |||
444 | // Look for flash using a 16 bit bus interface (ie 2 8-bit chips) | ||
445 | static int jedec_probe16(struct map_info *map,unsigned long base, | ||
446 | struct jedec_private *priv) | ||
447 | { | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | // Look for flash using a 32 bit bus interface (ie 4 8-bit chips) | ||
452 | static int jedec_probe32(struct map_info *map,unsigned long base, | ||
453 | struct jedec_private *priv) | ||
454 | { | ||
455 | #define flread(x) map_read32(map,base+((x)<<2)) | ||
456 | #define flwrite(v,x) map_write32(map,v,base+((x)<<2)) | ||
457 | |||
458 | const unsigned long AutoSel1 = 0xAAAAAAAA; | ||
459 | const unsigned long AutoSel2 = 0x55555555; | ||
460 | const unsigned long AutoSel3 = 0x90909090; | ||
461 | const unsigned long Reset = 0xF0F0F0F0; | ||
462 | __u32 OldVal; | ||
463 | __u8 Mfg[4]; | ||
464 | __u8 Id[4]; | ||
465 | unsigned I; | ||
466 | unsigned long Size; | ||
467 | |||
468 | // Wait for any write/erase operation to settle | ||
469 | OldVal = flread(base); | ||
470 | for (I = 0; OldVal != flread(base) && I < 10000; I++) | ||
471 | OldVal = flread(base); | ||
472 | |||
473 | // Reset the chip | ||
474 | flwrite(Reset,0x555); | ||
475 | |||
476 | // Send the sequence | ||
477 | flwrite(AutoSel1,0x555); | ||
478 | flwrite(AutoSel2,0x2AA); | ||
479 | flwrite(AutoSel3,0x555); | ||
480 | |||
481 | // Test #1, JEDEC numbers are readable from 0x??00/0x??01 | ||
482 | if (flread(0) != flread(0x100) || | ||
483 | flread(1) != flread(0x101)) | ||
484 | { | ||
485 | flwrite(Reset,0x555); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | // Split up the JEDEC numbers | ||
490 | OldVal = flread(0); | ||
491 | for (I = 0; I != 4; I++) | ||
492 | Mfg[I] = (OldVal >> (I*8)); | ||
493 | OldVal = flread(1); | ||
494 | for (I = 0; I != 4; I++) | ||
495 | Id[I] = (OldVal >> (I*8)); | ||
496 | |||
497 | Size = handle_jedecs(map,Mfg,Id,4,base,priv); | ||
498 | if (Size == 0) | ||
499 | { | ||
500 | flwrite(Reset,0x555); | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /* Check if there is address wrap around within a single bank, if this | ||
505 | returns JEDEC numbers then we assume that it is wrap around. Notice | ||
506 | we call this routine with the JEDEC return still enabled, if two or | ||
507 | more flashes have a truncated address space the probe test will still | ||
508 | work */ | ||
509 | if (base + (Size<<2)+0x555 < map->size && | ||
510 | base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size) | ||
511 | { | ||
512 | if (flread(base+Size) != flread(base+Size + 0x100) || | ||
513 | flread(base+Size + 1) != flread(base+Size + 0x101)) | ||
514 | { | ||
515 | jedec_probe32(map,base+Size,priv); | ||
516 | } | ||
517 | } | ||
518 | |||
519 | // Reset. | ||
520 | flwrite(0xF0F0F0F0,0x555); | ||
521 | |||
522 | return 1; | ||
523 | |||
524 | #undef flread | ||
525 | #undef flwrite | ||
526 | } | ||
527 | |||
528 | /* Linear read. */ | ||
529 | static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
530 | size_t *retlen, u_char *buf) | ||
531 | { | ||
532 | struct map_info *map = mtd->priv; | ||
533 | |||
534 | map_copy_from(map, buf, from, len); | ||
535 | *retlen = len; | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | /* Banked read. Take special care to jump past the holes in the bank | ||
540 | mapping. This version assumes symetry in the holes.. */ | ||
541 | static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, | ||
542 | size_t *retlen, u_char *buf) | ||
543 | { | ||
544 | struct map_info *map = mtd->priv; | ||
545 | struct jedec_private *priv = map->fldrv_priv; | ||
546 | |||
547 | *retlen = 0; | ||
548 | while (len > 0) | ||
549 | { | ||
550 | // Determine what bank and offset into that bank the first byte is | ||
551 | unsigned long bank = from & (~(priv->bank_fill[0]-1)); | ||
552 | unsigned long offset = from & (priv->bank_fill[0]-1); | ||
553 | unsigned long get = len; | ||
554 | if (priv->bank_fill[0] - offset < len) | ||
555 | get = priv->bank_fill[0] - offset; | ||
556 | |||
557 | bank /= priv->bank_fill[0]; | ||
558 | map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); | ||
559 | |||
560 | len -= get; | ||
561 | *retlen += get; | ||
562 | from += get; | ||
563 | } | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /* Pass the flags value that the flash return before it re-entered read | ||
568 | mode. */ | ||
569 | static void jedec_flash_failed(unsigned char code) | ||
570 | { | ||
571 | /* Bit 5 being high indicates that there was an internal device | ||
572 | failure, erasure time limits exceeded or something */ | ||
573 | if ((code & (1 << 5)) != 0) | ||
574 | { | ||
575 | printk("mtd: Internal Flash failure\n"); | ||
576 | return; | ||
577 | } | ||
578 | printk("mtd: Programming didn't take\n"); | ||
579 | } | ||
580 | |||
581 | /* This uses the erasure function described in the AMD Flash Handbook, | ||
582 | it will work for flashes with a fixed sector size only. Flashes with | ||
583 | a selection of sector sizes (ie the AMD Am29F800B) will need a different | ||
584 | routine. This routine tries to parallize erasing multiple chips/sectors | ||
585 | where possible */ | ||
586 | static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
587 | { | ||
588 | // Does IO to the currently selected chip | ||
589 | #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) | ||
590 | #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) | ||
591 | |||
592 | unsigned long Time = 0; | ||
593 | unsigned long NoTime = 0; | ||
594 | unsigned long start = instr->addr, len = instr->len; | ||
595 | unsigned int I; | ||
596 | struct map_info *map = mtd->priv; | ||
597 | struct jedec_private *priv = map->fldrv_priv; | ||
598 | |||
599 | // Verify the arguments.. | ||
600 | if (start + len > mtd->size || | ||
601 | (start % mtd->erasesize) != 0 || | ||
602 | (len % mtd->erasesize) != 0 || | ||
603 | (len/mtd->erasesize) == 0) | ||
604 | return -EINVAL; | ||
605 | |||
606 | jedec_flash_chip_scan(priv,start,len); | ||
607 | |||
608 | // Start the erase sequence on each chip | ||
609 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
610 | { | ||
611 | unsigned long off; | ||
612 | struct jedec_flash_chip *chip = priv->chips + I; | ||
613 | |||
614 | if (chip->length == 0) | ||
615 | continue; | ||
616 | |||
617 | if (chip->start + chip->length > chip->size) | ||
618 | { | ||
619 | printk("DIE\n"); | ||
620 | return -EIO; | ||
621 | } | ||
622 | |||
623 | flwrite(0xF0,chip->start + 0x555); | ||
624 | flwrite(0xAA,chip->start + 0x555); | ||
625 | flwrite(0x55,chip->start + 0x2AA); | ||
626 | flwrite(0x80,chip->start + 0x555); | ||
627 | flwrite(0xAA,chip->start + 0x555); | ||
628 | flwrite(0x55,chip->start + 0x2AA); | ||
629 | |||
630 | /* Once we start selecting the erase sectors the delay between each | ||
631 | command must not exceed 50us or it will immediately start erasing | ||
632 | and ignore the other sectors */ | ||
633 | for (off = 0; off < len; off += chip->sectorsize) | ||
634 | { | ||
635 | // Check to make sure we didn't timeout | ||
636 | flwrite(0x30,chip->start + off); | ||
637 | if (off == 0) | ||
638 | continue; | ||
639 | if ((flread(chip->start + off) & (1 << 3)) != 0) | ||
640 | { | ||
641 | printk("mtd: Ack! We timed out the erase timer!\n"); | ||
642 | return -EIO; | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | |||
647 | /* We could split this into a timer routine and return early, performing | ||
648 | background erasure.. Maybe later if the need warrents */ | ||
649 | |||
650 | /* Poll the flash for erasure completion, specs say this can take as long | ||
651 | as 480 seconds to do all the sectors (for a 2 meg flash). | ||
652 | Erasure time is dependent on chip age, temp and wear.. */ | ||
653 | |||
654 | /* This being a generic routine assumes a 32 bit bus. It does read32s | ||
655 | and bundles interleved chips into the same grouping. This will work | ||
656 | for all bus widths */ | ||
657 | Time = 0; | ||
658 | NoTime = 0; | ||
659 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
660 | { | ||
661 | struct jedec_flash_chip *chip = priv->chips + I; | ||
662 | unsigned long off = 0; | ||
663 | unsigned todo[4] = {0,0,0,0}; | ||
664 | unsigned todo_left = 0; | ||
665 | unsigned J; | ||
666 | |||
667 | if (chip->length == 0) | ||
668 | continue; | ||
669 | |||
670 | /* Find all chips in this data line, realistically this is all | ||
671 | or nothing up to the interleve count */ | ||
672 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | ||
673 | { | ||
674 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | ||
675 | (chip->base & (~((1<<chip->addrshift)-1)))) | ||
676 | { | ||
677 | todo_left++; | ||
678 | todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], | ||
683 | (short)todo[2],(short)todo[3]); | ||
684 | */ | ||
685 | while (1) | ||
686 | { | ||
687 | __u32 Last[4]; | ||
688 | unsigned long Count = 0; | ||
689 | |||
690 | /* During erase bit 7 is held low and bit 6 toggles, we watch this, | ||
691 | should it stop toggling or go high then the erase is completed, | ||
692 | or this is not really flash ;> */ | ||
693 | switch (map->buswidth) { | ||
694 | case 1: | ||
695 | Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
696 | Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
697 | Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
698 | break; | ||
699 | case 2: | ||
700 | Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
701 | Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
702 | Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
703 | break; | ||
704 | case 3: | ||
705 | Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
706 | Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
707 | Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
708 | break; | ||
709 | } | ||
710 | Count = 3; | ||
711 | while (todo_left != 0) | ||
712 | { | ||
713 | for (J = 0; J != 4; J++) | ||
714 | { | ||
715 | __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF; | ||
716 | __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF; | ||
717 | __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; | ||
718 | if (todo[J] == 0) | ||
719 | continue; | ||
720 | |||
721 | if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) | ||
722 | { | ||
723 | // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); | ||
724 | continue; | ||
725 | } | ||
726 | |||
727 | if (Byte1 == Byte2) | ||
728 | { | ||
729 | jedec_flash_failed(Byte3); | ||
730 | return -EIO; | ||
731 | } | ||
732 | |||
733 | todo[J] = 0; | ||
734 | todo_left--; | ||
735 | } | ||
736 | |||
737 | /* if (NoTime == 0) | ||
738 | Time += HZ/10 - schedule_timeout(HZ/10);*/ | ||
739 | NoTime = 0; | ||
740 | |||
741 | switch (map->buswidth) { | ||
742 | case 1: | ||
743 | Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
744 | break; | ||
745 | case 2: | ||
746 | Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
747 | break; | ||
748 | case 4: | ||
749 | Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); | ||
750 | break; | ||
751 | } | ||
752 | Count++; | ||
753 | |||
754 | /* // Count time, max of 15s per sector (according to AMD) | ||
755 | if (Time > 15*len/mtd->erasesize*HZ) | ||
756 | { | ||
757 | printk("mtd: Flash Erase Timed out\n"); | ||
758 | return -EIO; | ||
759 | } */ | ||
760 | } | ||
761 | |||
762 | // Skip to the next chip if we used chip erase | ||
763 | if (chip->length == chip->size) | ||
764 | off = chip->size; | ||
765 | else | ||
766 | off += chip->sectorsize; | ||
767 | |||
768 | if (off >= chip->length) | ||
769 | break; | ||
770 | NoTime = 1; | ||
771 | } | ||
772 | |||
773 | for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) | ||
774 | { | ||
775 | if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == | ||
776 | (chip->base & (~((1<<chip->addrshift)-1)))) | ||
777 | priv->chips[J].length = 0; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | //printk("done\n"); | ||
782 | instr->state = MTD_ERASE_DONE; | ||
783 | mtd_erase_callback(instr); | ||
784 | return 0; | ||
785 | |||
786 | #undef flread | ||
787 | #undef flwrite | ||
788 | } | ||
789 | |||
790 | /* This is the simple flash writing function. It writes to every byte, in | ||
791 | sequence. It takes care of how to properly address the flash if | ||
792 | the flash is interleved. It can only be used if all the chips in the | ||
793 | array are identical!*/ | ||
794 | static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, | ||
795 | size_t *retlen, const u_char *buf) | ||
796 | { | ||
797 | /* Does IO to the currently selected chip. It takes the bank addressing | ||
798 | base (which is divisible by the chip size) adds the necessary lower bits | ||
799 | of addrshift (interleave index) and then adds the control register index. */ | ||
800 | #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | ||
801 | #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) | ||
802 | |||
803 | struct map_info *map = mtd->priv; | ||
804 | struct jedec_private *priv = map->fldrv_priv; | ||
805 | unsigned long base; | ||
806 | unsigned long off; | ||
807 | size_t save_len = len; | ||
808 | |||
809 | if (start + len > mtd->size) | ||
810 | return -EIO; | ||
811 | |||
812 | //printk("Here"); | ||
813 | |||
814 | //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); | ||
815 | while (len != 0) | ||
816 | { | ||
817 | struct jedec_flash_chip *chip = priv->chips; | ||
818 | unsigned long bank; | ||
819 | unsigned long boffset; | ||
820 | |||
821 | // Compute the base of the flash. | ||
822 | off = ((unsigned long)start) % (chip->size << chip->addrshift); | ||
823 | base = start - off; | ||
824 | |||
825 | // Perform banked addressing translation. | ||
826 | bank = base & (~(priv->bank_fill[0]-1)); | ||
827 | boffset = base & (priv->bank_fill[0]-1); | ||
828 | bank = (bank/priv->bank_fill[0])*my_bank_size; | ||
829 | base = bank + boffset; | ||
830 | |||
831 | // printk("Flasing %X %X %X\n",base,chip->size,len); | ||
832 | // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); | ||
833 | |||
834 | // Loop over this page | ||
835 | for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) | ||
836 | { | ||
837 | unsigned char oldbyte = map_read8(map,base+off); | ||
838 | unsigned char Last[4]; | ||
839 | unsigned long Count = 0; | ||
840 | |||
841 | if (oldbyte == *buf) { | ||
842 | // printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len); | ||
843 | continue; | ||
844 | } | ||
845 | if (((~oldbyte) & *buf) != 0) | ||
846 | printk("mtd: warn: Trying to set a 0 to a 1\n"); | ||
847 | |||
848 | // Write | ||
849 | flwrite(0xAA,0x555); | ||
850 | flwrite(0x55,0x2AA); | ||
851 | flwrite(0xA0,0x555); | ||
852 | map_write8(map,*buf,base + off); | ||
853 | Last[0] = map_read8(map,base + off); | ||
854 | Last[1] = map_read8(map,base + off); | ||
855 | Last[2] = map_read8(map,base + off); | ||
856 | |||
857 | /* Wait for the flash to finish the operation. We store the last 4 | ||
858 | status bytes that have been retrieved so we can determine why | ||
859 | it failed. The toggle bits keep toggling when there is a | ||
860 | failure */ | ||
861 | for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && | ||
862 | Count < 10000; Count++) | ||
863 | Last[Count % 4] = map_read8(map,base + off); | ||
864 | if (Last[(Count - 1) % 4] != *buf) | ||
865 | { | ||
866 | jedec_flash_failed(Last[(Count - 3) % 4]); | ||
867 | return -EIO; | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | *retlen = save_len; | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | /* This is used to enhance the speed of the erase routine, | ||
876 | when things are being done to multiple chips it is possible to | ||
877 | parallize the operations, particularly full memory erases of multi | ||
878 | chip memories benifit */ | ||
879 | static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start, | ||
880 | unsigned long len) | ||
881 | { | ||
882 | unsigned int I; | ||
883 | |||
884 | // Zero the records | ||
885 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
886 | priv->chips[I].start = priv->chips[I].length = 0; | ||
887 | |||
888 | // Intersect the region with each chip | ||
889 | for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) | ||
890 | { | ||
891 | struct jedec_flash_chip *chip = priv->chips + I; | ||
892 | unsigned long ByteStart; | ||
893 | unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); | ||
894 | |||
895 | // End is before this chip or the start is after it | ||
896 | if (start+len < chip->offset || | ||
897 | ChipEndByte - (1 << chip->addrshift) < start) | ||
898 | continue; | ||
899 | |||
900 | if (start < chip->offset) | ||
901 | { | ||
902 | ByteStart = chip->offset; | ||
903 | chip->start = 0; | ||
904 | } | ||
905 | else | ||
906 | { | ||
907 | chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; | ||
908 | ByteStart = start; | ||
909 | } | ||
910 | |||
911 | if (start + len >= ChipEndByte) | ||
912 | chip->length = (ChipEndByte - ByteStart) >> chip->addrshift; | ||
913 | else | ||
914 | chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | int __init jedec_init(void) | ||
919 | { | ||
920 | register_mtd_chip_driver(&jedec_chipdrv); | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static void __exit jedec_exit(void) | ||
925 | { | ||
926 | unregister_mtd_chip_driver(&jedec_chipdrv); | ||
927 | } | ||
928 | |||
929 | module_init(jedec_init); | ||
930 | module_exit(jedec_exit); | ||
931 | |||
932 | MODULE_LICENSE("GPL"); | ||
933 | MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al."); | ||
934 | MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips"); | ||