blob: 2c3f019197c116463b74b04645dd6baf54e0dd65 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001
2/* JEDEC Flash Interface.
Thomas Gleixner1f948b42005-11-07 11:15:37 +00003 * This is an older type of interface for self programming flash. It is
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * 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>
Tim Schmielau4e57b682005-10-30 15:03:48 -080020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/mtd/jedec.h>
22#include <linux/mtd/map.h>
23#include <linux/mtd/mtd.h>
24#include <linux/mtd/compatmac.h>
25
26static struct mtd_info *jedec_probe(struct map_info *);
27static int jedec_probe8(struct map_info *map,unsigned long base,
28 struct jedec_private *priv);
29static int jedec_probe16(struct map_info *map,unsigned long base,
30 struct jedec_private *priv);
31static int jedec_probe32(struct map_info *map,unsigned long base,
32 struct jedec_private *priv);
33static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
34 unsigned long len);
35static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
36static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
37 size_t *retlen, const u_char *buf);
38
39static unsigned long my_bank_size;
40
41/* Listing of parts and sizes. We need this table to learn the sector
42 size of the chip and the total length */
43static const struct JEDECTable JEDEC_table[] = {
44 {
45 .jedec = 0x013D,
46 .name = "AMD Am29F017D",
47 .size = 2*1024*1024,
48 .sectorsize = 64*1024,
49 .capabilities = MTD_CAP_NORFLASH
50 },
51 {
52 .jedec = 0x01AD,
53 .name = "AMD Am29F016",
54 .size = 2*1024*1024,
55 .sectorsize = 64*1024,
56 .capabilities = MTD_CAP_NORFLASH
57 },
58 {
59 .jedec = 0x01D5,
60 .name = "AMD Am29F080",
61 .size = 1*1024*1024,
62 .sectorsize = 64*1024,
63 .capabilities = MTD_CAP_NORFLASH
64 },
65 {
66 .jedec = 0x01A4,
67 .name = "AMD Am29F040",
68 .size = 512*1024,
69 .sectorsize = 64*1024,
70 .capabilities = MTD_CAP_NORFLASH
71 },
72 {
73 .jedec = 0x20E3,
74 .name = "AMD Am29W040B",
75 .size = 512*1024,
76 .sectorsize = 64*1024,
77 .capabilities = MTD_CAP_NORFLASH
78 },
79 {
80 .jedec = 0xC2AD,
81 .name = "Macronix MX29F016",
82 .size = 2*1024*1024,
83 .sectorsize = 64*1024,
84 .capabilities = MTD_CAP_NORFLASH
85 },
86 { .jedec = 0x0 }
87};
88
89static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
90static void jedec_sync(struct mtd_info *mtd) {};
Thomas Gleixner1f948b42005-11-07 11:15:37 +000091static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 size_t *retlen, u_char *buf);
Thomas Gleixner1f948b42005-11-07 11:15:37 +000093static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 size_t *retlen, u_char *buf);
95
96static struct mtd_info *jedec_probe(struct map_info *map);
97
98
99
100static struct mtd_chip_driver jedec_chipdrv = {
101 .probe = jedec_probe,
102 .name = "jedec",
103 .module = THIS_MODULE
104};
105
106/* Probe entry point */
107
108static struct mtd_info *jedec_probe(struct map_info *map)
109{
110 struct mtd_info *MTD;
111 struct jedec_private *priv;
112 unsigned long Base;
113 unsigned long SectorSize;
114 unsigned count;
115 unsigned I,Uniq;
116 char Part[200];
117 memset(&priv,0,sizeof(priv));
118
119 MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
120 if (!MTD)
121 return NULL;
122
123 memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private));
124 priv = (struct jedec_private *)&MTD[1];
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 my_bank_size = map->size;
127
128 if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
129 {
130 printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
131 kfree(MTD);
132 return NULL;
133 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 for (Base = 0; Base < map->size; Base += my_bank_size)
136 {
137 // Perhaps zero could designate all tests?
138 if (map->buswidth == 0)
139 map->buswidth = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 if (map->buswidth == 1){
142 if (jedec_probe8(map,Base,priv) == 0) {
143 printk("did recognize jedec chip\n");
144 kfree(MTD);
145 return NULL;
146 }
147 }
148 if (map->buswidth == 2)
149 jedec_probe16(map,Base,priv);
150 if (map->buswidth == 4)
151 jedec_probe32(map,Base,priv);
152 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 // Get the biggest sector size
155 SectorSize = 0;
156 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
157 {
158 // printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
159 // printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
160 if (priv->chips[I].sectorsize > SectorSize)
161 SectorSize = priv->chips[I].sectorsize;
162 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 // Quickly ensure that the other sector sizes are factors of the largest
165 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
166 {
167 if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
168 {
169 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
170 kfree(MTD);
171 return NULL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 /* Generate a part name that includes the number of different chips and
176 other configuration information */
177 count = 1;
178 strlcpy(Part,map->name,sizeof(Part)-10);
179 strcat(Part," ");
180 Uniq = 0;
181 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
182 {
183 const struct JEDECTable *JEDEC;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 if (priv->chips[I+1].jedec == priv->chips[I].jedec)
186 {
187 count++;
188 continue;
189 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 // Locate the chip in the jedec table
192 JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
193 if (JEDEC == 0)
194 {
195 printk("mtd: Internal Error, JEDEC not set\n");
196 kfree(MTD);
197 return NULL;
198 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 if (Uniq != 0)
201 strcat(Part,",");
202 Uniq++;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 if (count != 1)
205 sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
206 else
207 sprintf(Part+strlen(Part),"%s",JEDEC->name);
208 if (strlen(Part) > sizeof(Part)*2/3)
209 break;
210 count = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 /* Determine if the chips are organized in a linear fashion, or if there
214 are empty banks. Note, the last bank does not count here, only the
215 first banks are important. Holes on non-bank boundaries can not exist
216 due to the way the detection algorithm works. */
217 if (priv->size < my_bank_size)
218 my_bank_size = priv->size;
219 priv->is_banked = 0;
220 //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
221 //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
222 if (!priv->size) {
223 printk("priv->size is zero\n");
224 kfree(MTD);
225 return NULL;
226 }
227 if (priv->size/my_bank_size) {
228 if (priv->size/my_bank_size == 1) {
229 priv->size = my_bank_size;
230 }
231 else {
232 for (I = 0; I != priv->size/my_bank_size - 1; I++)
233 {
234 if (priv->bank_fill[I] != my_bank_size)
235 priv->is_banked = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 /* This even could be eliminated, but new de-optimized read/write
238 functions have to be written */
239 printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
240 if (priv->bank_fill[I] != priv->bank_fill[0])
241 {
242 printk("mtd: Failed. Cannot handle unsymmetric banking\n");
243 kfree(MTD);
244 return NULL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 }
247 }
248 }
249 if (priv->is_banked == 1)
250 strcat(Part,", banked");
251
252 // printk("Part: '%s'\n",Part);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 memset(MTD,0,sizeof(*MTD));
255 // strlcpy(MTD->name,Part,sizeof(MTD->name));
256 MTD->name = map->name;
257 MTD->type = MTD_NORFLASH;
258 MTD->flags = MTD_CAP_NORFLASH;
Artem B. Bityutskiy17ffc7b2006-06-22 18:15:48 +0400259 MTD->writesize = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 MTD->erasesize = SectorSize*(map->buswidth);
261 // printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
262 MTD->size = priv->size;
263 // printk("MTD->size is %x\n",(unsigned int)MTD->size);
264 //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
265 MTD->erase = flash_erase;
266 if (priv->is_banked == 1)
267 MTD->read = jedec_read_banked;
268 else
269 MTD->read = jedec_read;
270 MTD->write = flash_write;
271 MTD->sync = jedec_sync;
272 MTD->priv = map;
273 map->fldrv_priv = priv;
274 map->fldrv = &jedec_chipdrv;
275 __module_get(THIS_MODULE);
276 return MTD;
277}
278
279/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
280static int checkparity(u_char C)
281{
282 u_char parity = 0;
283 while (C != 0)
284 {
285 parity ^= C & 1;
286 C >>= 1;
287 }
288
289 return parity == 1;
290}
291
292
293/* Take an array of JEDEC numbers that represent interleved flash chips
294 and process them. Check to make sure they are good JEDEC numbers, look
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000295 them up and then add them to the chip list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
297 unsigned long base,struct jedec_private *priv)
298{
299 unsigned I,J;
300 unsigned long Size;
301 unsigned long SectorSize;
302 const struct JEDECTable *JEDEC;
303
304 // Test #2 JEDEC numbers exhibit odd parity
305 for (I = 0; I != Count; I++)
306 {
307 if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
308 return 0;
309 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 // Finally, just make sure all the chip sizes are the same
312 JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (JEDEC == 0)
315 {
316 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
317 return 0;
318 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 Size = JEDEC->size;
321 SectorSize = JEDEC->sectorsize;
322 for (I = 0; I != Count; I++)
323 {
324 JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
325 if (JEDEC == 0)
326 {
327 printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
328 return 0;
329 }
330
331 if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
332 {
333 printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
334 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 }
337
338 // Load the Chips
339 for (I = 0; I != MAX_JEDEC_CHIPS; I++)
340 {
341 if (priv->chips[I].jedec == 0)
342 break;
343 }
344
345 if (I + Count > MAX_JEDEC_CHIPS)
346 {
347 printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
348 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000349 }
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 // Add them to the table
352 for (J = 0; J != Count; J++)
353 {
354 unsigned long Bank;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
357 priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
358 priv->chips[I].size = JEDEC->size;
359 priv->chips[I].sectorsize = JEDEC->sectorsize;
360 priv->chips[I].base = base + J;
361 priv->chips[I].datashift = J*8;
362 priv->chips[I].capabilities = JEDEC->capabilities;
363 priv->chips[I].offset = priv->size + J;
364
365 // log2 n :|
366 priv->chips[I].addrshift = 0;
367 for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 // Determine how filled this bank is.
370 Bank = base & (~(my_bank_size-1));
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000371 if (priv->bank_fill[Bank/my_bank_size] < base +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 (JEDEC->size << priv->chips[I].addrshift) - Bank)
373 priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
374 I++;
375 }
376
377 priv->size += priv->chips[I-1].size*Count;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 return priv->chips[I-1].size;
380}
381
382/* Lookup the chip information from the JEDEC ID table. */
383static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
384{
385 __u16 Id = (mfr << 8) | id;
386 unsigned long I = 0;
387 for (I = 0; JEDEC_table[I].jedec != 0; I++)
388 if (JEDEC_table[I].jedec == Id)
389 return JEDEC_table + I;
390 return NULL;
391}
392
393// Look for flash using an 8 bit bus interface
394static int jedec_probe8(struct map_info *map,unsigned long base,
395 struct jedec_private *priv)
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000396{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 #define flread(x) map_read8(map,base+x)
398 #define flwrite(v,x) map_write8(map,v,base+x)
399
400 const unsigned long AutoSel1 = 0xAA;
401 const unsigned long AutoSel2 = 0x55;
402 const unsigned long AutoSel3 = 0x90;
403 const unsigned long Reset = 0xF0;
404 __u32 OldVal;
405 __u8 Mfg[1];
406 __u8 Id[1];
407 unsigned I;
408 unsigned long Size;
409
410 // Wait for any write/erase operation to settle
411 OldVal = flread(base);
412 for (I = 0; OldVal != flread(base) && I < 10000; I++)
413 OldVal = flread(base);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 // Reset the chip
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000416 flwrite(Reset,0x555);
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 // Send the sequence
419 flwrite(AutoSel1,0x555);
420 flwrite(AutoSel2,0x2AA);
421 flwrite(AutoSel3,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 // Get the JEDEC numbers
424 Mfg[0] = flread(0);
425 Id[0] = flread(1);
426 // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 Size = handle_jedecs(map,Mfg,Id,1,base,priv);
429 // printk("handle_jedecs Size is %x\n",(unsigned int)Size);
430 if (Size == 0)
431 {
432 flwrite(Reset,0x555);
433 return 0;
434 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 // Reset.
438 flwrite(Reset,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 return 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 #undef flread
443 #undef flwrite
444}
445
446// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
447static int jedec_probe16(struct map_info *map,unsigned long base,
448 struct jedec_private *priv)
449{
450 return 0;
451}
452
453// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
454static int jedec_probe32(struct map_info *map,unsigned long base,
455 struct jedec_private *priv)
456{
457 #define flread(x) map_read32(map,base+((x)<<2))
458 #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
459
460 const unsigned long AutoSel1 = 0xAAAAAAAA;
461 const unsigned long AutoSel2 = 0x55555555;
462 const unsigned long AutoSel3 = 0x90909090;
463 const unsigned long Reset = 0xF0F0F0F0;
464 __u32 OldVal;
465 __u8 Mfg[4];
466 __u8 Id[4];
467 unsigned I;
468 unsigned long Size;
469
470 // Wait for any write/erase operation to settle
471 OldVal = flread(base);
472 for (I = 0; OldVal != flread(base) && I < 10000; I++)
473 OldVal = flread(base);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 // Reset the chip
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000476 flwrite(Reset,0x555);
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 // Send the sequence
479 flwrite(AutoSel1,0x555);
480 flwrite(AutoSel2,0x2AA);
481 flwrite(AutoSel3,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 // Test #1, JEDEC numbers are readable from 0x??00/0x??01
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000484 if (flread(0) != flread(0x100) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 flread(1) != flread(0x101))
486 {
487 flwrite(Reset,0x555);
488 return 0;
489 }
490
491 // Split up the JEDEC numbers
492 OldVal = flread(0);
493 for (I = 0; I != 4; I++)
494 Mfg[I] = (OldVal >> (I*8));
495 OldVal = flread(1);
496 for (I = 0; I != 4; I++)
497 Id[I] = (OldVal >> (I*8));
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 Size = handle_jedecs(map,Mfg,Id,4,base,priv);
500 if (Size == 0)
501 {
502 flwrite(Reset,0x555);
503 return 0;
504 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 /* Check if there is address wrap around within a single bank, if this
507 returns JEDEC numbers then we assume that it is wrap around. Notice
508 we call this routine with the JEDEC return still enabled, if two or
509 more flashes have a truncated address space the probe test will still
510 work */
511 if (base + (Size<<2)+0x555 < map->size &&
512 base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
513 {
514 if (flread(base+Size) != flread(base+Size + 0x100) ||
515 flread(base+Size + 1) != flread(base+Size + 0x101))
516 {
517 jedec_probe32(map,base+Size,priv);
518 }
519 }
520
521 // Reset.
522 flwrite(0xF0F0F0F0,0x555);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 #undef flread
527 #undef flwrite
528}
529
530/* Linear read. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000531static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 size_t *retlen, u_char *buf)
533{
534 struct map_info *map = mtd->priv;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 map_copy_from(map, buf, from, len);
537 *retlen = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000538 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539}
540
541/* Banked read. Take special care to jump past the holes in the bank
542 mapping. This version assumes symetry in the holes.. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000543static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 size_t *retlen, u_char *buf)
545{
546 struct map_info *map = mtd->priv;
547 struct jedec_private *priv = map->fldrv_priv;
548
549 *retlen = 0;
550 while (len > 0)
551 {
552 // Determine what bank and offset into that bank the first byte is
553 unsigned long bank = from & (~(priv->bank_fill[0]-1));
554 unsigned long offset = from & (priv->bank_fill[0]-1);
555 unsigned long get = len;
556 if (priv->bank_fill[0] - offset < len)
557 get = priv->bank_fill[0] - offset;
558
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000559 bank /= priv->bank_fill[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 len -= get;
563 *retlen += get;
564 from += get;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000565 }
566 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000569/* Pass the flags value that the flash return before it re-entered read
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 mode. */
571static void jedec_flash_failed(unsigned char code)
572{
573 /* Bit 5 being high indicates that there was an internal device
574 failure, erasure time limits exceeded or something */
575 if ((code & (1 << 5)) != 0)
576 {
577 printk("mtd: Internal Flash failure\n");
578 return;
579 }
580 printk("mtd: Programming didn't take\n");
581}
582
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000583/* This uses the erasure function described in the AMD Flash Handbook,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 it will work for flashes with a fixed sector size only. Flashes with
585 a selection of sector sizes (ie the AMD Am29F800B) will need a different
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000586 routine. This routine tries to parallize erasing multiple chips/sectors
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 where possible */
588static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
589{
590 // Does IO to the currently selected chip
591 #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
592 #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 unsigned long Time = 0;
595 unsigned long NoTime = 0;
596 unsigned long start = instr->addr, len = instr->len;
597 unsigned int I;
598 struct map_info *map = mtd->priv;
599 struct jedec_private *priv = map->fldrv_priv;
600
601 // Verify the arguments..
602 if (start + len > mtd->size ||
603 (start % mtd->erasesize) != 0 ||
604 (len % mtd->erasesize) != 0 ||
605 (len/mtd->erasesize) == 0)
606 return -EINVAL;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 jedec_flash_chip_scan(priv,start,len);
609
610 // Start the erase sequence on each chip
611 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
612 {
613 unsigned long off;
614 struct jedec_flash_chip *chip = priv->chips + I;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (chip->length == 0)
617 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (chip->start + chip->length > chip->size)
620 {
621 printk("DIE\n");
622 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000623 }
624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 flwrite(0xF0,chip->start + 0x555);
626 flwrite(0xAA,chip->start + 0x555);
627 flwrite(0x55,chip->start + 0x2AA);
628 flwrite(0x80,chip->start + 0x555);
629 flwrite(0xAA,chip->start + 0x555);
630 flwrite(0x55,chip->start + 0x2AA);
631
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000632 /* Once we start selecting the erase sectors the delay between each
633 command must not exceed 50us or it will immediately start erasing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 and ignore the other sectors */
635 for (off = 0; off < len; off += chip->sectorsize)
636 {
637 // Check to make sure we didn't timeout
638 flwrite(0x30,chip->start + off);
639 if (off == 0)
640 continue;
641 if ((flread(chip->start + off) & (1 << 3)) != 0)
642 {
643 printk("mtd: Ack! We timed out the erase timer!\n");
644 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 /* We could split this into a timer routine and return early, performing
650 background erasure.. Maybe later if the need warrents */
651
652 /* Poll the flash for erasure completion, specs say this can take as long
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000653 as 480 seconds to do all the sectors (for a 2 meg flash).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 Erasure time is dependent on chip age, temp and wear.. */
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* This being a generic routine assumes a 32 bit bus. It does read32s
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000657 and bundles interleved chips into the same grouping. This will work
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 for all bus widths */
659 Time = 0;
660 NoTime = 0;
661 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
662 {
663 struct jedec_flash_chip *chip = priv->chips + I;
664 unsigned long off = 0;
665 unsigned todo[4] = {0,0,0,0};
666 unsigned todo_left = 0;
667 unsigned J;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (chip->length == 0)
670 continue;
671
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000672 /* Find all chips in this data line, realistically this is all
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 or nothing up to the interleve count */
674 for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
675 {
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000676 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 (chip->base & (~((1<<chip->addrshift)-1))))
678 {
679 todo_left++;
680 todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683
684 /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
685 (short)todo[2],(short)todo[3]);
686 */
687 while (1)
688 {
689 __u32 Last[4];
690 unsigned long Count = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000691
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 /* During erase bit 7 is held low and bit 6 toggles, we watch this,
693 should it stop toggling or go high then the erase is completed,
694 or this is not really flash ;> */
695 switch (map->buswidth) {
696 case 1:
697 Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
698 Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
699 Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
700 break;
701 case 2:
702 Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
703 Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
704 Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
705 break;
706 case 3:
707 Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
708 Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
709 Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
710 break;
711 }
712 Count = 3;
713 while (todo_left != 0)
714 {
715 for (J = 0; J != 4; J++)
716 {
717 __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
718 __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
719 __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
720 if (todo[J] == 0)
721 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
724 {
725// printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
726 continue;
727 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000728
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if (Byte1 == Byte2)
730 {
731 jedec_flash_failed(Byte3);
732 return -EIO;
733 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 todo[J] = 0;
736 todo_left--;
737 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000738
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739/* if (NoTime == 0)
740 Time += HZ/10 - schedule_timeout(HZ/10);*/
741 NoTime = 0;
742
743 switch (map->buswidth) {
744 case 1:
745 Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
746 break;
747 case 2:
748 Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
749 break;
750 case 4:
751 Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
752 break;
753 }
754 Count++;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756/* // Count time, max of 15s per sector (according to AMD)
757 if (Time > 15*len/mtd->erasesize*HZ)
758 {
759 printk("mtd: Flash Erase Timed out\n");
760 return -EIO;
761 } */
762 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 // Skip to the next chip if we used chip erase
765 if (chip->length == chip->size)
766 off = chip->size;
767 else
768 off += chip->sectorsize;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (off >= chip->length)
771 break;
772 NoTime = 1;
773 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
776 {
777 if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
778 (chip->base & (~((1<<chip->addrshift)-1))))
779 priv->chips[J].length = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 }
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000782
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 //printk("done\n");
784 instr->state = MTD_ERASE_DONE;
785 mtd_erase_callback(instr);
786 return 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 #undef flread
789 #undef flwrite
790}
791
792/* This is the simple flash writing function. It writes to every byte, in
793 sequence. It takes care of how to properly address the flash if
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000794 the flash is interleved. It can only be used if all the chips in the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 array are identical!*/
796static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
797 size_t *retlen, const u_char *buf)
798{
799 /* Does IO to the currently selected chip. It takes the bank addressing
800 base (which is divisible by the chip size) adds the necessary lower bits
801 of addrshift (interleave index) and then adds the control register index. */
802 #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
803 #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 struct map_info *map = mtd->priv;
806 struct jedec_private *priv = map->fldrv_priv;
807 unsigned long base;
808 unsigned long off;
809 size_t save_len = len;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (start + len > mtd->size)
812 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 //printk("Here");
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
817 while (len != 0)
818 {
819 struct jedec_flash_chip *chip = priv->chips;
820 unsigned long bank;
821 unsigned long boffset;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 // Compute the base of the flash.
824 off = ((unsigned long)start) % (chip->size << chip->addrshift);
825 base = start - off;
826
827 // Perform banked addressing translation.
828 bank = base & (~(priv->bank_fill[0]-1));
829 boffset = base & (priv->bank_fill[0]-1);
830 bank = (bank/priv->bank_fill[0])*my_bank_size;
831 base = bank + boffset;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 // printk("Flasing %X %X %X\n",base,chip->size,len);
834 // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 // Loop over this page
837 for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
838 {
839 unsigned char oldbyte = map_read8(map,base+off);
840 unsigned char Last[4];
841 unsigned long Count = 0;
842
843 if (oldbyte == *buf) {
844 // printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
845 continue;
846 }
847 if (((~oldbyte) & *buf) != 0)
848 printk("mtd: warn: Trying to set a 0 to a 1\n");
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 // Write
851 flwrite(0xAA,0x555);
852 flwrite(0x55,0x2AA);
853 flwrite(0xA0,0x555);
854 map_write8(map,*buf,base + off);
855 Last[0] = map_read8(map,base + off);
856 Last[1] = map_read8(map,base + off);
857 Last[2] = map_read8(map,base + off);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000858
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* Wait for the flash to finish the operation. We store the last 4
860 status bytes that have been retrieved so we can determine why
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000861 it failed. The toggle bits keep toggling when there is a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 failure */
863 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
864 Count < 10000; Count++)
865 Last[Count % 4] = map_read8(map,base + off);
866 if (Last[(Count - 1) % 4] != *buf)
867 {
868 jedec_flash_failed(Last[(Count - 3) % 4]);
869 return -EIO;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 }
872 }
873 *retlen = save_len;
874 return 0;
875}
876
877/* This is used to enhance the speed of the erase routine,
878 when things are being done to multiple chips it is possible to
879 parallize the operations, particularly full memory erases of multi
880 chip memories benifit */
881static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
882 unsigned long len)
883{
884 unsigned int I;
885
886 // Zero the records
887 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
888 priv->chips[I].start = priv->chips[I].length = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 // Intersect the region with each chip
891 for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
892 {
893 struct jedec_flash_chip *chip = priv->chips + I;
894 unsigned long ByteStart;
895 unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 // End is before this chip or the start is after it
898 if (start+len < chip->offset ||
899 ChipEndByte - (1 << chip->addrshift) < start)
900 continue;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 if (start < chip->offset)
903 {
904 ByteStart = chip->offset;
905 chip->start = 0;
Thomas Gleixner1f948b42005-11-07 11:15:37 +0000906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 else
908 {
909 chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
910 ByteStart = start;
911 }
912
913 if (start + len >= ChipEndByte)
914 chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
915 else
916 chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
917 }
918}
919
920int __init jedec_init(void)
921{
922 register_mtd_chip_driver(&jedec_chipdrv);
923 return 0;
924}
925
926static void __exit jedec_exit(void)
927{
928 unregister_mtd_chip_driver(&jedec_chipdrv);
929}
930
931module_init(jedec_init);
932module_exit(jedec_exit);
933
934MODULE_LICENSE("GPL");
935MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
936MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");